├── 3-assembled-output ├── GameCode.inf ├── GameCode.bin ├── !RunImage.bin ├── README.md ├── RunImage.arm ├── RunImgSrc,fff └── exports.arm ├── 5-compiled-game-discs ├── arthur │ └── Game │ │ ├── GameCode.inf │ │ ├── GameCode │ │ ├── Lander,ffb │ │ └── GameCode,8000-A614 ├── zip │ ├── Game.zip │ └── !Lander.zip ├── riscos │ └── !Lander │ │ ├── !RunImage,ff8 │ │ ├── !Sprites,ff9 │ │ ├── MemAlloc,ffa │ │ └── !Run,feb └── README.md ├── 2-build-files ├── make.exe ├── libintl3.dll ├── libiconv2.dll ├── decrypt │ ├── !RunImage.bin │ ├── !RunImage.decrypt.bin │ ├── README.md │ ├── lander-decrypt.arm │ └── lander-decrypt.py ├── README.md ├── export-symbols.py ├── convert-to-basic.py ├── convert-to-vasm.py └── crc32.py ├── 4-reference-binaries ├── GameCode.bin ├── !RunImage.bin └── README.md ├── 1-source-files ├── other-sources │ ├── arthur │ │ ├── Lander,ffb │ │ └── README.md │ ├── riscos │ │ ├── !Sprites,ff9 │ │ ├── MemAlloc,ffa │ │ ├── !Run,feb │ │ └── README.md │ └── README.md ├── README.md └── main-sources │ ├── README.md │ └── RunImage.arm ├── make.bat ├── .gitignore ├── .gitattributes ├── Makefile └── README.md /3-assembled-output/GameCode.inf: -------------------------------------------------------------------------------- 1 | $.Gamecode 008000 00A614 009A10 -------------------------------------------------------------------------------- /5-compiled-game-discs/arthur/Game/GameCode.inf: -------------------------------------------------------------------------------- 1 | $.Gamecode 008000 00A614 009A10 -------------------------------------------------------------------------------- /2-build-files/make.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/markmoxon/lander-source-code-acorn-archimedes/HEAD/2-build-files/make.exe -------------------------------------------------------------------------------- /2-build-files/libintl3.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/markmoxon/lander-source-code-acorn-archimedes/HEAD/2-build-files/libintl3.dll -------------------------------------------------------------------------------- /2-build-files/libiconv2.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/markmoxon/lander-source-code-acorn-archimedes/HEAD/2-build-files/libiconv2.dll -------------------------------------------------------------------------------- /3-assembled-output/GameCode.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/markmoxon/lander-source-code-acorn-archimedes/HEAD/3-assembled-output/GameCode.bin -------------------------------------------------------------------------------- /3-assembled-output/!RunImage.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/markmoxon/lander-source-code-acorn-archimedes/HEAD/3-assembled-output/!RunImage.bin -------------------------------------------------------------------------------- /4-reference-binaries/GameCode.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/markmoxon/lander-source-code-acorn-archimedes/HEAD/4-reference-binaries/GameCode.bin -------------------------------------------------------------------------------- /2-build-files/decrypt/!RunImage.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/markmoxon/lander-source-code-acorn-archimedes/HEAD/2-build-files/decrypt/!RunImage.bin -------------------------------------------------------------------------------- /4-reference-binaries/!RunImage.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/markmoxon/lander-source-code-acorn-archimedes/HEAD/4-reference-binaries/!RunImage.bin -------------------------------------------------------------------------------- /5-compiled-game-discs/zip/Game.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/markmoxon/lander-source-code-acorn-archimedes/HEAD/5-compiled-game-discs/zip/Game.zip -------------------------------------------------------------------------------- /5-compiled-game-discs/zip/!Lander.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/markmoxon/lander-source-code-acorn-archimedes/HEAD/5-compiled-game-discs/zip/!Lander.zip -------------------------------------------------------------------------------- /2-build-files/decrypt/!RunImage.decrypt.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/markmoxon/lander-source-code-acorn-archimedes/HEAD/2-build-files/decrypt/!RunImage.decrypt.bin -------------------------------------------------------------------------------- /5-compiled-game-discs/arthur/Game/GameCode: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/markmoxon/lander-source-code-acorn-archimedes/HEAD/5-compiled-game-discs/arthur/Game/GameCode -------------------------------------------------------------------------------- /1-source-files/other-sources/arthur/Lander,ffb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/markmoxon/lander-source-code-acorn-archimedes/HEAD/1-source-files/other-sources/arthur/Lander,ffb -------------------------------------------------------------------------------- /5-compiled-game-discs/arthur/Game/Lander,ffb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/markmoxon/lander-source-code-acorn-archimedes/HEAD/5-compiled-game-discs/arthur/Game/Lander,ffb -------------------------------------------------------------------------------- /1-source-files/other-sources/riscos/!Sprites,ff9: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/markmoxon/lander-source-code-acorn-archimedes/HEAD/1-source-files/other-sources/riscos/!Sprites,ff9 -------------------------------------------------------------------------------- /1-source-files/other-sources/riscos/MemAlloc,ffa: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/markmoxon/lander-source-code-acorn-archimedes/HEAD/1-source-files/other-sources/riscos/MemAlloc,ffa -------------------------------------------------------------------------------- /5-compiled-game-discs/riscos/!Lander/!RunImage,ff8: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/markmoxon/lander-source-code-acorn-archimedes/HEAD/5-compiled-game-discs/riscos/!Lander/!RunImage,ff8 -------------------------------------------------------------------------------- /5-compiled-game-discs/riscos/!Lander/!Sprites,ff9: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/markmoxon/lander-source-code-acorn-archimedes/HEAD/5-compiled-game-discs/riscos/!Lander/!Sprites,ff9 -------------------------------------------------------------------------------- /5-compiled-game-discs/riscos/!Lander/MemAlloc,ffa: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/markmoxon/lander-source-code-acorn-archimedes/HEAD/5-compiled-game-discs/riscos/!Lander/MemAlloc,ffa -------------------------------------------------------------------------------- /make.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | SETLOCAL 3 | SET BEEBASM=C:\Users\user\bin\beebasm.exe 4 | SET PYTHON=C:\Users\user\AppData\Local\Microsoft\WindowsApps\python.exe 5 | 2-build-files\make %* 6 | -------------------------------------------------------------------------------- /5-compiled-game-discs/arthur/Game/GameCode,8000-A614: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/markmoxon/lander-source-code-acorn-archimedes/HEAD/5-compiled-game-discs/arthur/Game/GameCode,8000-A614 -------------------------------------------------------------------------------- /1-source-files/other-sources/riscos/!Run,feb: -------------------------------------------------------------------------------- 1 | | !Run file for !Lander, version 0.41 (16-Dec-88) 2 | WimpSlot 0 0 3 | RMEnsure MemAlloc 0 RMLoad .MemAlloc 4 | Echo <22><141> 5 | ScreenSize 160 Error Not enough memory to run Lander 6 | Echo <22><141> 7 | WimpSlot -min 168K -max 168K 8 | Run .!RunImage 9 | -------------------------------------------------------------------------------- /5-compiled-game-discs/riscos/!Lander/!Run,feb: -------------------------------------------------------------------------------- 1 | | !Run file for !Lander, version 0.41 (16-Dec-88) 2 | WimpSlot 0 0 3 | RMEnsure MemAlloc 0 RMLoad .MemAlloc 4 | Echo <22><141> 5 | ScreenSize 160 Error Not enough memory to run Lander 6 | Echo <22><141> 7 | WimpSlot -min 168K -max 168K 8 | Run .!RunImage 9 | -------------------------------------------------------------------------------- /1-source-files/other-sources/arthur/README.md: -------------------------------------------------------------------------------- 1 | # Annotated source code for Lander on the Acorn Archimedes 2 | 3 | This folder contains other source files for the Arthur variant of Lander on the Acorn Archimedes. 4 | 5 | * [Lander,ffb](Lander,ffb) is the BBC BASIC loader for the Arthur operating system 6 | 7 | --- 8 | 9 | _Mark Moxon_ -------------------------------------------------------------------------------- /1-source-files/README.md: -------------------------------------------------------------------------------- 1 | # Source files for Lander on the Acorn Archimedes 2 | 3 | This folder contains the source files for Lander on the Acorn Archimedes. 4 | 5 | * [other-sources](other-sources) contains BASIC programs and RISC OS application files to include on the final disc 6 | 7 | * [main-sources](main-sources) contains the annotated source code 8 | 9 | --- 10 | 11 | _Mark Moxon_ -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Windows thumbnail cache files 2 | Thumbs.db 3 | ehthumbs.db 4 | ehthumbs_vista.db 5 | 6 | # Folder config file 7 | Desktop.ini 8 | 9 | # Recycle Bin used on file shares 10 | $RECYCLE.BIN/ 11 | 12 | # Windows Installer files 13 | *.cab 14 | *.msi 15 | *.msm 16 | *.msp 17 | 18 | # Windows shortcuts 19 | *.lnk 20 | 21 | # IDE files 22 | .vscode/ 23 | *.code-workspace 24 | run.bat 25 | -------------------------------------------------------------------------------- /1-source-files/other-sources/README.md: -------------------------------------------------------------------------------- 1 | # Annotated source code for Lander on the Acorn Archimedes 2 | 3 | This folder contains other source files for Lander on the Acorn Archimedes. 4 | 5 | * [arthur](arthur) contains the BBC BASIC loader for the Arthur operating system 6 | 7 | * [riscos](riscos) contains the files that make up the !Lander RISC OS application folder 8 | 9 | --- 10 | 11 | _Mark Moxon_ -------------------------------------------------------------------------------- /1-source-files/main-sources/README.md: -------------------------------------------------------------------------------- 1 | # Annotated source code for Lander on the Acorn Archimedes 2 | 3 | This folder contains the annotated source code for Lander on the Acorn Archimedes. 4 | 5 | * Main source files: 6 | 7 | * [Lander.arm](Lander.arm) contains the main source for the game 8 | 9 | * Other source files: 10 | 11 | * [RunImage.arm](RunImage.arm) contains the wrapper source for the RISC OS !RunImage Absolute file 12 | 13 | --- 14 | 15 | _Mark Moxon_ -------------------------------------------------------------------------------- /3-assembled-output/README.md: -------------------------------------------------------------------------------- 1 | # Assembled output for Lander on the Acorn Archimedes 2 | 3 | This folder contains the output binaries from the build process for Lander on the Acorn Archimedes. 4 | 5 | It also contains [compile.txt](compile.txt) and [compile-RunImage.txt](compile-RunImage.txt), which contain the output from the assembly process for the main game and !RunImage file respectively. This is very useful when debugging the build process. 6 | 7 | --- 8 | 9 | _Mark Moxon_ -------------------------------------------------------------------------------- /1-source-files/other-sources/riscos/README.md: -------------------------------------------------------------------------------- 1 | # Annotated source code for Lander on the Acorn Archimedes 2 | 3 | This folder contains the files that make up the !Lander RISC OS application folder in the RISC OS variant of Lander on the Acorn Archimedes. 4 | 5 | * [!Run,feb](!Run,feb) is the application's run Obey file 6 | 7 | * [!Sprites,ff9](!Sprites,ff9) contains the application's sprites 8 | 9 | * [MemAlloc,ffa](MemAlloc,ffa) is the application's memory allocation module 10 | 11 | --- 12 | 13 | _Mark Moxon_ 14 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | 4 | # Custom for Visual Studio 5 | *.cs diff=csharp 6 | 7 | # Standard to msysgit 8 | *.doc diff=astextplain 9 | *.DOC diff=astextplain 10 | *.docx diff=astextplain 11 | *.DOCX diff=astextplain 12 | *.dot diff=astextplain 13 | *.DOT diff=astextplain 14 | *.pdf diff=astextplain 15 | *.PDF diff=astextplain 16 | *.rtf diff=astextplain 17 | *.RTF diff=astextplain 18 | 19 | # Set syntax for ARM assembler files 20 | *.arm linguist-language=Assembly 21 | -------------------------------------------------------------------------------- /3-assembled-output/RunImage.arm: -------------------------------------------------------------------------------- 1 | .set CODE, 0x00008000 2 | .include "3-assembled-output/exports.arm" 3 | .org CODE 4 | B DecryptGameBinary 5 | gameCode: 6 | .incbin "3-assembled-output/GameCode.bin" 7 | gameCodeEnd: 8 | DecryptGameBinary: 9 | LDR R0, gameCodeAddr 10 | LDR R1, absoluteAddr 11 | LDR R2, gameCodeEndAddr 12 | decr1: 13 | LDR R12, [R0], #4 14 | STR R12, [R1], #4 15 | CMP R0, R2 16 | BNE decr1 17 | B Entry 18 | absoluteAddr: 19 | .long CODE 20 | gameCodeAddr: 21 | .long gameCode 22 | gameCodeEndAddr: 23 | .long gameCodeEnd 24 | -------------------------------------------------------------------------------- /4-reference-binaries/README.md: -------------------------------------------------------------------------------- 1 | # Reference binaries for Lander on the Acorn Archimedes 2 | 3 | This folder contains the binaries from the game disc for Lander on the Acorn Archimedes. 4 | 5 | * [GameCode.bin](GameCode.bin) contains the game binary from the Arthur variant, as found on the Arthur applications disc 6 | 7 | * [!RunImage.bin](!RunImage.unprot.bin) contains the game binary wrapped up into an Absolute file, so this is what is currently built by the build process (this file does not contain the encryption of the released version of RISC OS Lander) 8 | 9 | --- 10 | 11 | _Mark Moxon_ -------------------------------------------------------------------------------- /2-build-files/decrypt/README.md: -------------------------------------------------------------------------------- 1 | # Decryption files for Lander on the Acorn Archimedes 2 | 3 | This folder contains support scripts for decrypting the RISC OS version of Lander on the Acorn Archimedes. 4 | 5 | * [lander-decrypt.arm](lander-decrypt.arm) contains the decryption code from the RISC OS variant of the game, taken from the end of the !RunImage file 6 | 7 | * [lander-decrypt.py](lander-decrypt.py) contains the decryption code from the RISC OS variant of the game, translated into Python 8 | 9 | * [!RunImage.bin](!RunImage.bin) contains the encrypted game binary from the RISC OS variant, as found on the RISC OS 2 applications disc 10 | 11 | * [!RunImage.decrypt.bin](!RunImage.decrypt.bin) contains the decrypted version of !RunImage.bin, extracted by the [lander-decrypt.py](lander-decrypt.py) script (so this exactly matches GameCode.bin) 12 | 13 | --- 14 | 15 | _Mark Moxon_ -------------------------------------------------------------------------------- /5-compiled-game-discs/README.md: -------------------------------------------------------------------------------- 1 | # Compiled game discs for Lander on the Acorn Archimedes 2 | 3 | This folder contains the final disc files for Lander on the Acorn Archimedes, as produced by the build process. There is one folder for each supported variant, plus a folder for zips of each variant. These files can be loaded into an emulator like Arculator, or into a real Archimedes using a device like a Gotek. 4 | 5 | The Arthur variant contains the GameCode binary in two formats: as a pair of files (GameCode and GameCode.inf) that is suitable for programs that support inf files, or as a single file (GameCode,8000-A614) that will work with HostFS. Both options contain the load and execution address of the file, and you should choose the one that works for you when copying the game to your emulator or Archimedes. 6 | 7 | It also contains LanderSrc,fff, which is a BBC BASIC-compatible file that will build Lander on an Archimedes. 8 | 9 | --- 10 | 11 | _Mark Moxon_ -------------------------------------------------------------------------------- /2-build-files/README.md: -------------------------------------------------------------------------------- 1 | # Build files for Lander on the Acorn Archimedes 2 | 3 | This folder contains support scripts for building Lander on the Acorn Archimedes. 4 | 5 | * [convert-to-vasm.py](convert-to-vasm.py) converts the main source files into vasm-compatible syntax so vasm can assemble the game 6 | 7 | * [convert-to-basic.py](convert-to-basic.py) converts the main source files into a BBC BASIC-compatible syntax that will build on an Archimedes 8 | 9 | * [crc32.py](crc32.py) calculates checksums during the verify stage and compares the results with the relevant binaries in the [4-reference-binaries](../4-reference-binaries) folder 10 | 11 | * [export-symbols.py](convert-to-vasm.py) extracts symbol values from the vasm output so they can be included in the !RunImage source (so changing the souce code won't break the !RunImage loader) 12 | 13 | * The [decrypt](decrypt) folder contains decryption-related files from the RISC OS variant of the game 14 | 15 | It also contains the `make.exe` executable for Windows, plus the required DLL files. 16 | 17 | --- 18 | 19 | _Mark Moxon_ -------------------------------------------------------------------------------- /2-build-files/export-symbols.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # 3 | # ****************************************************************************** 4 | # 5 | # EXPORT SYMBOLS FROM VASM 6 | # 7 | # Written by Mark Moxon 8 | # 9 | # This script extracts symbol values from the vasm output so they can be 10 | # included in the !RunImage source, and it creates a GameCode.inf file for 11 | # Arthur that contains the correct file size, load and execution addresses. 12 | # 13 | # ****************************************************************************** 14 | 15 | import re 16 | import shutil 17 | 18 | 19 | def convert(input_file, output_file, inf_file): 20 | 21 | export_section_reached = False 22 | exec_address = "" 23 | file_size = "" 24 | 25 | for line in input_file: 26 | 27 | if "Symbols by value:" in line: 28 | export_section_reached = True 29 | 30 | # Export variables 31 | if export_section_reached: 32 | exported_variable = re.search(r"^([0-9A-F]{8}) (\w+)$", line) 33 | if exported_variable: 34 | export = ".set " + exported_variable.group(2) + ", 0x" + exported_variable.group(1) + "\n" 35 | output_file.write(export) 36 | if exported_variable.group(2) == 'Entry': 37 | exec_address = exported_variable.group(1)[-6:] 38 | if exported_variable.group(2) == 'endCode': 39 | end_code = exported_variable.group(1) 40 | file_size = hex(int(end_code, 16) - 0x8000).replace("0x", "00000000") 41 | 42 | inf = "$.Gamecode 008000 " + exec_address[-6:].upper() + " " + file_size[-6:].upper() 43 | inf_file.write(inf) 44 | 45 | shutil.copy("5-compiled-game-discs/arthur/Game/GameCode", "5-compiled-game-discs/arthur/Game/GameCode,8000-" + exec_address[-4:].upper()) 46 | 47 | 48 | print("Extracting exported variables from 1-source-files/Lander.arm") 49 | 50 | compile_file = open("3-assembled-output/compile.txt", "r") 51 | vasm_file = open("3-assembled-output/exports.arm", "w") 52 | inf_file = open("3-assembled-output/GameCode.inf", "w") 53 | convert(compile_file, vasm_file, inf_file) 54 | inf_file.close() 55 | compile_file.close() 56 | vasm_file.close() 57 | 58 | print("Variables extracted") 59 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | VASM?=vasmarm_std 2 | PYTHON?=python 3 | 4 | # The deploy target deploys !Lander to a web server so archi.medes.live can load it 5 | # 6 | # LANDER_PATH should be set to the scp path of the server hosting the build 7 | # 8 | # e.g. export $LANDER_PATH=name@server.com:~/path/to 9 | # 10 | # Once deployed, you can load a URL like this to see the compiled game: 11 | # 12 | # https://archi.medes.live/#ff=14400&disc=https://server.com/path/to/!Lander.zip&autoboot=desktop%20filer_opendir%20HostFS::HostFS.$ 13 | 14 | .PHONY:all 15 | all: 16 | @$(PYTHON) 2-build-files/convert-to-vasm.py 17 | 18 | rm -fr 5-compiled-game-discs/arthur/Game/* 19 | rm -fr 5-compiled-game-discs/riscos/!Lander/* 20 | rm -fr 5-compiled-game-discs/zip/* 21 | 22 | $(VASM) -a2 -m2 -quiet -Fbin -L 3-assembled-output/compile.txt -o 3-assembled-output/GameCode.bin 3-assembled-output/Lander.arm 23 | cp 3-assembled-output/GameCode.inf 5-compiled-game-discs/arthur/Game/GameCode.inf 24 | cp 1-source-files/other-sources/arthur/Lander,ffb 5-compiled-game-discs/arthur/Game/Lander,ffb 25 | cp 3-assembled-output/GameCode.bin 5-compiled-game-discs/arthur/Game/GameCode 26 | 27 | @$(PYTHON) 2-build-files/export-symbols.py 28 | 29 | $(VASM) -a2 -m2 -quiet -Fbin -L 3-assembled-output/compile-RunImage.txt -o 3-assembled-output/!RunImage.bin 3-assembled-output/RunImage.arm 30 | cp 1-source-files/other-sources/riscos/!Run,feb 5-compiled-game-discs/riscos/!Lander/!Run,feb 31 | cp 1-source-files/other-sources/riscos/!Sprites,ff9 5-compiled-game-discs/riscos/!Lander/!Sprites,ff9 32 | cp 1-source-files/other-sources/riscos/MemAlloc,ffa 5-compiled-game-discs/riscos/!Lander/MemAlloc,ffa 33 | cp 3-assembled-output/!RunImage.bin 5-compiled-game-discs/riscos/!Lander/!RunImage,ff8 34 | 35 | @$(PYTHON) 2-build-files/convert-to-basic.py 36 | cp 3-assembled-output/LanderSrc,fff 5-compiled-game-discs/LanderSrc,fff 37 | 38 | cp -r 5-compiled-game-discs/riscos/!Lander . 39 | zip -r \!Lander.zip !Lander -x "*/.*" 40 | mv \!Lander.zip 5-compiled-game-discs/zip 41 | rm -fr \!Lander 42 | 43 | cp -r 5-compiled-game-discs/arthur/Game . 44 | zip -r Game.zip Game -x "*/.*" 45 | mv Game.zip 5-compiled-game-discs/zip 46 | rm -fr Game 47 | 48 | @$(PYTHON) 2-build-files/crc32.py 4-reference-binaries 3-assembled-output 49 | 50 | deploy: 51 | scp 5-compiled-game-discs/zip/!Lander.zip ${LANDER_PATH} 52 | -------------------------------------------------------------------------------- /2-build-files/convert-to-basic.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # 3 | # ****************************************************************************** 4 | # 5 | # CONVERT REPOSITORY ASSEMBLER FORMAT TO BBC BASIC 6 | # 7 | # Written by Mark Moxon 8 | # 9 | # This script converts source code from the repository style into BBC BASIC ARM 10 | # Assembler style. 11 | # 12 | # ****************************************************************************** 13 | 14 | import re 15 | 16 | 17 | def convert(input_file, output_file): 18 | 19 | in_code = False 20 | 21 | for line in input_file: 22 | 23 | if in_code: 24 | if re.match(r"^ *\]", line): 25 | in_code = False 26 | else: 27 | in_code = re.match(r"^ *\[", line) 28 | 29 | # Change (...) in comments to [...] 30 | while re.search(r"(\\.*)\(", line): 31 | line = re.sub(r"(\\.*)\(", r"\1[", line) 32 | while re.search(r"(\\.*)\)", line): 33 | line = re.sub(r"(\\.*)\)", r"\1]", line) 34 | 35 | # Change " in comments to ' 36 | while re.search(r"(\\.*)\"", line): 37 | line = re.sub(r"(\\.*)\"", r"\1'", line) 38 | 39 | # Change : in comments to ; 40 | while re.search(r"(\\.*):", line): 41 | line = re.sub(r"(\\.*):", r"\1;", line) 42 | 43 | # Replace comma-separated EQUs with individual EQUs 44 | while re.search(r"\b(EQU.) *([^:\\,\n]+), *", line): 45 | line = re.sub(r"\b(EQU.) *([^:\\,\n]+), *", r"\1 \2 : \1 ", line) 46 | 47 | if not in_code: 48 | # Change \ to : REM 49 | line = re.sub(r"^\\", r"REM", line) 50 | line = re.sub(r"\\", r": REM", line) 51 | 52 | # Change GameCode.bin to GameCode 53 | line = re.sub(r"GameCode\.bin", r"GameCode", line) 54 | 55 | if in_code: 56 | # Change ALIGN to FN_AlignWithZeroes 57 | line = re.sub(r"ALIGN", r"OPT FN_AlignWithZeroes", line) 58 | 59 | # Write updated line 60 | output_file.write(line) 61 | 62 | # Write FNs 63 | output_file.write("\n END\n\n") 64 | output_file.write(" DEF FN_AlignWithZeroes\n") 65 | output_file.write(" a = P% AND 3\n") 66 | output_file.write(" IF a > 0 THEN\n") 67 | output_file.write(" FOR I% = 1 TO 4 - a\n") 68 | output_file.write(" [\n") 69 | output_file.write(" OPT pass%\n") 70 | output_file.write(" EQUB 0\n") 71 | output_file.write(" ]\n") 72 | output_file.write(" NEXT I%\n") 73 | output_file.write(" ENDIF\n") 74 | output_file.write(" =pass%\n") 75 | 76 | 77 | print("Converting 1-source-files/Lander.arm") 78 | 79 | source_file = open("1-source-files/main-sources/Lander.arm", "r") 80 | basic_file = open("3-assembled-output/LanderSrc,fff", "w") 81 | convert(source_file, basic_file) 82 | source_file.close() 83 | basic_file.close() 84 | 85 | print("3-assembled-output/LanderSrc,fff file saved") 86 | 87 | print("Converting 1-source-files/RunImage.arm") 88 | 89 | source_file = open("1-source-files/main-sources/RunImage.arm", "r") 90 | basic_file = open("3-assembled-output/RunImgSrc,fff", "w") 91 | convert(source_file, basic_file) 92 | source_file.close() 93 | basic_file.close() 94 | 95 | print("3-assembled-output/RunImage,fff file saved") 96 | -------------------------------------------------------------------------------- /2-build-files/convert-to-vasm.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # 3 | # ****************************************************************************** 4 | # 5 | # CONVERT REPOSITORY ASSEMBLER FORMAT TO VASM 6 | # 7 | # Written by Mark Moxon 8 | # 9 | # This script converts source code from the repository style into 10 | # vasm-compatible ARM assembler. 11 | # 12 | # ****************************************************************************** 13 | 14 | import re 15 | 16 | 17 | def convert(input_file, output_file): 18 | 19 | for line in input_file: 20 | 21 | # Strip comments 22 | line = re.sub(r" *[;\\].*$", "", line) 23 | 24 | # .label -> label: 25 | line = re.sub(r"^\.([^ \n]+)", r"\1:", line) 26 | 27 | # Remove INT(...) 28 | line = re.sub(r" INT\(", " (", line) 29 | 30 | # Remove lines that mention pass% 31 | line = re.sub(r"^.*pass%.*$", "", line) 32 | 33 | # Remove lines that start with "DIM " 34 | line = re.sub(r"^ *DIM .*$", "", line) 35 | 36 | # Remove lines that start with "O% = " 37 | line = re.sub(r"^ *O% = .*$", "", line) 38 | 39 | # Remove lines that start with "OSCLI " 40 | line = re.sub(r"^ *OSCLI .*$", "", line) 41 | 42 | # Remove lines that start with [ or ] 43 | line = re.sub(r"^ *(\[|\]).*$", "", line) 44 | 45 | # "P% = " -> .org 46 | line = re.sub(r"^ *P% = ", ".org ", line) 47 | 48 | # FOR loop -> .rept 49 | line = re.sub(r"^ *FOR I% = 1 TO ", ".rept ", line) 50 | 51 | # NEXT -> .endr 52 | line = re.sub(r"^ *NEXT", ".endr", line) 53 | 54 | # x = y -> .set x, y 55 | line = re.sub(r"^ *(.+) = (.+)$", r".set \1, \2", line) 56 | 57 | # SKIP -> .skip 58 | line = re.sub(r"^ *SKIP ", ".skip ", line) 59 | 60 | # P% -> $ 61 | line = re.sub(r"P%", "$", line) 62 | 63 | # Binary % -> 0x 64 | binary_string = re.search(r"%([0-1]+)", line) 65 | if binary_string: 66 | hex_string = hex(int(binary_string.group(1), 2)) 67 | line = re.sub(r"%([0-1]+)", hex_string, line) 68 | 69 | # Hexadecimal & -> 0x 70 | line = re.sub(r"&", "0x", line) 71 | 72 | # EQUD -> .long 73 | line = re.sub(r"^ *EQUD ", ".long ", line) 74 | 75 | # EQUW -> .word 76 | line = re.sub(r"^ *EQUW ", ".word ", line) 77 | 78 | # EQUS -> .byte 79 | line = re.sub(r"^ *EQUS ", ".byte ", line) 80 | 81 | # EQUB -> .byte 82 | line = re.sub(r"^ *EQUB ", ".byte ", line) 83 | 84 | # ALIGN -> .balign 85 | line = re.sub(r"^ *ALIGN", ".balign 4", line) 86 | 87 | # IF -> .ifdef 88 | line = re.sub(r"^ *IF ", ".ifdef ", line) 89 | 90 | # ENDIF -> .endif 91 | line = re.sub(r"^ *ENDIF", ".endif", line) 92 | 93 | # ELSE -> .else 94 | line = re.sub(r"^ *ELSE", ".else", line) 95 | 96 | # INCBIN -> .incbin 97 | line = re.sub(r"^ *INCBIN", ".incbin", line) 98 | 99 | # INCLUDE -> .include 100 | line = re.sub(r"^ *INCLUDE", ".include", line) 101 | 102 | # Write updated line 103 | if line.strip(): 104 | output_file.write(line) 105 | 106 | 107 | print("Converting 1-source-files/Lander.arm") 108 | 109 | source_file = open("1-source-files/main-sources/Lander.arm", "r") 110 | vasm_file = open("3-assembled-output/Lander.arm", "w") 111 | convert(source_file, vasm_file) 112 | source_file.close() 113 | vasm_file.close() 114 | 115 | source_file = open("1-source-files/main-sources/RunImage.arm", "r") 116 | vasm_file = open("3-assembled-output/RunImage.arm", "w") 117 | convert(source_file, vasm_file) 118 | source_file.close() 119 | vasm_file.close() 120 | 121 | print("3-assembled-output/Lander.arm file saved") 122 | -------------------------------------------------------------------------------- /2-build-files/crc32.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # 3 | # ****************************************************************************** 4 | # 5 | # LANDER VERIFICATION SCRIPT 6 | # 7 | # Written by Kieran Connell, extended by Mark Moxon 8 | # 9 | # This script performs checksums on the compiled files from the build process, 10 | # and checks them against the extracted files from the original source disc 11 | # 12 | # ****************************************************************************** 13 | 14 | from __future__ import print_function 15 | import sys 16 | import os 17 | import os.path 18 | import zlib 19 | 20 | 21 | def main(): 22 | if len(sys.argv) <= 2: 23 | # Do CRC on single folder 24 | folder = sys.argv[1] if len(sys.argv) == 2 else "." 25 | names = sorted(os.listdir(folder)) 26 | 27 | print() 28 | print('Checksum Size Filename') 29 | print('------------------------------------------') 30 | 31 | for name in names: 32 | if name.endswith(".bin"): 33 | full_name = os.path.join(folder, name) 34 | if not os.path.isfile(full_name): 35 | continue 36 | with open(full_name, 'rb') as f: 37 | data = f.read() 38 | print('%08x %5d %s' % ( 39 | zlib.crc32(data) & 0xffffffff, 40 | len(data), 41 | full_name) 42 | ) 43 | print() 44 | else: 45 | # Do CRC on two folders 46 | folder1 = sys.argv[1] 47 | names1 = sorted(os.listdir(folder1)) 48 | folder2 = sys.argv[2] 49 | names2 = sorted(os.listdir(folder2)) 50 | names = list(names1) 51 | names.extend(x for x in names2 if x not in names) 52 | 53 | if '4-reference-binaries' in folder1: 54 | src = '[--originals--]' 55 | elif 'output' in folder1: 56 | src = '[---output----]' 57 | else: 58 | src = '[{0: ^13}]'.format(folder1[0:13]).replace(' ', '-') 59 | 60 | if '4-reference-binaries' in folder2: 61 | dest = '[--originals--]' 62 | elif 'output' in folder2: 63 | dest = '[---output----]' 64 | else: 65 | dest = '[{0: ^13}]'.format(folder2[0:13]).replace(' ', '-') 66 | 67 | print('Results for release: ' + os.path.basename(folder1)) 68 | print(src + ' ' + dest) 69 | print('Checksum Size Checksum Size Match Filename') 70 | print('-----------------------------------------------------------') 71 | 72 | for name in names: 73 | if name.endswith(".bin"): 74 | full_name1 = os.path.join(folder1, name) 75 | full_name2 = os.path.join(folder2, name) 76 | 77 | if name in names1 and name in names2 and os.path.isfile(full_name1) and os.path.isfile(full_name2): 78 | with open(full_name1, 'rb') as f: 79 | data1 = f.read() 80 | with open(full_name2, 'rb') as f: 81 | data2 = f.read() 82 | crc1 = zlib.crc32(data1) & 0xffffffff 83 | crc2 = zlib.crc32(data2) & 0xffffffff 84 | match = ' Yes ' if crc1 == crc2 and len(data1) == len(data2) else ' No ' 85 | print('%08x %5d %08x %5d %s %s' % ( 86 | crc1, 87 | len(data1), 88 | crc2, 89 | len(data2), 90 | match, 91 | name) 92 | ) 93 | elif name in names1 and os.path.isfile(full_name1): 94 | with open(full_name1, 'rb') as f: 95 | data = f.read() 96 | print('%08x %5d %s %s %s %s' % ( 97 | zlib.crc32(data) & 0xffffffff, 98 | len(data), 99 | '- ', 100 | ' -', 101 | ' - ', 102 | name) 103 | ) 104 | elif name in names2 and os.path.isfile(full_name2): 105 | with open(full_name2, 'rb') as f: 106 | data = f.read() 107 | print('%s %s %08x %5d %s %s' % ( 108 | '- ', 109 | ' -', 110 | zlib.crc32(data) & 0xffffffff, 111 | len(data), 112 | ' - ', 113 | name) 114 | ) 115 | print() 116 | 117 | 118 | if __name__ == '__main__': 119 | main() 120 | -------------------------------------------------------------------------------- /1-source-files/main-sources/RunImage.arm: -------------------------------------------------------------------------------- 1 | \ ****************************************************************************** 2 | \ 3 | \ LANDER !RunImage SOURCE 4 | \ 5 | \ Lander was written by David Braben and is copyright D.J.Braben 1987 6 | \ 7 | \ The code on this site has been reconstructed from a disassembly of the game on 8 | \ the Arthur, RISC OS 2 and RISC OS 3.00 application discs 9 | \ 10 | \ The commentary is copyright Mark Moxon, and any misunderstandings or mistakes 11 | \ in the documentation are entirely my fault 12 | \ 13 | \ The terminology and notations used in this commentary are explained at 14 | \ https://lander.bbcelite.com/terminology 15 | \ 16 | \ The deep dive articles referred to in this commentary can be found at 17 | \ https://lander.bbcelite.com/deep_dives 18 | \ 19 | \ ------------------------------------------------------------------------------ 20 | \ 21 | \ This source file contains decryption code for the RISC OS version of Lander. 22 | \ It decrypts the main game code as part of the !RunImage binary. 23 | \ 24 | \ ------------------------------------------------------------------------------ 25 | \ 26 | \ This source file produces the following binary file: 27 | \ 28 | \ * !RunImage.unprot.bin 29 | \ 30 | \ after reading in the following file: 31 | \ 32 | \ * GameCode.bin 33 | \ 34 | \ ****************************************************************************** 35 | 36 | CODE = &00008000 \ The build address for the Absolute file 37 | 38 | INCLUDE "3-assembled-output/exports.arm" 39 | 40 | \ ****************************************************************************** 41 | \ 42 | \ LANDER !RunImage CODE 43 | \ 44 | \ Produces the binary file !RunImage.unprot.bin. 45 | \ 46 | \ ****************************************************************************** 47 | 48 | DIM CODE% &A000 \ Reserve a block in memory for the 49 | \ assembled code 50 | 51 | FOR pass% = 4 TO 6 STEP 2 \ Perform a two-pass assembly, using both 52 | \ P% and O%, with errors enabled on the 53 | \ second pass only 54 | 55 | O% = CODE% \ Assemble the code into the reserved block 56 | \ of memory at CODE% 57 | 58 | P% = CODE \ Assemble the code so it runs at the 59 | \ address in CODE 60 | 61 | [ \ Switch from BASIC into assembly language 62 | 63 | OPT pass% \ Set the assembly option for this pass 64 | 65 | \ ****************************************************************************** 66 | \ 67 | \ Name: RunImageEntry 68 | \ Type: Subroutine 69 | \ Category: Copy protection 70 | \ Summary: Entry point for the !RunImage Absolute file 71 | \ 72 | \ ****************************************************************************** 73 | 74 | B DecryptGameBinary \ RISC OS runs !RunImage as an Absolute file 75 | \ which executes from the first instruction 76 | \ rather than having an execute address, so 77 | \ this jumps to the decryption routine to 78 | \ decrypt the game binary before jumping to 79 | \ Entry to start the game 80 | 81 | \ ****************************************************************************** 82 | \ 83 | \ Name: gameCode 84 | \ Type: Variable 85 | \ Category: Copy protection 86 | \ Summary: The unencrypted game code 87 | \ 88 | \ ****************************************************************************** 89 | 90 | .gameCode 91 | 92 | INCBIN "3-assembled-output/GameCode.bin" 93 | 94 | .gameCodeEnd 95 | 96 | \ ****************************************************************************** 97 | \ 98 | \ Name: DecryptGameBinary 99 | \ Type: Subroutine 100 | \ Category: Copy protection 101 | \ Summary: Placeholder routine to decrypt game code to &8000 so it can be run 102 | \ 103 | \ ****************************************************************************** 104 | 105 | .DecryptGameBinary 106 | 107 | LDR R0, gameCodeAddr \ Set R0 to the address of the game code 108 | 109 | LDR R1, absoluteAddr \ Set R1 to the address of the start of the 110 | \ Absolute file 111 | 112 | LDR R2, gameCodeEndAddr \ Set R2 to the address of the end of the 113 | \ game code 114 | 115 | .decr1 116 | 117 | LDR R12, [R0], #4 \ Copy a word from R0 to R1, updating the 118 | STR R12, [R1], #4 \ addresses as we go (this is where the 119 | \ decryption process would work, but 120 | \ currently it is just a copy) 121 | 122 | CMP R0, R2 \ Loop back until we have copied the whole 123 | BNE decr1 \ game 124 | 125 | B Entry \ Start the game by jumping to the Entry 126 | \ routine 127 | 128 | \ ****************************************************************************** 129 | \ 130 | \ Name: absoluteAddr 131 | \ Type: Variable 132 | \ Category: Copy protection 133 | \ Summary: The address of the start of the Absolute file 134 | \ 135 | \ ****************************************************************************** 136 | 137 | .absoluteAddr 138 | 139 | EQUD CODE 140 | 141 | \ ****************************************************************************** 142 | \ 143 | \ Name: gameCodeAddr 144 | \ Type: Variable 145 | \ Category: Copy protection 146 | \ Summary: The address of the game code 147 | \ 148 | \ ****************************************************************************** 149 | 150 | .gameCodeAddr 151 | 152 | EQUD gameCode 153 | 154 | \ ****************************************************************************** 155 | \ 156 | \ Name: gameCodeEndAddr 157 | \ Type: Variable 158 | \ Category: Copy protection 159 | \ Summary: The address of the end of the game code 160 | \ 161 | \ ****************************************************************************** 162 | 163 | .gameCodeEndAddr 164 | 165 | EQUD gameCodeEnd 166 | 167 | \ ****************************************************************************** 168 | \ 169 | \ Two-pass assembly loop 170 | \ 171 | \ ****************************************************************************** 172 | 173 | ] 174 | 175 | NEXT pass% \ Loop back for the second pass 176 | 177 | \ ****************************************************************************** 178 | \ 179 | \ Save !RunImage.unprot.bin 180 | \ 181 | \ ****************************************************************************** 182 | 183 | OSCLI "SAVE !RunImage "+STR$~CODE%+" "+STR$~O%+" "+STR$~CODE+" "+STR$~CODE 184 | -------------------------------------------------------------------------------- /3-assembled-output/RunImgSrc,fff: -------------------------------------------------------------------------------- 1 | REM ****************************************************************************** 2 | REM 3 | REM LANDER !RunImage SOURCE 4 | REM 5 | REM Lander was written by David Braben and is copyright D.J.Braben 1987 6 | REM 7 | REM The code on this site has been reconstructed from a disassembly of the game on 8 | REM the Arthur, RISC OS 2 and RISC OS 3.00 application discs 9 | REM 10 | REM The commentary is copyright Mark Moxon, and any misunderstandings or mistakes 11 | REM in the documentation are entirely my fault 12 | REM 13 | REM The terminology and notations used in this commentary are explained at 14 | REM https;//lander.bbcelite.com/terminology 15 | REM 16 | REM The deep dive articles referred to in this commentary can be found at 17 | REM https;//lander.bbcelite.com/deep_dives 18 | REM 19 | REM ------------------------------------------------------------------------------ 20 | REM 21 | REM This source file produces the following binary file; 22 | REM 23 | REM * !RunImage.unprot.bin 24 | REM 25 | REM ****************************************************************************** 26 | 27 | CODE = &00008000 : REM The build address for the Absolute file 28 | 29 | INCLUDE "3-assembled-output/exports.arm" 30 | 31 | REM ****************************************************************************** 32 | REM 33 | REM LANDER !RunImage CODE 34 | REM 35 | REM Produces the binary file !RunImage.unprot.bin. 36 | REM 37 | REM ****************************************************************************** 38 | 39 | DIM CODE% &A000 : REM Reserve a block in memory for the 40 | : REM assembled code 41 | 42 | FOR pass% = 4 TO 6 STEP 2 : REM Perform a two-pass assembly, using both 43 | : REM P% and O%, with errors enabled on the 44 | : REM second pass only 45 | 46 | O% = CODE% : REM Assemble the code into the reserved block 47 | : REM of memory at CODE% 48 | 49 | P% = CODE : REM Assemble the code so it runs at the 50 | : REM address in CODE 51 | 52 | [ \ Switch from BASIC into assembly language 53 | 54 | OPT pass% \ Set the assembly option for this pass 55 | 56 | \ ****************************************************************************** 57 | \ 58 | \ Name; RunImageEntry 59 | \ Type; Subroutine 60 | \ Category; Copy protection 61 | \ Summary; Entry point for the !RunImage Absolute file 62 | \ 63 | \ ****************************************************************************** 64 | 65 | B DecryptGameBinary \ RISC OS runs !RunImage as an Absolute file 66 | \ which executes from the first instruction 67 | \ rather than having an execute address, so 68 | \ this jumps to the decryption routine to 69 | \ decrypt the game binary before jumping to 70 | \ Entry to start the game 71 | 72 | \ ****************************************************************************** 73 | \ 74 | \ Name; gameCode 75 | \ Type; Variable 76 | \ Category; Copy protection 77 | \ Summary; The unencrypted game code 78 | \ 79 | \ ****************************************************************************** 80 | 81 | .gameCode 82 | 83 | INCBIN "3-assembled-output/GameCode.bin" 84 | 85 | .gameCodeEnd 86 | 87 | \ ****************************************************************************** 88 | \ 89 | \ Name; DecryptGameBinary 90 | \ Type; Subroutine 91 | \ Category; Copy protection 92 | \ Summary; Placeholder routine to decrypt game code to &8000 so it can be run 93 | \ 94 | \ ****************************************************************************** 95 | 96 | .DecryptGameBinary 97 | 98 | LDR R0, gameCodeAddr \ Set R0 to the address of the game code 99 | 100 | LDR R1, absoluteAddr \ Set R1 to the address of the start of the 101 | \ Absolute file 102 | 103 | LDR R2, gameCodeEndAddr \ Set R2 to the address of the end of the 104 | \ game code 105 | 106 | .decr1 107 | 108 | LDR R12, [R0], #4 \ Copy a word from R0 to R1, updating the 109 | STR R12, [R1], #4 \ addresses as we go [this is where the 110 | \ decryption process would work, but 111 | \ currently it is just a copy] 112 | 113 | CMP R0, R2 \ Loop back until we have copied the whole 114 | BNE decr1 \ game 115 | 116 | B Entry \ Start the game by jumping to the Entry 117 | \ routine 118 | 119 | \ ****************************************************************************** 120 | \ 121 | \ Name; absoluteAddr 122 | \ Type; Variable 123 | \ Category; Copy protection 124 | \ Summary; The address of the start of the Absolute file 125 | \ 126 | \ ****************************************************************************** 127 | 128 | .absoluteAddr 129 | 130 | EQUD CODE 131 | 132 | \ ****************************************************************************** 133 | \ 134 | \ Name; gameCodeAddr 135 | \ Type; Variable 136 | \ Category; Copy protection 137 | \ Summary; The address of the game code 138 | \ 139 | \ ****************************************************************************** 140 | 141 | .gameCodeAddr 142 | 143 | EQUD gameCode 144 | 145 | \ ****************************************************************************** 146 | \ 147 | \ Name; gameCodeEndAddr 148 | \ Type; Variable 149 | \ Category; Copy protection 150 | \ Summary; The address of the end of the game code 151 | \ 152 | \ ****************************************************************************** 153 | 154 | .gameCodeEndAddr 155 | 156 | EQUD gameCodeEnd 157 | 158 | \ ****************************************************************************** 159 | \ 160 | \ Two-pass assembly loop 161 | \ 162 | \ ****************************************************************************** 163 | 164 | ] 165 | 166 | NEXT pass% : REM Loop back for the second pass 167 | 168 | REM ****************************************************************************** 169 | REM 170 | REM Save !RunImage.unprot.bin 171 | REM 172 | REM ****************************************************************************** 173 | 174 | OSCLI "SAVE !RunImage "+STR$~CODE%+" "+STR$~O%+" "+STR$~CODE+" "+STR$~CODE 175 | 176 | END 177 | 178 | DEF FN_AlignWithZeroes 179 | a = P% AND 3 180 | IF a > 0 THEN 181 | FOR I% = 1 TO 4 - a 182 | [ 183 | OPT pass% 184 | EQUB 0 185 | ] 186 | NEXT I% 187 | ENDIF 188 | =pass% 189 | -------------------------------------------------------------------------------- /2-build-files/decrypt/lander-decrypt.arm: -------------------------------------------------------------------------------- 1 | EQUD 0x00009A10 ; 0000EDB0 : 00009A10 : .... 2 | EQUD 0x000050F2 ; 0000EDB4 : 000050F2 : .P.. 3 | EQUD 0x00001CBA ; 0000EDB8 : 00001CBA : .... 4 | EQUD 0x00000700 ; 0000EDBC : 00000700 : .... 5 | EQUD 0x00000700 ; 0000EDC0 : 00000700 : .... 6 | EQUD 0x00000160 ; 0000EDC4 : 00000160 : `... 7 | 8 | EQUD 0xE3A004FB ; 0000EDC8 : E3A004FB : .... 9 | EQUD 0xE3CE133F ; 0000EDCC : E3CE133F : ?... 10 | EQUD 0xE5010004 ; 0000EDD0 : E5010004 : .... 11 | 12 | ADR R0, 0x0000EDB0 ; 0000EDD4 : E24F002C : ,.O. 13 | LDMIA R0, {R8-R13} ; 0000EDD8 : E8903F00 : .?.. 14 | SUB R10, R0, R10 ; 0000EDDC : E040A00A : ..@. 15 | SUB R9, R10, R9 ; 0000EDE0 : E04A9009 : ..J. 16 | ADD R8, R9, R8 ; 0000EDE4 : E0898008 : .... 17 | MOV R6, R8 ; 0000EDE8 : E1A06008 : .`.. 18 | ADD R1, R11, R12 ; 0000EDEC : E08B100C : .... 19 | ADD R7, R6, R1, LSL #2 ; 0000EDF0 : E0867101 : .q.. 20 | MOV R5, R10 ; 0000EDF4 : E1A0500A : .P.. 21 | MOV R4, #0 ; 0000EDF8 : E3A04000 : .@.. 22 | 23 | .0x0000EDFC 24 | MOV R2, R6 ; 0000EDFC : E1A02006 : . .. 25 | MVN R3, #0 ; 0000EE00 : E3E03000 : .0.. 26 | 27 | .0x0000EE04 28 | SUBS R11, R11, #1 ; 0000EE04 : E25BB001 : ..[. 29 | BLT 0x0000EEB0 ; 0000EE08 : BA000028 : (... 30 | LDRB R1, [R5], #1 ; 0000EE0C : E4D51001 : .... 31 | SUBS R0, R1, #0xA ; 0000EE10 : E251000A : ..Q. 32 | BGE 0x0000EE64 ; 0000EE14 : AA000012 : .... 33 | CMP R1, #0 ; 0000EE18 : E3510000 : ..Q. 34 | BNE 0x0000EE48 ; 0000EE1C : 1A000009 : .... 35 | LDRB R0, [R5], #1 ; 0000EE20 : E4D50001 : .... 36 | LDRB R1, [R5], #1 ; 0000EE24 : E4D51001 : .... 37 | ORR R0, R0, R1, LSL #8 ; 0000EE28 : E1800401 : .... 38 | LDRB R1, [R5], #1 ; 0000EE2C : E4D51001 : .... 39 | ORR R0, R0, R1, LSL #16 ; 0000EE30 : E1800801 : .... 40 | LDRB R1, [R5], #1 ; 0000EE34 : E4D51001 : .... 41 | ORR R0, R0, R1, LSL #24 ; 0000EE38 : E1800C01 : .... 42 | ADD R3, R3, R0 ; 0000EE3C : E0833000 : .0.. 43 | STR R3, [R6], #4 ; 0000EE40 : E4863004 : .0.. 44 | B 0x0000EE04 ; 0000EE44 : EAFFFFEE : .... 45 | 46 | .0x0000EE48 47 | SUB R11, R11, R1 ; 0000EE48 : E04BB001 : ..K. 48 | ADD R11, R11, #1 ; 0000EE4C : E28BB001 : .... 49 | .0x0000EE50 50 | ADD R3, R3, #1 ; 0000EE50 : E2833001 : .0.. 51 | STR R3, [R6], #4 ; 0000EE54 : E4863004 : .0.. 52 | SUBS R1, R1, #1 ; 0000EE58 : E2511001 : ..Q. 53 | BGT 0x0000EE50 ; 0000EE5C : CAFFFFFB : .... 54 | B 0x0000EE04 ; 0000EE60 : EAFFFFE7 : .... 55 | 56 | .0x0000EE64 57 | CMP R1, #0x5C ; 0000EE64 : E351005C : \.Q. 58 | ADDLT R3, R3, R0 ; 0000EE68 : B0833000 : .0.. 59 | STRLT R3, [R6], #4 ; 0000EE6C : B4863004 : .0.. 60 | BLT 0x0000EE04 ; 0000EE70 : BAFFFFE3 : .... 61 | SUBS R0, R1, #0xAE ; 0000EE74 : E25100AE : ..Q. 62 | BLT 0x0000EE98 ; 0000EE78 : BA000006 : .... 63 | LDRB R1, [R5], #1 ; 0000EE7C : E4D51001 : .... 64 | ORR R0, R1, R0, LSL #16 ; 0000EE80 : E1810800 : .... 65 | LDRB R1, [R5], #1 ; 0000EE84 : E4D51001 : .... 66 | ORR R0, R0, R1, LSL #8 ; 0000EE88 : E1800401 : .... 67 | ADD R3, R3, R0 ; 0000EE8C : E0833000 : .0.. 68 | STR R3, [R6], #4 ; 0000EE90 : E4863004 : .0.. 69 | B 0x0000EE04 ; 0000EE94 : EAFFFFDA : .... 70 | 71 | .0x0000EE98 72 | SUBS R0, R1, #0x5C ; 0000EE98 : E251005C : \.Q. 73 | LDRB R1, [R5], #1 ; 0000EE9C : E4D51001 : .... 74 | ORR R0, R1, R0, LSL #8 ; 0000EEA0 : E1810400 : .... 75 | ADD R3, R3, R0 ; 0000EEA4 : E0833000 : .0.. 76 | STR R3, [R6], #4 ; 0000EEA8 : E4863004 : .0.. 77 | B 0x0000EE04 ; 0000EEAC : EAFFFFD4 : .... 78 | 79 | .0x0000EEB0 80 | CMP R4, #0 ; 0000EEB0 : E3540000 : ..T. 81 | BNE 0x0000EECC ; 0000EEB4 : 1A000004 : .... 82 | MOV R11, R12 ; 0000EEB8 : E1A0B00C : .... 83 | MOV R12, R2 ; 0000EEBC : E1A0C002 : .... 84 | MOV R2, R6 ; 0000EEC0 : E1A02006 : . .. 85 | MOV R4, #1 ; 0000EEC4 : E3A04001 : .@.. 86 | B 0x0000EDFC ; 0000EEC8 : EAFFFFCB : .... 87 | 88 | .0x0000EECC 89 | MOV R11, R2 ; 0000EECC : E1A0B002 : .... 90 | ADR R5, 0x0000EEF0 ; 0000EED0 : E28F5018 : .P.. 91 | ADR R6, 0x0000F018 ; 0000EED4 : E28F6F4F : Oo.. 92 | MOV R4, R7 ; 0000EED8 : E1A04007 : .@.. 93 | 94 | .0x0000EEDC 95 | LDMIA R5!, {R0-R3} ; 0000EEDC : E8B5000F : .... 96 | STMIA R7!, {R0-R3} ; 0000EEE0 : E8A7000F : .... 97 | CMP R5, R6 ; 0000EEE4 : E1550006 : ..U. 98 | BLT 0x0000EEDC ; 0000EEE8 : BAFFFFFB : .... 99 | MOV PC, R4 ; 0000EEEC : E1A0F004 : .... 100 | 101 | .0x0000EEF0 102 | ADD R9, R9, R13 ; 0000EEF0 : E089900D : .... 103 | SUB R8, R8, #4 ; 0000EEF4 : E2488004 : ..H. 104 | 105 | .0x0000EEF8 106 | CMP R10, R9 ; 0000EEF8 : E15A0009 : ..Z. 107 | BLE 0x0000EFE0 ; 0000EEFC : DA000037 : 7... 108 | LDRB R6, [R10, #-1]! ; 0000EF00 : E57A6001 : .`z. 109 | AND R3, R6, #0xF ; 0000EF04 : E206300F : .0.. 110 | SUBS R0, R3, #9 ; 0000EF08 : E2530009 : ..S. 111 | BLT 0x0000EF20 ; 0000EF0C : BA000003 : .... 112 | LDRB R1, [R10, #-1]! ; 0000EF10 : E57A1001 : ..z. 113 | ORR R0, R1, R0, LSL #8 ; 0000EF14 : E1810400 : .... 114 | LDR R4, [R12, R0, LSL #2] ; 0000EF18 : E79C4100 : .A.. 115 | B 0x0000EF68 ; 0000EF1C : EA000011 : .... 116 | 117 | .0x0000EF20 118 | SUBS R0, R3, #2 ; 0000EF20 : E2530002 : ..S. 119 | BLT 0x0000EF40 ; 0000EF24 : BA000005 : .... 120 | LDRB R1, [R10, #-1]! ; 0000EF28 : E57A1001 : ..z. 121 | ORR R0, R1, R0, LSL #8 ; 0000EF2C : E1810400 : .... 122 | LDR R0, [R11, R0, LSL #2] ; 0000EF30 : E79B0100 : .... 123 | LDRB R1, [R10, #-1]! ; 0000EF34 : E57A1001 : ..z. 124 | ORR R4, R1, R0, LSL #8 ; 0000EF38 : E1814400 : .D.. 125 | B 0x0000EF68 ; 0000EF3C : EA000009 : .... 126 | 127 | .0x0000EF40 128 | CMP R3, #0 ; 0000EF40 : E3530000 : ..S. 129 | MOVEQ R4, R3 ; 0000EF44 : 01A04003 : .@.. 130 | BEQ 0x0000EF68 ; 0000EF48 : 0A000006 : .... 131 | LDRB R0, [R10, #-1]! ; 0000EF4C : E57A0001 : ..z. 132 | LDRB R1, [R10, #-1]! ; 0000EF50 : E57A1001 : ..z. 133 | ORR R0, R0, R1, LSL #8 ; 0000EF54 : E1800401 : .... 134 | LDRB R1, [R10, #-1]! ; 0000EF58 : E57A1001 : ..z. 135 | ORR R0, R0, R1, LSL #16 ; 0000EF5C : E1800801 : .... 136 | LDRB R1, [R10, #-1]! ; 0000EF60 : E57A1001 : ..z. 137 | ORR R4, R0, R1, LSL #24 ; 0000EF64 : E1804C01 : .L.. 138 | 139 | .0x0000EF68 140 | MOV R3, R6, LSR #4 ; 0000EF68 : E1A03226 : &2.. 141 | SUBS R0, R3, #9 ; 0000EF6C : E2530009 : ..S. 142 | BLT 0x0000EF88 ; 0000EF70 : BA000004 : .... 143 | LDRB R1, [R10, #-1]! ; 0000EF74 : E57A1001 : ..z. 144 | ORR R0, R1, R0, LSL #8 ; 0000EF78 : E1810400 : .... 145 | LDR R5, [R12, R0, LSL #2] ; 0000EF7C : E79C5100 : .Q.. 146 | STMDB R8!, {R4-R5} ; 0000EF80 : E9280030 : 0.(. 147 | B 0x0000EEF8 ; 0000EF84 : EAFFFFDB : .... 148 | 149 | .0x0000EF88 150 | SUBS R0, R3, #2 ; 0000EF88 : E2530002 : ..S. 151 | BLT 0x0000EFAC ; 0000EF8C : BA000006 : .... 152 | LDRB R1, [R10, #-1]! ; 0000EF90 : E57A1001 : ..z. 153 | ORR R0, R1, R0, LSL #8 ; 0000EF94 : E1810400 : .... 154 | LDR R0, [R11, R0, LSL #2] ; 0000EF98 : E79B0100 : .... 155 | LDRB R1, [R10, #-1]! ; 0000EF9C : E57A1001 : ..z. 156 | ORR R5, R1, R0, LSL #8 ; 0000EFA0 : E1815400 : .T.. 157 | STMDB R8!, {R4-R5} ; 0000EFA4 : E9280030 : 0.(. 158 | B 0x0000EEF8 ; 0000EFA8 : EAFFFFD2 : .... 159 | 160 | .0x0000EFAC 161 | CMP R3, #0 ; 0000EFAC : E3530000 : ..S. 162 | MOVEQ R5, R3 ; 0000EFB0 : 01A05003 : .P.. 163 | STMDBEQ R8!, {R4-R5} ; 0000EFB4 : 09280030 : 0.(. 164 | BEQ 0x0000EEF8 ; 0000EFB8 : 0AFFFFCE : .... 165 | LDRB R0, [R10, #-1]! ; 0000EFBC : E57A0001 : ..z. 166 | LDRB R1, [R10, #-1]! ; 0000EFC0 : E57A1001 : ..z. 167 | ORR R0, R0, R1, LSL #8 ; 0000EFC4 : E1800401 : .... 168 | LDRB R1, [R10, #-1]! ; 0000EFC8 : E57A1001 : ..z. 169 | ORR R0, R0, R1, LSL #16 ; 0000EFCC : E1800801 : .... 170 | LDRB R1, [R10, #-1]! ; 0000EFD0 : E57A1001 : ..z. 171 | ORR R5, R0, R1, LSL #24 ; 0000EFD4 : E1805C01 : .\.. 172 | STMDB R8!, {R4-R5} ; 0000EFD8 : E9280030 : 0.(. 173 | B 0x0000EEF8 ; 0000EFDC : EAFFFFC5 : .... 174 | 175 | .0x0000EFE0 176 | CMP R13, #0 ; 0000EFE0 : E35D0000 : ..]. 177 | BLE 0x0000F008 ; 0000EFE4 : DA000007 : .... 178 | SUB R6, R9, R13 ; 0000EFE8 : E049600D : .`I. 179 | MOV R9, R7 ; 0000EFEC : E1A09007 : .... 180 | ADD R10, R9, R13 ; 0000EFF0 : E089A00D : .... 181 | 182 | .0x0000EFF4 183 | LDMIA R6!, {R0-R3} ; 0000EFF4 : E8B6000F : .... 184 | STMIA R7!, {R0-R3} ; 0000EFF8 : E8A7000F : .... 185 | SUBS R13, R13, #0x10 ; 0000EFFC : E25DD010 : ..]. 186 | BGT 0x0000EFF4 ; 0000F000 : CAFFFFFB : .... 187 | B 0x0000EEF8 ; 0000F004 : EAFFFFBB : .... 188 | 189 | .0x0000F008 190 | ADD R8, R8, #0x14 ; 0000F008 : E2888014 : .... 191 | ADD R8, R8, #0x2600 ; 0000F00C : E2888C26 : &... 192 | MOV PC, R8 ; 0000F010 : E1A0F008 : .... 193 | 194 | EQUD &20636372 ; 0000F014 : 20636372 : rcc 195 | 196 | .0x0000F018 197 | EQUS "0.23" ; 0000F018 : 33322E30 : 0.23 198 | -------------------------------------------------------------------------------- /3-assembled-output/exports.arm: -------------------------------------------------------------------------------- 1 | .set OS_WriteC, 0x00000000 2 | .set xObject, 0x00000000 3 | .set STORE, 0x00000000 4 | .set LANDSCAPE_Y, 0x00000000 5 | .set OS_WriteS, 0x00000001 6 | .set OS_ReadC, 0x00000004 7 | .set HALF_TILES_X, 0x00000006 8 | .set OS_Byte, 0x00000006 9 | .set OS_Word, 0x00000007 10 | .set zObject, 0x00000008 11 | .set LAUNCHPAD_OBJECT, 0x00000009 12 | .set TILES_Z, 0x0000000B 13 | .set TILES_X, 0x0000000D 14 | .set OS_Mouse, 0x0000001C 15 | .set OS_BinaryToDecimal, 0x00000028 16 | .set rotationMatrix, 0x00000030 17 | .set xNoseV, 0x00000030 18 | .set xRoofV, 0x00000034 19 | .set xSideV, 0x00000038 20 | .set yNoseV, 0x0000003C 21 | .set yRoofV, 0x00000040 22 | .set ySideV, 0x00000044 23 | .set zNoseV, 0x00000048 24 | .set zRoofV, 0x0000004C 25 | .set zSideV, 0x00000050 26 | .set xVertex, 0x00000054 27 | .set varOffset, 0x00000054 28 | .set yVertex, 0x00000058 29 | .set xVertexRotated, 0x00000064 30 | .set labOffset, 0x0000006C 31 | .set xCoord, 0x00000074 32 | .set yCoord, 0x00000078 33 | .set xObjectScaled, 0x00000084 34 | .set xPlayer, 0x00000094 35 | .set yPlayer, 0x00000098 36 | .set xVelocity, 0x000000A0 37 | .set yVelocity, 0x000000A4 38 | .set zVelocity, 0x000000A8 39 | .set previousColumn, 0x000000C4 40 | .set typeOffset, 0x000000CC 41 | .set tileCornerRow, 0x000000E4 42 | .set unusedConfig, 0x000000F0 43 | .set objectType, 0x000000F4 44 | .set tileRowOddEven, 0x000000F8 45 | .set altitude, 0x00000100 46 | .set prevAltitude, 0x00000104 47 | .set particleEnd, 0x00000108 48 | .set particleCount, 0x0000010C 49 | .set objectData, 0x00000110 50 | .set objectFlags, 0x00000114 51 | .set mainLoopCount, 0x00000118 52 | .set crashLoopCount, 0x0000011C 53 | .set crashedFlag, 0x00000120 54 | .set currentScore, 0x00000124 55 | .set fuelLevel, 0x00000128 56 | .set gravity, 0x0000012C 57 | .set playingGame, 0x00000130 58 | .set remainingLives, 0x00000134 59 | .set highScore, 0x00000138 60 | .set xCamera, 0x0000013C 61 | .set yCamera, 0x00000140 62 | .set zCamera, 0x00000144 63 | .set xCameraTile, 0x00000148 64 | .set zCameraTile, 0x00000150 65 | .set shipDirection, 0x00000154 66 | .set shipPitch, 0x00000158 67 | .set fuelBurnRate, 0x0000015C 68 | .set xLandscapeRow, 0x00000160 69 | .set zLandscapeRow, 0x00000168 70 | .set xLandscapeCol, 0x00000170 71 | .set yLandscapeCol, 0x00000174 72 | .set MAX_PARTICLES, 0x000001E4 73 | .set stringBuffer, 0x00000200 74 | .set cornerStore1, 0x00000400 75 | .set cornerStore2, 0x00000500 76 | .set vertexProjected, 0x00000600 77 | .set particleData, 0x00000700 78 | .set BUFFER_SIZE, 0x000010D4 79 | .set objectMap, 0x00004400 80 | .set CODE, 0x00008000 81 | .set landscapeOffset, 0x00008000 82 | .set landscapeOffsetAddr, 0x0000800C 83 | .set landscapeConfig, 0x00008010 84 | .set landscapeConfigAddr, 0x00008028 85 | .set graphicsBuffers, 0x0000802C 86 | .set graphicsBuffersEnd, 0x0000805C 87 | .set DrawLandscapeAndBuffers, 0x0000808C 88 | .set land1, 0x000080DC 89 | .set land2, 0x00008114 90 | .set land3, 0x0000816C 91 | .set land4, 0x00008170 92 | .set land5, 0x000081E0 93 | .set GetLandscapeAltitude, 0x000081F4 94 | .set GetLandscapeBelowVertex, 0x000082AC 95 | .set GetLandscapeTileColour, 0x000082DC 96 | .set MoveAndDrawPlayer, 0x00008398 97 | .set ship1, 0x00008400 98 | .set ship2, 0x00008408 99 | .set ship3, 0x0000841C 100 | .set ship4, 0x00008424 101 | .set ship5, 0x00008508 102 | .set ship6, 0x0000850C 103 | .set ship7, 0x000085F4 104 | .set ship8, 0x00008650 105 | .set LandOnLaunchpad, 0x00008654 106 | .set LoseLifeFromParticleLoop, 0x000086C4 107 | .set LoseLife, 0x000086C8 108 | .set lose1, 0x000086EC 109 | .set GameOver, 0x00008744 110 | .set graphicsBuffEndAddr2, 0x000087EC 111 | .set MoveAndDrawParticles, 0x000087F4 112 | .set dpar1, 0x00008800 113 | .set dpar2, 0x0000880C 114 | .set dpar3, 0x000088E8 115 | .set dpar4, 0x00008904 116 | .set SetParticleColourToFade, 0x0000893C 117 | .set BounceParticle, 0x00008998 118 | .set ProcessObjectDestruction, 0x000089C8 119 | .set AddSmallExplosionToBuffer, 0x00008A28 120 | .set SplashParticleIntoSea, 0x00008A34 121 | .set psea1, 0x00008A4C 122 | .set DeleteParticleData, 0x00008A58 123 | .set AddBulletParticleToBuffer, 0x00008A84 124 | .set AddExhaustParticleToBuffer, 0x00008A8C 125 | .set AddStaticParticleToBuffer, 0x00008A94 126 | .set AddRisingParticleToBuffer, 0x00008A98 127 | .set AddMovingParticleToBuffer, 0x00008AA0 128 | .set StoreParticleData, 0x00008AC8 129 | .set InitialiseParticleData, 0x00008AF4 130 | .set AddSmokeParticleToBuffer, 0x00008B0C 131 | .set AddDebrisParticleToBuffer, 0x00008B70 132 | .set DropARockFromTheSky, 0x00008BD8 133 | .set AddSparkParticleToBuffer, 0x00008C40 134 | .set AddSprayParticleToBuffer, 0x00008C58 135 | .set AddExplosionToBuffer, 0x00008CBC 136 | .set expl1, 0x00008CC0 137 | .set AddShipExplosionToBuffer, 0x00008CDC 138 | .set AddSparkCloudToBuffer, 0x00008CFC 139 | .set spcl1, 0x00008D14 140 | .set SpawnRock, 0x00008D24 141 | .set DropRocksFromTheSky, 0x00008D40 142 | .set objectTypes, 0x00008D78 143 | .set DrawObjects, 0x00008DDC 144 | .set dobs1, 0x00008DFC 145 | .set dobs2, 0x00008E04 146 | .set dobs3, 0x00008E1C 147 | .set dobs4, 0x00008E38 148 | .set dobs5, 0x00008E80 149 | .set dobs6, 0x00008E8C 150 | .set objectPlayerAddr, 0x00008EBC 151 | .set objectRockAddr, 0x00008EC0 152 | .set DrawObject, 0x00008EC4 153 | .set dobj1, 0x00008EFC 154 | .set dobj2, 0x00008F54 155 | .set dobj3, 0x00008FBC 156 | .set dobj4, 0x00009038 157 | .set dobj5, 0x000090F4 158 | .set PrintCurrentScore, 0x00009108 159 | .set prsc1, 0x00009140 160 | .set PrintScoreInBothBanks, 0x00009160 161 | .set prsb1, 0x000091A0 162 | .set prsb2, 0x000091D8 163 | .set fuelBarColour, 0x000091EC 164 | .set sinTableAddr, 0x000091F0 165 | .set arctanTableAddr, 0x000091F4 166 | .set squareRootTableAddr, 0x000091F8 167 | .set DrawFuelLevel, 0x000091FC 168 | .set graphicsBufferEndAddr, 0x0000924C 169 | .set graphicsBufferAddr, 0x00009250 170 | .set MultiplyVectorByMatrix, 0x00009254 171 | .set GetDotProduct, 0x0000928C 172 | .set dotp1, 0x000092BC 173 | .set dotp2, 0x00009308 174 | .set dotp3, 0x00009358 175 | .set TransposeRotationMatrix, 0x0000937C 176 | .set AddVectorsWithFeedback, 0x000093B4 177 | .set CalculateRotationMatrix, 0x000093E4 178 | .set rmat1, 0x00009450 179 | .set rmat2, 0x00009498 180 | .set rmat3, 0x000094E4 181 | .set rmat4, 0x00009530 182 | .set GetMouseInPolarCoordinates, 0x00009574 183 | .set pole1, 0x000095AC 184 | .set pole2, 0x000095CC 185 | .set pole3, 0x000095D4 186 | .set pole4, 0x000095F0 187 | .set pole5, 0x00009624 188 | .set pole6, 0x00009648 189 | .set ProjectParticleOntoScreen, 0x00009670 190 | .set ppar1, 0x000096A8 191 | .set ppar2, 0x000096DC 192 | .set ppar3, 0x00009700 193 | .set ProjectVertexOntoScreen, 0x00009748 194 | .set pver1, 0x00009788 195 | .set pver2, 0x000097B8 196 | .set pver3, 0x000097DC 197 | .set pver4, 0x00009820 198 | .set pver5, 0x00009830 199 | .set pver6, 0x00009864 200 | .set pver7, 0x00009890 201 | .set vmod1, 0x000098E4 202 | .set vmod2, 0x000098E8 203 | .set vmod3, 0x000098EC 204 | .set vmod4, 0x000098F0 205 | .set vmod5, 0x000098F4 206 | .set AddVectors, 0x000098F8 207 | .set AddVectorToVertices, 0x0000991C 208 | .set MultiplyVectorByConstant, 0x00009948 209 | .set vcon1, 0x0000997C 210 | .set vcon2, 0x000099C4 211 | .set vcon3, 0x00009A0C 212 | .set randomSeed1, 0x00009A38 213 | .set randomSeed2, 0x00009A3C 214 | .set GetRandomNumbers, 0x00009A40 215 | .set screenAddr, 0x00009A6C 216 | .set greyColourWords, 0x00009A70 217 | .set greyColourWordsAddr, 0x00009AC0 218 | .set Draw1x1ParticleFromBuffer, 0x00009AC4 219 | .set Draw2x1ParticleFromBuffer, 0x00009AE8 220 | .set Draw2x2ParticleFromBuffer, 0x00009B10 221 | .set Draw3x2ParticleFromBuffer, 0x00009B40 222 | .set Draw3x1ParticleFromBuffer, 0x00009B78 223 | .set DrawTriangleFromBuffer, 0x00009BA4 224 | .set DrawParticleToBuffer, 0x00009BB8 225 | .set DrawParticleShadowToBuffer, 0x00009BF4 226 | .set DrawTriangleShadowToBuffer, 0x00009C28 227 | .set DrawTriangleToBuffer, 0x00009C58 228 | .set bufferJump, 0x00009C8C 229 | .set DrawGraphicsBuffer, 0x00009CDC 230 | .set DrawNextFromGraphicsBuffer, 0x00009CEC 231 | .set TerminateGraphicsBuffer, 0x00009CF8 232 | .set AddTerminatorsToBuffers, 0x00009CFC 233 | .set term1, 0x00009D10 234 | .set screenBank2Addr, 0x00009D2C 235 | .set screenBank1Addr, 0x00009D30 236 | .set screenBankNumber, 0x00009D34 237 | .set divisionTableAddr, 0x00009D38 238 | .set SwitchScreenBank, 0x00009D3C 239 | .set bank1, 0x00009DAC 240 | .set DrawQuadrilateral, 0x00009DC8 241 | .set DrawTriangle, 0x00009DDC 242 | .set trin1, 0x00009E20 243 | .set trin2, 0x00009E40 244 | .set trin3, 0x00009E60 245 | .set trin4, 0x00009E98 246 | .set trin5, 0x00009EA4 247 | .set trin6, 0x00009EBC 248 | .set trin7, 0x00009EEC 249 | .set trin8, 0x00009EF8 250 | .set trin9, 0x00009F10 251 | .set trin10, 0x00009F38 252 | .set trin11, 0x00009F8C 253 | .set trin12, 0x00009F98 254 | .set trin13, 0x00009FB0 255 | .set trin14, 0x00009FEC 256 | .set trin15, 0x0000A014 257 | .set trin16, 0x0000A030 258 | .set trin17, 0x0000A05C 259 | .set trin18, 0x0000A068 260 | .set trin19, 0x0000A080 261 | .set trin20, 0x0000A0B0 262 | .set trin21, 0x0000A0BC 263 | .set trin22, 0x0000A0D4 264 | .set trin23, 0x0000A110 265 | .set trin24, 0x0000A158 266 | .set trin25, 0x0000A178 267 | .set trin26, 0x0000A198 268 | .set trin27, 0x0000A1CC 269 | .set trin28, 0x0000A1D8 270 | .set trin29, 0x0000A1F0 271 | .set trin30, 0x0000A220 272 | .set trin31, 0x0000A22C 273 | .set trin32, 0x0000A244 274 | .set trin33, 0x0000A2A0 275 | .set trin34, 0x0000A2AC 276 | .set trin35, 0x0000A2C4 277 | .set trin36, 0x0000A300 278 | .set trin37, 0x0000A30C 279 | .set trin38, 0x0000A328 280 | .set trin39, 0x0000A354 281 | .set trin40, 0x0000A360 282 | .set trin41, 0x0000A378 283 | .set trin42, 0x0000A3A8 284 | .set trin43, 0x0000A3B4 285 | .set trin44, 0x0000A3CC 286 | .set trin45, 0x0000A408 287 | .set trin46, 0x0000A414 288 | .set trin47, 0x0000A46C 289 | .set trin48, 0x0000A470 290 | .set lineJump, 0x0000A480 291 | .set DrawHorizontalLine, 0x0000A4C8 292 | .set hlin1, 0x0000A4F4 293 | .set DrawLineSegment, 0x0000A524 294 | .set workspaceAddr, 0x0000A56C 295 | .set stackAddr, 0x0000A570 296 | .set memoryTestAddr, 0x0000A574 297 | .set initialScore, 0x0000A578 298 | .set initialHighScore, 0x0000A57C 299 | .set initialFuelLevel, 0x0000A580 300 | .set stackPointerOnEntry, 0x0000A584 301 | .set mouseParameters, 0x0000A588 302 | .set mouseParametersAddr, 0x0000A590 303 | .set ResetMousePosition, 0x0000A594 304 | .set AbortWithMemoryError, 0x0000A5A4 305 | .set Entry, 0x0000A614 306 | .set entr1, 0x0000A6E4 307 | .set StartNewGame, 0x0000A734 308 | .set PlaceObjectsOnMap, 0x0000A774 309 | .set snew1, 0x0000A78C 310 | .set snew2, 0x0000A7A0 311 | .set snew3, 0x0000A7E0 312 | .set PlacePlayerOnLaunchpad, 0x0000A7F8 313 | .set MainLoop, 0x0000A850 314 | .set EndGame, 0x0000A8AC 315 | .set ReturnToDesktop, 0x0000A8D4 316 | .set PrintHexNumber, 0x0000A8E0 317 | .set PrintHexDigit, 0x0000A948 318 | .set objectRock, 0x0000A960 319 | .set objectRockVertices, 0x0000A970 320 | .set objectRockFaces, 0x0000A9B8 321 | .set objectPyramid, 0x0000AA98 322 | .set objectPyramidVertices, 0x0000AAA8 323 | .set objectPyramidFaces, 0x0000AAE4 324 | .set objectPlayer, 0x0000AB8C 325 | .set objectPlayerVertices, 0x0000AB9C 326 | .set objectPlayerFaces, 0x0000AC08 327 | .set objectSmallLeafyTree, 0x0000AD04 328 | .set objectSmallLeafyTreeVertices, 0x0000AD14 329 | .set objectSmallLeafyTreeFaces, 0x0000AD98 330 | .set objectTallLeafyTree, 0x0000AE24 331 | .set objectTallLeafyTreeVertices, 0x0000AE34 332 | .set objectTallLeafyTreeFaces, 0x0000AEDC 333 | .set objectSmokingRemainsLeft, 0x0000AF84 334 | .set objectSmokingRemainsLeftVertices, 0x0000AF94 335 | .set objectSmokingRemainsLeftFaces, 0x0000AFD0 336 | .set objectSmokingRemainsRight, 0x0000B008 337 | .set objectSmokingRemainsRightVertices, 0x0000B018 338 | .set objectSmokingRemainsRightFaces, 0x0000B054 339 | .set objectFirTree, 0x0000B08C 340 | .set objectFirTreeVertices, 0x0000B09C 341 | .set objectFirTreeFaces, 0x0000B0D8 342 | .set objectGazebo, 0x0000B110 343 | .set objectGazeboVertices, 0x0000B120 344 | .set objectGazeboFaces, 0x0000B1BC 345 | .set objectBuilding, 0x0000B29C 346 | .set objectBuildingVertices, 0x0000B2AC 347 | .set objectBuildingFaces, 0x0000B36C 348 | .set objectSmokingBuilding, 0x0000B4BC 349 | .set objectSmokingBuildingVertices, 0x0000B4CC 350 | .set objectSmokingBuildingFaces, 0x0000B514 351 | .set objectSmokingGazebo, 0x0000B5BC 352 | .set objectSmokingGazeboVertices, 0x0000B5CC 353 | .set objectSmokingGazeboFaces, 0x0000B614 354 | .set objectRocket, 0x0000B684 355 | .set objectRocketVertices, 0x0000B694 356 | .set objectRocketFaces, 0x0000B730 357 | .set sinTable, 0x0000B810 358 | .set arctanTable, 0x0000C810 359 | .set squareRootTable, 0x0000CA10 360 | .set divisionTable, 0x0000DA10 361 | .set endCode, 0x00011A10 362 | .set stack, 0x000121FC 363 | .set workspace, 0x00012200 364 | .set buffers, 0x00014400 365 | .set buffer, 0x00032FF0 366 | .set SMOKE_RISING_SPEED, 0x00080000 367 | .set SPLASH_HEIGHT, 0x00100000 368 | .set LANDING_SPEED, 0x00200000 369 | .set CRASH_CLOUD_Y, 0x00500000 370 | .set UNDERCARRIAGE_Y, 0x00640000 371 | .set SMOKE_HEIGHT, 0x00C00000 372 | .set TILE_SIZE, 0x01000000 373 | .set SAFE_HEIGHT, 0x01800000 374 | .set LAUNCHPAD_Y, 0x02EC0000 375 | .set LAUNCHPAD_ALTITUDE, 0x03500000 376 | .set CAMERA_PLAYER_Z, 0x05000000 377 | .set LAND_MID_HEIGHT, 0x05000000 378 | .set SEA_LEVEL, 0x05500000 379 | .set LANDSCAPE_X, 0x05800000 380 | .set LANDSCAPE_X_HALF, 0x06000000 381 | .set PLAYER_FRONT_Z, 0x06000000 382 | .set LAUNCHPAD_SIZE, 0x08000000 383 | .set LANDSCAPE_Z_DEPTH, 0x0A000000 384 | .set LANDSCAPE_Z_FRONT, 0x0A000000 385 | .set LANDSCAPE_Z_BEYOND, 0x0B000000 386 | .set LANDSCAPE_X_WIDTH, 0x0B000000 387 | .set LANDSCAPE_Z_MID, 0x0F000000 388 | .set LANDSCAPE_Z, 0x14000000 389 | .set ROCK_HEIGHT, 0x20000000 390 | .set HIGHEST_ALTITUDE, 0x34000000 391 | -------------------------------------------------------------------------------- /2-build-files/decrypt/lander-decrypt.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # 3 | # ****************************************************************************** 4 | # 5 | # LANDER DECRYPTION SCRIPT 6 | # 7 | # Written by Mark Moxon 8 | # 9 | # This script decrypts the !RunImage file from the RISC OS variant of Lander and 10 | # saves the results into 3-assembled-output/!RunImage.decrypt.bin 11 | # 12 | # This file is identical to the Arthur variant's GameCode binary, proving that 13 | # the two variants are identical in terms of game code 14 | # 15 | # ****************************************************************************** 16 | 17 | 18 | def write_word(addr, word): 19 | if addr < 0x8000: 20 | print("Write error to !" + hex(addr)) 21 | return 22 | # print("!" + hex(addr - 0x8000) + " (" + hex(addr) + ") = " + hex(word)) 23 | lander_code[addr - 0x8000] = word & 0xFF 24 | lander_code[addr - 0x8000 + 1] = ((word & (0xFF << 8)) >> 8) 25 | lander_code[addr - 0x8000 + 2] = ((word & (0xFF << 16)) >> 16) 26 | lander_code[addr - 0x8000 + 3] = ((word & (0xFF << 24)) >> 24) 27 | 28 | 29 | def write_byte(addr, byte): 30 | if addr < 0x8000: 31 | print("Write error to ?" + hex(addr)) 32 | return 33 | # print("?" + hex(addr - 0x8000) + " (" + hex(addr) + ") = " + hex(byte)) 34 | lander_code[addr - 0x8000] = byte & 0xFF 35 | 36 | 37 | def fetch_word(addr): 38 | # print("Fetch !" + hex(addr - 0x8000) + " (" + hex(addr) + ")") 39 | word = lander_code[addr - 0x8000 + 3] << 24 40 | word += lander_code[addr - 0x8000 + 2] << 16 41 | word += lander_code[addr - 0x8000 + 1] << 8 42 | word += lander_code[addr - 0x8000] 43 | return word 44 | 45 | 46 | def fetch_byte(addr): 47 | # print("Fetch ?" + hex(addr - 0x8000)+ " (" + hex(addr) + ")") 48 | return lander_code[addr - 0x8000] 49 | 50 | 51 | def run_moved_code(): 52 | global r0, r1, r2, r3, r4, r5, r6, r7, r8, r9, r10, r11, r12, r13 53 | # print("run_moved_code() with r4 = " + hex(r4) + ", r7 = " + hex(r7) + ", r8 = " + hex(r8) + ", r9 = " + hex(r9) + ", r10 = " + hex(r10) + ", r11 = " + hex(r11) + ", r12 = " + hex(r12) + ", r13 = " + hex(r13)) 54 | # .0x0000EEF0 55 | while True: 56 | r9 += r13 # 0000EEF0 ADD R9, R9, R13 57 | r8 -= 4 # 0000EEF4 SUB R8, R8, #4 58 | # .0x0000EEF8 59 | while True: 60 | if r10 <= r9: # 0000EEF8 CMP R10, R9 61 | # print("run_moved_code() with r10 <= r9 with r10 = " + hex(r10) + ", r9 = " + hex(r10)) 62 | # .0x0000EFE0 # 0000EEFC BLE 0x0000EFE0 63 | if r13 <= 0: # 0000EFE0 CMP R13, #0 64 | # .0x0000F008 65 | r8 += 0x14 # 0000F008 ADD R8, R8, #0x14 66 | r8 += 0x2600 # 0000F00C ADD R8, R8, #0x2600 67 | print("[ Info ] Jump to " + hex(r8) + " to run game") 68 | return # 0000F010 MOV PC, R8 69 | else: 70 | r6 = r9 - r13 # 0000EFE8 SUB R6, R9, R13 71 | r9 = r7 # 0000EFEC MOV R9, R7 72 | r10 = r9 + r13 # 0000EFF0 ADD R10, R9, R13 73 | # .0x0000EFF4 74 | while True: 75 | r0 = fetch_word(r6) # 0000EFF4 LDMIA R6!, {R0-R3} # Copy r13 bytes from r6 to r7 76 | r1 = fetch_word(r6 + 4) 77 | r2 = fetch_word(r6 + 8) 78 | r3 = fetch_word(r6 + 12) 79 | r6 += 16 80 | write_word(r7, r0) # 0000EFF8 STMIA R7!, {R0-R3} 81 | write_word(r7 + 4, r1) 82 | write_word(r7 + 8, r2) 83 | write_word(r7 + 12, r3) 84 | r7 += 16 85 | r13 -= 0x10 # 0000EFFC SUBS R13, R13, #0x10 86 | if r13 > 0: # 0000F000 BGT 0x0000EFF4 87 | continue 88 | else: 89 | break 90 | continue # 0000F004 B 0x0000EEF8 91 | else: 92 | # print("run_moved_code() with r10 > r9 with r10 = " + hex(r10) + ", r9 = " + hex(r10)) 93 | r10 -= 1 # 0000EF00 LDRB R6, [R10, #-1]! 94 | r6 = fetch_byte(r10) 95 | r3 = r6 & 0xF # 0000EF04 AND R3, R6, #0xF 96 | r0 = r3 - 9 # 0000EF08 SUBS R0, R3, #9 97 | if r0 < 0: # 0000EF0C BLT 0x0000EF20 98 | # .0x0000EF20 99 | r0 = r3 - 2 # 0000EF20 SUBS R0, R3, #2 100 | if r0 < 0: # 0000EF24 BLT 0x0000EF40 101 | # .0x0000EF40 102 | if r3 == 0: # 0000EF40 CMP R3, #0 103 | r4 = r3 # 0000EF44 MOVEQ R4, R3 104 | pass # 0000EF48 BEQ 0x0000EF68 105 | else: 106 | r10 -= 1 # 0000EF4C LDRB R0, [R10, #-1]! 107 | r0 = fetch_byte(r10) 108 | r10 -= 1 # 0000EF50 LDRB R1, [R10, #-1]! 109 | r1 = fetch_byte(r10) 110 | r0 = r0 | (r1 << 8) # 0000EF54 ORR R0, R0, R1, LSL #8 111 | r10 -= 1 # 0000EF58 LDRB R1, [R10, #-1]! 112 | r1 = fetch_byte(r10) 113 | r0 = r0 | (r1 << 16) # 0000EF5C ORR R0, R0, R1, LSL #16 114 | r10 -= 1 # 0000EF60 LDRB R1, [R10, #-1]! 115 | r1 = fetch_byte(r10) 116 | r4 = r0 | (r1 << 24) # ORR R4, R0, R1, LSL #24 117 | pass # Fall through into 0x0000EF68 118 | else: 119 | r10 -= 1 # 0000EF28 LDRB R1, [R10, #-1]! 120 | r1 = fetch_byte(r10) 121 | r0 = r1 | (r0 << 8) # 0000EF2C ORR R0, R1, R0, LSL #8 122 | r0 = fetch_word(r11 + (r0 << 2)) # 0000EF30 LDR R0, [R11, R0, LSL #2] 123 | r10 -= 1 # 0000EF34 LDRB R1, [R10, #-1]! 124 | r1 = fetch_byte(r10) 125 | r4 = r1 | (r0 << 8) # 0000EF38 ORR R4, R1, R0, LSL #8 126 | pass # 0000EF3C B 0x0000EF68 127 | else: 128 | r10 -= 1 # 0000EF10 LDRB R1, [R10, #-1]! 129 | r1 = fetch_byte(r10) 130 | r0 = r1 | (r0 << 8) # 0000EF14 ORR R0, R1, R0, LSL #8 131 | temp = r12 + (r0 << 2) # 0000EF18 LDR R4, [R12, R0, LSL #2] 132 | r4 = fetch_word(temp) 133 | pass # 0000EF1C B 0x0000EF68 134 | 135 | # .0x0000EF68 136 | r3 = r6 >> 4 # 0000EF68 MOV R3, R6, LSR #4 137 | r0 = r3 - 9 # 0000EF6C SUBS R0, R3, #9 138 | if r0 < 0: # 0000EF70 BLT 0x0000EF88 139 | # .0x0000EF88 140 | r0 = r3 - 2 # 0000EF88 SUBS R0, R3, #2 141 | if r0 < 0: # 0000EF8C BLT 0x0000EFAC 142 | # .0x0000EFAC 143 | if r3 == 0: # 0000EFAC CMP R3, #0 144 | r5 = r3 # 0000EFB0 MOVEQ R5, R3 145 | # print("1, r10 = " + hex(r10) + ", r9 = " + hex(r9) + ", r8 = " + hex(r8)) 146 | write_word(r8 - 4, r5) # 0000EFB4 STMDBEQ R8!, {R4-R5} 147 | write_word(r8 - 8, r4) 148 | r8 -= 8 149 | continue # 0000EFB8 BEQ 0x0000EEF8 150 | r10 -= 1 # 0000EFBC LDRB R0, [R10, #-1]! 151 | r0 = fetch_byte(r10) 152 | r10 -= 1 # 0000EFC0 LDRB R1, [R10, #-1]! 153 | r1 = fetch_byte(r10) 154 | r0 = r0 | (r1 << 8) # 0000EFC4 ORR R0, R0, R1, LSL #8 155 | r10 -= 1 # 0000EFC8 LDRB R1, [R10, #-1]! 156 | r1 = fetch_byte(r10) 157 | r0 = r0 | (r1 << 16) # 0000EFCC ORR R0, R0, R1, LSL #16 158 | r10 -= 1 # 0000EFD0 LDRB R1, [R10, #-1]! 159 | r1 = fetch_byte(r10) 160 | r5 = r0 | (r1 << 24) # 0000EFD4 ORR R5, R0, R1, LSL #24 161 | # print("2, r10 = " + hex(r10) + ", r9 = " + hex(r9) + ", r8 = " + hex(r8)) 162 | write_word(r8 - 4, r5) # 0000EFD8 STMDB R8!, {R4-R5} 163 | write_word(r8 - 8, r4) 164 | r8 -= 8 165 | continue # 0000EFDC B 0x0000EEF8 166 | else: 167 | r10 -= 1 # 0000EF90 LDRB R1, [R10, #-1]! 168 | r1 = fetch_byte(r10) 169 | r0 = r1 | (r0 << 8) # 0000EF94 ORR R0, R1, R0, LSL #8 170 | r0 = fetch_word(r11 + (r0 << 2)) # 0000EF98 LDR R0, [R11, R0, LSL #2] 171 | r10 -= 1 # 0000EF9C LDRB R1, [R10, #-1]! 172 | r1 = fetch_byte(r10) 173 | r5 = r1 | (r0 << 8) # 0000EFA0 ORR R5, R1, R0, LSL #8 174 | # print("3, r10 = " + hex(r10) + ", r9 = " + hex(r9) + ", r8 = " + hex(r8)) 175 | write_word(r8 - 4, r5) # 0000EFA4 STMDB R8!, {R4-R5} 176 | write_word(r8 - 8, r4) 177 | r8 -= 8 178 | continue # 0000EFA8 B 0x0000EEF8 179 | else: 180 | r10 -= 1 # 0000EF74 LDRB R1, [R10, #-1]! 181 | r1 = fetch_byte(r10) 182 | r0 = r1 | (r0 << 8) # 0000EF78 ORR R0, R1, R0, LSL #8 183 | r5 = fetch_word(r12 + (r0 << 2)) # 0000EF7C LDR R5, [R12, R0, LSL #2] 184 | # print("4, r10 = " + hex(r10) + ", r9 = " + hex(r9) + ", r8 = " + hex(r8)) 185 | write_word(r8 - 4, r5) # 0000EF80 STMDB R8!, {R4-R5} 186 | write_word(r8 - 8, r4) 187 | r8 -= 8 188 | continue # 0000EF84 B 0x0000EEF8 189 | 190 | 191 | print() 192 | print("RISC OS 2 Lander decryption") 193 | 194 | lander_code = bytearray() 195 | 196 | # Load assembled code file 197 | 198 | lander_file = open("!RunImage.bin", "rb") 199 | lander_code.extend(lander_file.read()) 200 | lander_file.close() 201 | 202 | # Extend bytearray to cover 0x8000 to 0x20000 203 | 204 | lander_code.extend(bytearray(0x20000 - 0x8000 - len(lander_code))) 205 | 206 | print() 207 | print("[ Read ] !RunImage.bin") 208 | 209 | # Do decryption 210 | 211 | pass # 0000EDB0 0x00009A10 212 | pass # 0000EDB4 0x000050F2 213 | pass # 0000EDB8 0x00001CBA 214 | pass # 0000EDBC 0x00000700 215 | pass # 0000EDC0 0x00000700 216 | pass # 0000EDC4 0x00000160 217 | 218 | r0 = 0x0000EDB0 # 0000EDD8 ADR R0, 0x0000EDB0 219 | r8 = 0x00009A10 # 0000EDD8 LDMIA R0, {R8-R13} 220 | r9 = 0x000050F2 221 | r10 = 0x00001CBA 222 | r11 = 0x00000700 223 | r12 = 0x00000700 224 | r13 = 0x00000160 225 | 226 | r10 = r0 - r10 # 0000EDDC SUB R10, R0, R10 # EDB0 - 1CBA = D0F6 227 | r9 = r10 - r9 # 0000EDE0 SUB R9, R10, R9 # D0F6 - 50F2 = 8004 228 | r8 = r9 + r8 # 0000EDE4 ADD R8, R9, R8 # 8004 + 9A10 = 11A14 229 | r6 = r8 # 0000EDE8 MOV R6, R8 # 11A14 230 | r1 = r11 + r12 # 0000EDEC ADD R1, R11, R12 # 0700 + 0700 = 1400 231 | r7 = r6 + (r1 << 2) # 0000EDF0 ADD R7, R6, R1, LSL #2 # 11A14 + 1400 << 2 = 11A14 + 5000 = 16A14 232 | r5 = r10 # 0000EDF4 MOV R5, R10 # D0F6 233 | r4 = 0 # 0000EDF8 MOV R4, #0 # 0 for first loop, 1 for second loop, controls relocation 234 | 235 | # .0x0000EDFC 236 | while True: 237 | r2 = r6 # 0000EDFC MOV R2, R6 238 | r3 = -1 # 0000EE00 MVN R3, #0 239 | 240 | # .0x0000EE04 241 | while True: 242 | r11 -= 1 # 0000EE04 SUBS R11, R11, #1 243 | if r11 < 0: # 0000EE08 BLT 0x0000EEB0 244 | break 245 | r1 = fetch_byte(r5) # 0000EE0C LDRB R1, [R5], #1 246 | r5 += 1 247 | r0 = r1 - 0xA # 0000EE10 SUBS R0, R1, #0xA 248 | if r0 >= 0: # 0000EE14 BGE 0x0000EE64 249 | # print("main loop with r0 >= 0 with r0 = " + hex(r0)) 250 | # .0x0000EE64 251 | if r1 < 0x5C: # 0000EE64 CMP R1, #0x5C 252 | r3 = r3 + r0 # 0000EE68 ADDLT R3, R3, R0 253 | write_word(r6, r3) # 0000EE6C STRLT R3, [R6], #4 254 | r6 += 4 255 | continue # 0000EE70 BLT 0x0000EE04 256 | r0 = r1 - 0xAE # 0000EE74 SUBS R0, R1, #0xAE 257 | if r0 < 0: # 0000EE78 BLT 0x0000EE98 258 | # .0x0000EE98 259 | r0 = r1 - 0x5C # 0000EE98 SUBS R0, R1, #0x5C 260 | r1 = fetch_byte(r5) # 0000EE9C LDRB R1, [R5], #1 261 | r5 += 1 262 | r0 = r1 | (r0 << 8) # 0000EEA0 ORR R0, R1, R0, LSL #8 263 | r3 += r0 # 0000EEA4 ADD R3, R3, R0 264 | write_word(r6, r3) # 0000EEA8 STR R3, [R6], #4 265 | r6 += 4 266 | continue # 0000EEAC B 0x0000EE04 267 | r1 = fetch_byte(r5) # 0000EE7C LDRB R1, [R5], #1 268 | r5 += 1 269 | r0 = r1 | (r0 << 16) # 0000EE80 ORR R0, R1, R0, LSL #16 270 | r1 = fetch_byte(r5) # 0000EE84 LDRB R1, [R5], #1 271 | r5 += 1 272 | r0 = r0 | (r1 << 8) # 0000EE88 ORR R0, R0, R1, LSL #8 273 | r3 += r0 # 0000EE8C ADD R3, R3, R0 274 | write_word(r6, r3) # 0000EE90 STR R3, [R6], #4 275 | r6 += 4 276 | continue # 0000EE94 B 0x0000EE04 277 | elif r1 != 0: # 0000EE18 CMP R1, #0 278 | # print("main loop with r0 < 0 and r1 != 0 with r0 = " + hex(r0) + ", r1 = " + hex(r1)) 279 | # .0x0000EE48 # 0000EE1C BNE 0x0000EE48 280 | r11 -= r1 # 0000EE48 SUB R11, R11, R1 281 | r11 += 1 # 0000EE4C ADD R11, R11, #1 282 | # .0x0000EE50 283 | while True: 284 | r3 += 1 # 0000EE50 ADD R3, R3, #1 285 | write_word(r6, r3) # 0000EE54 STR R3, [R6], #4 286 | r6 += 4 287 | r1 -= 1 # 0000EE58 SUBS R1, R1, #1 288 | if r1 > 0: # 0000EE5C BGT 0x0000EE50 289 | continue 290 | else: 291 | break 292 | continue # 0000EE60 B 0x0000EE04 293 | else: 294 | # print("main loop else with r0 = " + hex(r0) + ", r1 = " + hex(r1)) 295 | r0 = fetch_byte(r5) # 0000EE20 LDRB R0, [R5], #1 296 | r5 += 1 297 | r1 = fetch_byte(r5) # 0000EE24 LDRB R1, [R5], #1 298 | r5 += 1 299 | r0 = r0 | (r1 << 8) # 0000EE28 ORR R0, R0, R1, LSL #8 300 | r1 = fetch_byte(r5) # 0000EE2C LDRB R1, [R5], #1 301 | r5 += 1 302 | r0 = r0 | (r1 << 16) # 0000EE30 ORR R0, R0, R1, LSL #16 303 | r1 = fetch_byte(r5) # 0000EE34 LDRB R1, [R5], #1 304 | r5 += 1 305 | r0 = r0 | (r1 << 24) # 0000EE38 ORR R0, R0, R1, LSL #24 306 | r3 += r0 # 0000EE3C ADD R3, R3, R0 307 | write_word(r6, r3) # 0000EE40 STR R3, [R6], #4 308 | r6 += 4 309 | continue # 0000EE44 B 0x0000EE04 310 | 311 | # 0x0000EEB0 312 | if r4 != 0: # 0000EEB0 CMP R4, #0 313 | # print("main loop with r4 != 0 with r4 = " + hex(r4)) 314 | # .0x0000EECC # 0000EEB4 BNE 0x0000EECC 315 | r11 = r2 # 0000EECC MOV R11, R2 316 | r5 = 0x0000EEF0 # 0000EED0 ADR R5, 0x0000EEF0 317 | r6 = 0x0000F018 # 0000EED4 ADR R6, 0x0000F018 318 | r4 = r7 # 0000EED8 MOV R4, R7 319 | # print("Moving code from r5 = " + hex(r5) + " to r7 = " + hex(r7)) 320 | # .0x0000EEDC 321 | while True: 322 | r0 = fetch_word(r5) # 0000EEDC LDMIA R5!, {R0-R3} # Copy 0x0000EEF0-0x0000F018 to address in r7 323 | r1 = fetch_word(r5 + 4) 324 | r2 = fetch_word(r5 + 8) 325 | r3 = fetch_word(r5 + 12) 326 | r5 += 16 327 | write_word(r7, r0) # 0000EEE0 STMIA R7!, {R0-R3} 328 | write_word(r7 + 4, r1) 329 | write_word(r7 + 8, r2) 330 | write_word(r7 + 12, r3) 331 | r7 += 16 332 | if r5 < r6: # 0000EEE4 CMP R5, R6 333 | continue # 0000EEE8 BLT 0x0000EEDC 334 | else: 335 | break 336 | run_moved_code() # 0000EEEC MOV PC, R4 # Jump to location in r4, i.e. to start of copied code 337 | break # End program 338 | else: 339 | # print("main loop with r4 != 0 with r4 = " + hex(r4)) 340 | r11 = r12 # 0000EEB8 MOV R11, R12 341 | r12 = r2 # 0000EEBC MOV R12, R2 342 | r2 = r6 # 0000EEC0 MOV R2, R6 343 | r4 = 1 # 0000EEC4 MOV R4, #1 344 | continue # 0000EEC8 B 0x0000EDFC 345 | 346 | print("[ Decrypt ] !RunImage.bin") 347 | 348 | # Write output file for !RunImage.decrypt 349 | 350 | output_file = open("!RunImage.decrypt.bin", "wb") 351 | output_file.write(lander_code[0: 0x9A10]) 352 | output_file.close() 353 | 354 | print("[ Save ] !RunImage.decrypt.bin") 355 | print() 356 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Fully documented source code for Lander on the Acorn Archimedes 2 | 3 | [BBC Micro cassette Elite](https://github.com/markmoxon/elite-source-code-bbc-micro-cassette) | [BBC Micro disc Elite](https://github.com/markmoxon/elite-source-code-bbc-micro-disc) | [Acorn Electron Elite](https://github.com/markmoxon/elite-source-code-acorn-electron) | [6502 Second Processor Elite](https://github.com/markmoxon/elite-source-code-6502-second-processor) | [Commodore 64 Elite](https://github.com/markmoxon/elite-source-code-commodore-64) | [Apple II Elite](https://github.com/markmoxon/elite-source-code-apple-ii) | [BBC Master Elite](https://github.com/markmoxon/elite-source-code-bbc-master) | [NES Elite](https://github.com/markmoxon/elite-source-code-nes) | [Elite-A](https://github.com/markmoxon/elite-a-source-code-bbc-micro) | [Teletext Elite](https://github.com/markmoxon/teletext-elite) | [Elite Universe Editor](https://github.com/markmoxon/elite-universe-editor) | [Elite Compendium (BBC Master)](https://github.com/markmoxon/elite-compendium-bbc-master) | [Elite Compendium (BBC Micro)](https://github.com/markmoxon/elite-compendium-bbc-micro) | [Elite Compendium (BBC Micro B+)](https://github.com/markmoxon/elite-compendium-bbc-micro-b-plus) | [Elite Compendium (Acorn Electron)](https://github.com/markmoxon/elite-compendium-acorn-electron) | [Elite over Econet](https://github.com/markmoxon/elite-over-econet) | [!EliteNet](https://github.com/markmoxon/elite-over-econet-acorn-archimedes) | [Flicker-free Commodore 64 Elite](https://github.com/markmoxon/c64-elite-flicker-free) | [BBC Micro Aviator](https://github.com/markmoxon/aviator-source-code-bbc-micro) | [BBC Micro Revs](https://github.com/markmoxon/revs-source-code-bbc-micro) | **Archimedes Lander** 4 | 5 | ![Screenshot of Lander on the Acorn Archimedes](https://lander.bbcelite.com/images/github/Lander.png) 6 | 7 | This repository contains source code for Lander on the Acorn Archimedes, with every single line documented and (for the most part) explained. It has been reconstructed by hand from a disassembly of the original game binaries. 8 | 9 | It is a companion to the [lander.bbcelite.com website](https://lander.bbcelite.com). 10 | 11 | See the [introduction](#introduction) for more information. 12 | 13 | ## Contents 14 | 15 | * [Introduction](#introduction) 16 | 17 | * [Acknowledgements](#acknowledgements) 18 | 19 | * [A note on licences, copyright etc.](#user-content-a-note-on-licences-copyright-etc) 20 | 21 | * [Browsing the source in an IDE](#browsing-the-source-in-an-ide) 22 | 23 | * [Folder structure](#folder-structure) 24 | 25 | * [Extending the landscape with BigLander](#extending-the-landscape-with-biglander) 26 | 27 | * [Building Lander from the source](#building-lander-from-the-source) 28 | 29 | * [Requirements](#requirements) 30 | * [Build targets](#build-targets) 31 | * [Windows](#windows) 32 | * [Mac and Linux](#mac-and-linux) 33 | * [Archimedes](#archimedes) 34 | * [Verifying the output](#verifying-the-output) 35 | * [Encryption in the RISC OS variant](#encryption-in-the-risc-os-variant) 36 | * [Log files](#log-files) 37 | 38 | ## Introduction 39 | 40 | This repository contains source code for Lander on the Acorn Archimedes, with every single line documented and (for the most part) explained. 41 | 42 | You can build the fully functioning game from this source. Two variants are currently supported: the Arthur variant, and the RISC OS 2 variant. 43 | 44 | It is a companion to the [lander.bbcelite.com website](https://lander.bbcelite.com), which contains all the code from this repository, but laid out in a much more human-friendly fashion. 45 | 46 | * If you want to browse the source and read about how Lander works under the hood, you will probably find [the website](https://lander.bbcelite.com) is a better place to start than this repository. 47 | 48 | * If you would rather explore the source code in your favourite IDE, then the [annotated source](1-source-files/main-sources/Lander.arm) is what you're looking for. It contains the exact same content as the website, so you won't be missing out (the website is generated from the source files, so they are guaranteed to be identical). You might also like to read the section on [browsing the source in an IDE](#browsing-the-source-in-an-ide) for some tips. 49 | 50 | * If you want to build Lander from the source on a modern computer, to produce a working game disc that can be loaded into a Acorn Archimedes or an emulator, then you want the section on [building Lander from the source](#building-lander-from-the-source). You can also build the source on an Archimedes, as described in the the [Archimedes](#archimedes) section. 51 | 52 | My hope is that this repository 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 magic of David Braben's 32-bit masterpiece, and the first ever game for the ARM platform. 53 | 54 | ## Acknowledgements 55 | 56 | Lander was written by David Braben and is copyright © D.J.Braben 1987. 57 | 58 | The code on this site has been reconstructed from a disassembly of the version released on the [application discs for Arthur and RISC OS](http://www.lewisgilbert.co.uk/archiology/osdiscs.html). 59 | 60 | The commentary is copyright © Mark Moxon. Any misunderstandings or mistakes in the documentation are entirely my fault. 61 | 62 | ### A note on licences, copyright etc. 63 | 64 | This repository is _not_ provided with a licence, and there is intentionally no `LICENSE` file provided. 65 | 66 | According to [GitHub's licensing documentation](https://docs.github.com/en/free-pro-team@latest/github/creating-cloning-and-archiving-repositories/licensing-a-repository), this means that "the default copyright laws apply, meaning that you retain all rights to your source code and no one may reproduce, distribute, or create derivative works from your work". 67 | 68 | The reason for this is that my commentary is intertwined with the original Lander game code, and the original game is copyright. The whole site is therefore covered by default copyright law, to ensure that this copyright is respected. 69 | 70 | Under GitHub's rules, you have the right to read and fork this repository... but that's it. No other use is permitted, I'm afraid. 71 | 72 | My hope is that the educational and non-profit intentions of this repository will enable it to stay hosted and available, but the original copyright holders do have the right to ask for it to be taken down, in which case I will comply without hesitation. I do hope, though, that along with the various other disassemblies and commentaries of Acornsoft's games for the BBC Micro and Archimedes, it will remain viable. 73 | 74 | ## Browsing the source in an IDE 75 | 76 | If you want to browse the source in an IDE, you might find the following useful. 77 | 78 | * The most interesting files are in the [main-sources](1-source-files/main-sources) folder: 79 | 80 | * The main game's source code is in the [Lander.arm](1-source-files/main-sources/Lander.arm) file - this is the motherlode and probably contains all the stuff you're interested in. It produces a file called `GameCode` that contains the entire game. 81 | 82 | * The RISC OS application bundles up the game into a `!RunImage`, whose source is in the [RunImage.arm](1-source-files/main-sources/RunImage.arm) file. In the version on the RISC OS application disc the `!RunImage` binary is encrypted, but in this version the game binary is simply wrapped in a relocation routine (though encryption may be added later). 83 | 84 | * It's probably worth skimming through the [notes on terminology and notations](https://lander.bbcelite.com/terminology/) on the accompanying website, as this explains a number of terms used in the commentary, without which it might be a bit tricky to follow at times. 85 | 86 | * The entry point for the [main game code](1-source-files/main-sources/lander-source.asm) is routine `Entry`, which you can find by searching for `Name: Entry`. 87 | 88 | * The source code is designed to be read at an 80-column width and with a monospaced font, just like in the good old days. 89 | 90 | I hope you enjoy exploring the inner workings of Lander as much as I have. 91 | 92 | ## Folder structure 93 | 94 | There are five main folders in this repository, which reflect the order of the build process. 95 | 96 | * [1-source-files](1-source-files) contains all the different source files, such as the main assembler source files, BASIC loaders, RISC OS application files and so on. 97 | 98 | * [2-build-files](2-build-files) contains build-related scripts, such as the crc32 verification scripts and vasm converter script. 99 | 100 | * [3-assembled-output](3-assembled-output) contains the output from the assembly process, when the source files are assembled and the results processed by the build files. 101 | 102 | * [4-reference-binaries](4-reference-binaries) contains the correct binaries for each release, so we can verify that our assembled output matches the reference. 103 | 104 | * [5-compiled-game-discs](5-compiled-game-discs) contains the final output of the build process: folders that contains the compiled game for each variant and which can be run on real hardware or in an emulator, plus zips of those folders for easier deployment. It also contains version of the source code that can be built on an Archimedes; see the [Archimedes](#archimedes) section for information on the latter. The Arthur variant contains the GameCode binary in two formats: as a pair of files (GameCode and GameCode.inf) that is suitable for programs that support inf files, or as a single file (GameCode,8000-A614) that will work with HostFS. Both options contain the load and execution address of the file, and you should choose the one that works for you when copying the game to your emulator or Archimedes. 105 | 106 | ## Extending the landscape with BigLander 107 | 108 | This repository also includes a version of Lander with a much bigger landscape: 64 by 64 tiles, to be precise (as compared to the original 12 by 10 tiles). This version also runs on all versions of RISC OS (the original only works on Arthur and RISC OS 2). The big-landscape code is in a separate branch called `big-landscape`, and apart from the code differences for the landscape size and later versions of RISC OS, this branch is identical to the main branch and the same build process applies. 109 | 110 | The landscape size is configurable. The default is 64 by 64 tiles (which equates to TILES_X = 65 and TILES_Z = 65), but you can set your own values by passing x and z parameters to the build. For example, building BigLander like this on Mac or Linux: 111 | 112 | ``` 113 | make x=122 z=122 114 | ``` 115 | 116 | or this on Windows: 117 | 118 | ``` 119 | make.bat x=122 z=122 120 | ``` 121 | 122 | would build BigLander with a landscape size of 121 x 121 tiles (i.e. TILES_X = 122 and TILES_Z = 122). The number of tiles is given in the !Help file of the generated application, along with the build date. 123 | 124 | The annotated source files in the `big-landscape` branch contain both the original Lander code and all of the modifications for the bigger landscape, so you can look through the source to see exactly what's changed. Any code that I've removed from the original version is commented out in the source files, so when they are assembled they produce the big-landscape binaries, while still containing details of all the modifications. You can find all the diffs by searching the sources for `Mod:`. 125 | 126 | BigLander should work on all versions of RISC OS, but to get it working on a Raspberry Pi, you may need to create a text file in the !Boot.Loader folder called CMDLINE/TXT, containing the word `disable_mode_changes` (reboot after you create this). Make sure you have !ADFFS loaded, and then BigLander should run. You can see a video guide to this process [on YouTube](https://www.youtube.com/watch?v=HpQk1l7Rvu0). 127 | 128 | If BigLander on your Pi is blurry, you can change the GPU upscaler method. Edit the CONFIG/TXT in !Boot.Loader and add `scaling_kernel=8` on a new line before rebooting. This will probably make your desktop a bit messy, but BigLander should now look pretty great (and you can remove the line to go back to blurry BigLander and a crisp desktop). 129 | 130 | For more information on BigLander, see the [accompanying website](https://lander.bbcelite.com/deep_dives/hacking_the_landscape.html). 131 | 132 | ## Building Lander from the source 133 | 134 | Builds are supported for Windows and Mac/Linux systems. In all cases the build process is defined in the `Makefile` provided. 135 | 136 | The build process also creates a version of the source that can be built on [Archimedes](#archimedes) machines. 137 | 138 | ### Requirements 139 | 140 | You will need the following to build Lander from the source: 141 | 142 | * vasm, which can be downloaded from the [vasm homepage](http://sun.hasenbraten.de/vasm/). 143 | 144 | * Python. The build process has only been tested on 3.x, but 2.7 might work. 145 | 146 | * Mac and Linux users may need to install `make` if it isn't already present (for Windows users, `make.exe` is included in this repository). 147 | 148 | Let's look at how to build Lander from the source. 149 | 150 | ### Windows 151 | 152 | For Windows users, there is a batch file called `make.bat` that builds the project. Before this will work, you should edit the batch file and change the values of the `VASM` and `PYTHON` variables to point to the locations of your `vasmarm_std.exe` and `python.exe` executables (you need the `vasmarm_std` executable). You also need to change directory to the repository folder (i.e. the same folder as `make.bat`). 153 | 154 | All being well, entering the following into a command window: 155 | 156 | ``` 157 | make.bat 158 | ``` 159 | 160 | will produce folders called `arthur` and `riscos` in the `5-compiled-game-discs` folder, which contain the Arthur and RISC OS variants of the game, which you can then load into an emulator, or into a real Acorn Archimedes using a device like a Gotek. It also produces a zip file for each variant, which can be found in the `zip` folder (note that these zips do not contain RISC OS filetype metadata; filetypes are included as filename suffixes, so they will work with HostFS). 161 | 162 | ### Mac and Linux 163 | 164 | The build process uses a standard GNU `Makefile`, so you just need to install `make` if your system doesn't already have it. If vasm or Python are not on your path, then you can either fix this, or you can edit the `Makefile` and change the `VASM` and `PYTHON` variables in the first two lines to point to their locations (you need the `vasmarm_std` executable). You also need to change directory to the repository folder (i.e. the same folder as `Makefile`). 165 | 166 | All being well, entering the following into a terminal window: 167 | 168 | ``` 169 | make 170 | ``` 171 | 172 | will produce folders called `arthur` and `riscos` in the `5-compiled-game-discs` folder, which contain the Arthur and RISC OS variants of the game, which you can then load into an emulator, or into a real Acorn Archimedes using a device like a Gotek. It also produces a zip file for each variant, which can be found in the `zip` folder (note that these zips do not contain RISC OS filetype metadata; filetypes are included as filename suffixes, so they will work with HostFS). 173 | 174 | ### Archimedes 175 | 176 | The build process outlined above produces a file called `LanderSrc,fff` in the `5-compiled-game-discs` folder, or `BLanderSrc,fff` if you are building BigLander. These files contain versions of the game source that can be built on an Archimedes. 177 | 178 | To build the source on an Archimedes, you first need to convert the BBC BASIC text file into tokenised BBC BASIC. If you have RISC OS 3, then you can use Edit to do this, as follows: 179 | 180 | * Download the source as a BBC BASIC text file for [Lander](https://raw.githubusercontent.com/markmoxon/lander-source-code-acorn-archimedes/main/5-compiled-game-discs/LanderSrc%2Cfff) or [BigLander](https://raw.githubusercontent.com/markmoxon/lander-source-code-acorn-archimedes/big-landscape/5-compiled-game-discs/BLanderSrc%2Cfff). 181 | 182 | * Copy the file to an Archimedes machine (if you aren't already downloading it in RISC OS). 183 | 184 | * If you are using HostFS then the filetype should be set automatically, but if you need to set it manually, it should be a Text file. 185 | 186 | * Load the text file into Edit. You should see the fully documented source code appear. 187 | 188 | * Click Menu on Edit's icon bar icon, choose "BASIC options > Line number increment" and set the value to 1. 189 | 190 | * Click Menu over Edit's window, choose "Misc > Set type" and set the value to BASIC. 191 | 192 | * Save the file, which is now a BASIC program. 193 | 194 | You now have the Lander source in BBC BASIC, which is how David Braben originally wrote it (though without quite so many comments). 195 | 196 | To build the game from this source, simply run the file by double-clicking it. It will assemble the game and save the GameCode file into the current directory, so you may want to set the current directory before doing this. You may need to allocate more memory to the Next slot for the assembly to work: you need at least 832K to build Lander, and at least 904K to build BigLander. 197 | 198 | You can play the game by simply double-clicking on the GameCode file. You can run Lander on Arthur, RISC OS 2 or up to RISC OS 3.11, and you can run BigLander on any version of RISC OS. You may need to allocate more memory to the Next slot for the game to run: you need at least 168K to run Lander, and at least 400K to run BigLander. 199 | 200 | Note that the main source code in this repository is very close to being in BBC BASIC format, but it isn't exactly the same (which is why the BBC BASIC version is created by the build process rather than actually being the main source). This is because BBC BASIC has some limitations that make it a tricky companion for large commentaries like this. For example, the colon character separates multiple statements in BBC BASIC, but this also applies within comments, so any comments that contain colons will cause runtime errors when used in BASIC. The same applies with unmatched brackets and double-quotes, though these only generate warnings (though they do break the Text to BASIC conversion process). BBC BASIC also doesn't support comma-separated EQU arguments, which makes laying out tables like the object blueprints rather difficult. 201 | 202 | As a result the main source code in this repository is an homage to BBC BASIC's assembly language format, but it is not 100% accurate. That's why the build includes a conversion script to convert the Lander.arm source file into a working BBC BASIC source. See the [convert-to-basic.py](2-build-files/convert-to-basic.py) script for details. 203 | 204 | ### Verifying the output 205 | 206 | The build process prints out checksums of all the generated files, along with the checksums of the files from the original sources. 207 | 208 | The Python script `crc32.py` in the `2-build-files` folder does the actual verification, and shows the checksums and file sizes of both sets of files, alongside each other, and with a Match column that flags any discrepancies. 209 | 210 | The binaries in the `4-reference-binaries` folder are those extracted from the released version of the game, while those in the `3-assembled-output` folder are produced by the build process. For example, if you don't make any changes to the code and build the project with `make`, then this is the output of the verification process: 211 | 212 | ``` 213 | [--originals--] [---output----] 214 | Checksum Size Checksum Size Match Filename 215 | ----------------------------------------------------------- 216 | 9985364c 39488 9985364c 39488 Yes !RunImage.bin 217 | aa7f1052 39440 aa7f1052 39440 Yes GameCode.bin 218 | ``` 219 | 220 | All the compiled binaries match the originals, so we know we are producing the same final game for both the Arthur and RISC OS variants. 221 | 222 | ### Encryption in the RISC OS variant 223 | 224 | The !RunImage file in the RISC OS variant of Lander is encrypted. The [2-build-files/decrypt](2-build-files/decrypt) folder contains a script that decrypts the binary. 225 | 226 | It turns out that the decrypted !RunImage is identical to the Arthur variant's GameCode binary, so the RISC OS variant is the exact same game, just encrypted. To prove this, I've written a Python script called [lander-decrypt.py](2-build-files/decrypt/lander-decrypt.py) that decrypts the original !RunImage binary. This Python script is based on the original decryption routine, whose source is in [lander-decrypt.arm](2-build-files/decrypt/lander-decrypt.arm).

227 | 228 | The !RunImage produced by the build process doesn't include this encryption, and in its place there's a small routine that simply copies the game code to address &8000, without making any changes (you can see this in the main [RunImage.arm](1-source-files/main-sources/RunImage.arm) source). 229 | 230 | ### Log files 231 | 232 | During compilation, details of every step are output in a file called `compile.txt` in the `3-assembled-output` folder. If you have problems, it might come in handy, and it's a great reference if you need to know the addresses of labels and variables for debugging (or just snooping around). 233 | 234 | --- 235 | 236 | _Mark Moxon_ 237 | --------------------------------------------------------------------------------