Full Code of markmoxon/elite-beebasm for AI

main a8bc28d22ed9 cached
91 files
2.3 MB
600.2k tokens
71 symbols
1 requests
Download .txt
Showing preview only (2,400K chars total). Download the full file or copy to clipboard to get everything.
Repository: markmoxon/elite-beebasm
Branch: main
Commit: a8bc28d22ed9
Files: 91
Total size: 2.3 MB

Directory structure:
gitextract_xn5smrlz/

├── .gitattributes
├── .gitignore
├── 1-source-files/
│   ├── README.md
│   ├── basic-programs/
│   │   └── README.md
│   ├── boot-files/
│   │   └── README.md
│   ├── images/
│   │   └── README.md
│   ├── main-sources/
│   │   ├── README.md
│   │   ├── elite-bcfs.asm
│   │   ├── elite-build-options.asm
│   │   ├── elite-disc.asm
│   │   ├── elite-loader.asm
│   │   ├── elite-readme.asm
│   │   └── elite-source.asm
│   └── original-sources/
│       ├── $.DEFEDIT.inf
│       ├── $.DEFEDIT.txt
│       ├── $.DEFGEN.inf
│       ├── $.DEFGEN.txt
│       ├── $.DEFTRAN.inf
│       ├── $.DEFTRAN.txt
│       ├── $.DIALGEN.inf
│       ├── $.DIALGEN.txt
│       ├── $.ELITEA.inf
│       ├── $.ELITEA.txt
│       ├── $.ELITEB.inf
│       ├── $.ELITEB.txt
│       ├── $.ELITEC.inf
│       ├── $.ELITEC.txt
│       ├── $.ELITED.inf
│       ├── $.ELITED.txt
│       ├── $.ELITEE.inf
│       ├── $.ELITEE.txt
│       ├── $.ELITEF.inf
│       ├── $.ELITEF.txt
│       ├── $.ELITEG.inf
│       ├── $.ELITEG.txt
│       ├── $.ELITES.inf
│       ├── $.ELITES.txt
│       ├── $.FINDSC2.inf
│       ├── $.FINDSC2.txt
│       ├── $.GENTOK.inf
│       ├── $.GENTOK.txt
│       ├── $.GETBIT.inf
│       ├── $.GETBIT.txt
│       ├── $.MAKER.inf
│       ├── $.MAKER.txt
│       ├── $.SBLOCK.inf
│       ├── $.SBLOCK.txt
│       ├── $.SFTPROT.inf
│       ├── $.SFTPROT.txt
│       ├── $.SHPPRTE.inf
│       ├── $.SHPPRTE.txt
│       ├── $.TOKPRI.inf
│       ├── $.TOKPRI.txt
│       ├── $.UNPACK.inf
│       ├── $.UNPACK.txt
│       ├── A.GENTOK.inf
│       ├── A.GENTOK.txt
│       ├── O.ELITED.inf
│       ├── O.ELITED.txt
│       ├── README.md
│       ├── S.BCFS.inf
│       ├── S.BCFS.txt
│       ├── S.GENTOK.inf
│       ├── S.GENTOK.txt
│       ├── S.STEST.inf
│       ├── S.STEST.txt
│       └── text-sources/
│           ├── ELITEA.txt
│           ├── ELITEB.txt
│           ├── ELITEC.txt
│           ├── ELITED.txt
│           ├── ELITEE.txt
│           ├── ELITEF.txt
│           └── ELITEG.txt
├── 2-build-files/
│   ├── README.md
│   ├── crc32.py
│   ├── elite-checksum.py
│   ├── elite-decrypt.py
│   ├── mktibet-0.3.php
│   └── tibetuef-0.8.php
├── 3-assembled-output/
│   ├── README.md
│   ├── README.txt
│   └── compile.txt
├── 4-reference-binaries/
│   └── README.md
├── 5-compiled-game-discs/
│   ├── README.md
│   ├── elite-cassette-from-source-disc.ssd
│   ├── elite-cassette-from-text-sources.ssd
│   ├── elite-cassette-sth.ssd
│   └── elite-cassette-sth.uef
├── Makefile
├── README.md
└── make.bat

================================================
FILE CONTENTS
================================================

================================================
FILE: .gitattributes
================================================
# Auto detect text files and perform LF normalization
* text=auto

# Custom for Visual Studio
*.cs     diff=csharp

# Standard to msysgit
*.doc    diff=astextplain
*.DOC    diff=astextplain
*.docx   diff=astextplain
*.DOCX   diff=astextplain
*.dot    diff=astextplain
*.DOT    diff=astextplain
*.pdf    diff=astextplain
*.PDF    diff=astextplain
*.rtf    diff=astextplain
*.RTF    diff=astextplain


================================================
FILE: .gitignore
================================================
# Windows thumbnail cache files
Thumbs.db
ehthumbs.db
ehthumbs_vista.db

# Folder config file
Desktop.ini

# Recycle Bin used on file shares
$RECYCLE.BIN/

# Windows Installer files
*.cab
*.msi
*.msm
*.msp

# Windows shortcuts
*.lnk

# IDE files
.vscode/
*.code-workspace
run.bat


================================================
FILE: 1-source-files/README.md
================================================
# Source files for the BBC Micro cassette version of Elite

This folder contains the source files for the BBC Micro cassette version of Elite.

* [basic-programs](basic-programs) contains any BASIC programs to be included on the final game disc

* [boot-files](boot-files) contains any !BOOT files to be included on the final game disc

* [images](images) contains the image binaries for the title screen and dashboard

* [main-sources](main-sources) contains the annotated source code

* [original-sources](original-sources) contains the original source code from Ian Bell's personal website

---

Right on, Commanders!

_Mark Moxon_

================================================
FILE: 1-source-files/basic-programs/README.md
================================================
# BASIC programs for the BBC Micro cassette version of Elite

This folder contains the BASIC programs from the original sources for the BBC Micro cassette version of Elite on Ian Bell's personal website.

* [$.ELITE.bin]($.ELITE.bin) is the mode 7 loader program for the version that loads from disc, with an added command to insert a key into the keyboard buffer, so the Elite loader doesn't wait for a key press

* [$.ELITE-cassette.bin]($.ELITE-cassette.bin) is the mode 7 loader program for the original cassette version

* [$.ELITE-disc.bin]($.ELITE-disc.bin) is the mode 7 loader program for the version that loads from disc

---

Right on, Commanders!

_Mark Moxon_

================================================
FILE: 1-source-files/boot-files/README.md
================================================
# Boot files for the BBC Micro cassette version of Elite

This folder contains the boot file from the original sources for the BBC Micro cassette version of Elite on Ian Bell's personal website.

* [$.!BOOT.bin]($.!BOOT.bin) is the original boot file from the game disc

---

Right on, Commanders!

_Mark Moxon_

================================================
FILE: 1-source-files/images/README.md
================================================
# Image binaries for the BBC Micro cassette version of Elite

This folder contains the image binaries from the original sources for the BBC Micro cassette version of Elite on Ian Bell's personal website.

* [P.(C)ASFT.bin](P.(C)ASFT.bin) is the "(c) ACORNSOFT 1984" image for the bottom of the title screen

* [P.A-SOFT.bin](P.A-SOFT.bin) is the "ACORNSOFT" image for the very top of the title screen

* [P.DIALS.bin](P.DIALS2P.bin) is the dashboard image

* [P.ELITE.bin](P.ELITE.bin) is the "ELITE" image for the title screen

---

Right on, Commanders!

_Mark Moxon_

================================================
FILE: 1-source-files/main-sources/README.md
================================================
# Annotated source code for the BBC Micro cassette version of Elite

This folder contains the annotated source code for the BBC Micro cassette version of Elite.

* Main source files:

  * [elite-source.asm](elite-source.asm) contains the main source for the game

  * [elite-bcfs.asm](elite-bcfs.asm) contains the Big Code File source, which concatenates individually assembled binaries into the final game binary

* Other source files:

  * [elite-loader.asm](elite-loader.asm) contains the source for the loader

  * [elite-disc.asm](elite-disc.asm) builds the SSD disc image from the assembled binaries and other source files

  * [elite-readme.asm](elite-readme.asm) generates a README file for inclusion on the SSD disc image

* Files that are generated during the build process:

  * [elite-build-options.asm](elite-build-options.asm) stores the make options in BeebAsm format so they can be included in the assembly process

---

Right on, Commanders!

_Mark Moxon_

================================================
FILE: 1-source-files/main-sources/elite-bcfs.asm
================================================
\ ******************************************************************************
\
\ BBC MICRO CASSETTE ELITE BIG CODE FILE SOURCE
\
\ BBC Micro cassette Elite was written by Ian Bell and David Braben and is
\ copyright Acornsoft 1984
\
\ The code in this file is identical to the source discs released on Ian Bell's
\ personal website at http://www.elitehomepage.org/ (it's just been reformatted
\ to be more readable)
\
\ The commentary is copyright Mark Moxon, and any misunderstandings or mistakes
\ in the documentation are entirely my fault
\
\ The terminology and notations used in this commentary are explained at
\ https://elite.bbcelite.com/terminology
\
\ The deep dive articles referred to in this commentary can be found at
\ https://elite.bbcelite.com/deep_dives
\
\ ------------------------------------------------------------------------------
\
\ This source file contains code to produce the Big Code File for BBC Micro
\ cassette Elite. The Big Code File comprises the game code and the ship
\ blueprints.
\
\ ------------------------------------------------------------------------------
\
\ This source file produces the following binary files:
\
\   * ELTcode.unprot.bin
\   * ELThead.bin
\
\ after reading in the following files:
\
\   * ELTA.bin
\   * ELTB.bin
\   * ELTC.bin
\   * ELTD.bin
\   * ELTE.bin
\   * ELTF.bin
\   * ELTG.bin
\   * SHIPS.bin
\
\ ******************************************************************************

 INCLUDE "1-source-files/main-sources/elite-build-options.asm"

 _SOURCE_DISC           = (_VARIANT = 1)
 _TEXT_SOURCES          = (_VARIANT = 2)
 _STH_CASSETTE          = (_VARIANT = 3)

 GUARD &8000            \ Guard against assembling over MOS memory

\ ******************************************************************************
\
\ Configuration variables
\
\ ******************************************************************************

 CODE% = &0F40          \ CODE% is set to the location that the main game code
                        \ gets moved to after it is loaded

 LOAD% = &1128          \ LOAD% points to the start of the actual game code,
                        \ after the &28 bytes of header code that are inserted
                        \ below

\ ******************************************************************************
\
\       Name: ZP
\       Type: Workspace
\    Address: &0070 to &0071
\   Category: Workspaces
\    Summary: Important variables used by the loader
\
\ ******************************************************************************

 ORG &0070              \ Set the assembly address to &0070

.ZP

 SKIP 2                 \ Stores addresses used for moving content around

\ ******************************************************************************
\
\ Load the compiled binaries to create the Big Code File
\
\ ******************************************************************************

 ORG &1100              \ The load address of the main game code file ("ELTcode"
                        \ for loading from disc, "ELITEcode" for loading from
                        \ tape)

\ ******************************************************************************
\
\       Name: LBL
\       Type: Subroutine
\   Category: Copy protection
\    Summary: Checksum the two pages of code that were copied from UU% to LE%
\
\ ------------------------------------------------------------------------------
\
\ This routine is called at LBL+1 from the CHECKER routine in the loader code in
\ elite-loader.asm. It calculates the checksum of the first two pages of the
\ loader code that was copied from UU% to LE% by part 3 of the loader, and
\ checks the result against the result in the first byte of the LE% block,
\ CHECKbyt, at address &0B00.
\
\ ------------------------------------------------------------------------------
\
\ Other entry points:
\
\   LBL+2               Contains an RTS
\
\ ******************************************************************************

.LBL

 EQUB &6C               \ This value is decremented by the tape loading routine
                        \ in the loader, in IRQ1. During loading this value gets
                        \ decremented down to &6C, and this new value is then
                        \ included in the checksum calculation for the MAINSUM
                        \ checksum in the CHECKER routine (the value is set to
                        \ &6C here as the tape protection is disabled)

 LDX #&60               \ Set X = &60. This value of X isn't used, it's just a
                        \ set up for the RTS call below, where we jump to LBL+2
                        \ to perform an RTS, as the opcode for RTS is &60

                        \ We now run a checksum on the block of memory from
                        \ &0B01 to &0CFF, which is the UU% routine from the
                        \ loader

 LDA #&B                \ Set ZP(1 0) = &0B00, to point to the start of the code
 STA ZP+1               \ we want to checksum

 LDY #0                 \ Set Y = 0 to count through each byte within each page
 STY ZP

 TYA                    \ Set A = 0 for building the checksum

 INY                    \ Increment Y to 1

.CHK3

 CLC                    \ Add the Y-th byte of the game code to A
 ADC (ZP),Y

 INY                    \ Increment the counter to point to the next byte

 BNE CHK3               \ Loop back for the next byte until we have finished
                        \ adding up this page

 INC ZP+1               \ Increment the high byte of ZP(1 0) to point to the
                        \ next page

.CHK4

 CLC                    \ Add the Y-th byte of this page to the checksum in A
 ADC (ZP),Y

 INY                    \ Increment the counter for this page

 BPL CHK4               \ Loop back for the next byte until we have finished
                        \ adding up this second page

 CMP &0B00              \ Compare the result to the contents of CHECKbyt in the
                        \ loader code at elite-loader.asm. This value gets set
                        \ by elite-checksum.py

 BEQ LBL+2              \ If the checksums match, jump to LBL+2, which contains
                        \ an RTS

                        \ Otherwise the checksum just failed, so we reset the
                        \ machine

 LDA #%01111111         \ Set 6522 System VIA interrupt enable register IER
 STA &FE4E              \ (SHEILA &4E) bits 0-6 (i.e. disable all hardware
                        \ interrupts from the System VIA)

 JMP (&FFFC)            \ Jump to the address in &FFFC to reset the machine

.elitea

 PRINT "elitea = ", ~P%
 INCBIN "3-assembled-output/ELTA.bin"

.eliteb

 PRINT "eliteb = ", ~P%
 INCBIN "3-assembled-output/ELTB.bin"

.elitec

 PRINT "elitec = ", ~P%
 INCBIN "3-assembled-output/ELTC.bin"

.elited

 PRINT "elited = ", ~P%
 INCBIN "3-assembled-output/ELTD.bin"

.elitee

 PRINT "elitee = ", ~P%
 INCBIN "3-assembled-output/ELTE.bin"

.elitef

 PRINT "elitef = ", ~P%
 INCBIN "3-assembled-output/ELTF.bin"

.eliteg

 PRINT "eliteg = ", ~P%
 INCBIN "3-assembled-output/ELTG.bin"

.checksum0

 PRINT "checksum0 = ", ~P%

IF _SOURCE_DISC OR _TEXT_SOURCES

 SKIP 1                 \ We skip this byte so we can insert the checksum later
                        \ in elite-checksum.py

ELIF _STH_CASSETTE

 EQUB &20               \ We skip this byte so we can insert the checksum later
                        \ in elite-checksum.py; it contains workspace noise in
                        \ the Stairway to Hell variant

ENDIF

.ships

 PRINT "ships = ", ~P%
 INCBIN "3-assembled-output/SHIPS.bin"

.end

\ ******************************************************************************
\
\ Save ELTcode.unprot.bin and ELThead.bin
\
\ ******************************************************************************

 PRINT "P% = ", ~P%
 PRINT "S.ELTcode 1100 ", ~(LOAD% + &6000 - CODE%), " ", ~LOAD%, " ", ~LOAD%
 SAVE "3-assembled-output/ELTcode.unprot.bin", &1100, (LOAD% + &6000 - CODE%), LOAD%
 SAVE "3-assembled-output/ELThead.bin", &1100, elitea, &1100


================================================
FILE: 1-source-files/main-sources/elite-build-options.asm
================================================
_VERSION=1
_VARIANT=3
_REMOVE_CHECKSUMS=FALSE
_MAX_COMMANDER=FALSE
_DISC=TRUE
_PROT=FALSE


================================================
FILE: 1-source-files/main-sources/elite-disc.asm
================================================
\ ******************************************************************************
\
\ BBC MICRO CASSETTE ELITE DISC IMAGE SCRIPT
\
\ BBC Micro cassette Elite was written by Ian Bell and David Braben and is
\ copyright Acornsoft 1984
\
\ The code in this file is identical to the source discs released on Ian Bell's
\ personal website at http://www.elitehomepage.org/ (it's just been reformatted
\ to be more readable)
\
\ The commentary is copyright Mark Moxon, and any misunderstandings or mistakes
\ in the documentation are entirely my fault
\
\ The terminology and notations used in this commentary are explained at
\ https://elite.bbcelite.com/terminology
\
\ The deep dive articles referred to in this commentary can be found at
\ https://elite.bbcelite.com/deep_dives
\
\ ------------------------------------------------------------------------------
\
\ This source file produces an SSD disc image for BBC Micro cassette Elite.
\
\ ------------------------------------------------------------------------------
\
\ This source file produces one of the following SSD disc images, depending on
\ which release is being built:
\
\   * elite-cassette-sth.ssd
\   * elite-cassette-from-source-disc.ssd
\   * elite-cassette-from-text-sources.ssd
\
\ This can be loaded into an emulator or a real BBC Micro.
\
\ ******************************************************************************

 INCLUDE "1-source-files/main-sources/elite-build-options.asm"

 _SOURCE_DISC           = (_VARIANT = 1)
 _TEXT_SOURCES          = (_VARIANT = 2)
 _STH_CASSETTE          = (_VARIANT = 3)

IF _DISC

 PUTFILE "1-source-files/boot-files/$.!BOOT.bin", "!BOOT", &FFFFFF, &FFFFFF
 PUTFILE "1-source-files/basic-programs/$.ELITE.bin", "ELITE", &FF1900, &FF8023
 PUTFILE "3-assembled-output/ELITE.bin", "ELTdata", &FF1100, &FF2000
 PUTFILE "3-assembled-output/ELTcode.bin", "ELTcode", &FF1128, &FF1128

ELSE

 PUTFILE "1-source-files/boot-files/$.!BOOT.bin", "!BOOT", &FFFFFF, &FFFFFF
 PUTFILE "1-source-files/basic-programs/$.ELITE-cassette.bin", "ELITE", &FF1900, &FF8023
\PUTFILE "3-assembled-output/ELITE.bin", "ELITEdata", &FF0E00, &FF1D00
\PUTFILE "3-assembled-output/ELTcode.bin", "ELITEcode", &000E00, &000132
 PUTFILE "3-assembled-output/ELITE.bin", "ELITEda", &FF0E00, &FF1D00
 PUTFILE "3-assembled-output/ELTcode.bin", "ELITEco", &000E00, &000132

ENDIF

 PUTFILE "3-assembled-output/README.txt", "README", &FFFFFF, &FFFFFF


================================================
FILE: 1-source-files/main-sources/elite-loader.asm
================================================
\ ******************************************************************************
\
\ BBC MICRO CASSETTE ELITE GAME LOADER SOURCE
\
\ BBC Micro cassette Elite was written by Ian Bell and David Braben and is
\ copyright Acornsoft 1984
\
\ The code in this file is identical to the source discs released on Ian Bell's
\ personal website at http://www.elitehomepage.org/ (it's just been reformatted
\ to be more readable)
\
\ The commentary is copyright Mark Moxon, and any misunderstandings or mistakes
\ in the documentation are entirely my fault
\
\ The terminology and notations used in this commentary are explained at
\ https://elite.bbcelite.com/terminology
\
\ The deep dive articles referred to in this commentary can be found at
\ https://elite.bbcelite.com/deep_dives
\
\ ------------------------------------------------------------------------------
\
\ This source file contains the game loader for BBC Micro cassette Elite.
\
\ ------------------------------------------------------------------------------
\
\ This source file produces the following binary file:
\
\   * ELITE.unprot.bin
\
\ after reading in the following files:
\
\   * P.A-SOFT.bin
\   * P.(C)ASFT.bin
\   * DIALS.bin
\   * P.ELITE.bin
\   * PYTHON.bin
\   * WORDS9.bin
\
\ ******************************************************************************

 INCLUDE "1-source-files/main-sources/elite-build-options.asm"

 _SOURCE_DISC           = (_VARIANT = 1)
 _TEXT_SOURCES          = (_VARIANT = 2)
 _STH_CASSETTE          = (_VARIANT = 3)

 GUARD &6000            \ Guard against assembling over screen memory

\ ******************************************************************************
\
\ Configuration variables
\
\ ******************************************************************************

 DISC = _DISC           \ Set to TRUE to load the code above DFS and relocate
                        \ down, so we can load the cassette version from disc,
                        \ or set to FALSE to load the code as if it were from a
                        \ cassette

 PROT = _PROT           \ Set to TRUE to enable the tape protection code, or set
                        \ to FALSE to disable the code (for TRUE, the file must
                        \ be saved to tape with the block data corrupted, so you
                        \ probably want to leave this as FALSE)

IF DISC

 CODE% = &1100          \ CODE% is set to the assembly address of the loader
                        \ code file that we assemble in this file ("ELITE"),
                        \ which is at the lowest DFS page value of &1100 for the
                        \ version that loads from disc

 LOAD% = &1100          \ LOAD% is the load address of the main game code file
                        \ ("ELTcode" for loading from disc, "ELITEcode" for
                        \ loading from tape)

 L% = &1128             \ L% points to the start of the actual game code from
                        \ elite-source.asm, after the &28 bytes of header code
                        \ that are inserted by elite-bcfs.asm

ELSE

 CODE% = &0E00          \ CODE% is set to the assembly address of the loader
                        \ code file that we assemble in this file ("ELITE"),
                        \ which is at the standard &0E00 address for the version
                        \ that loads from cassette

 LOAD% = &0F1F          \ LOAD% is the load address of the main game code file
                        \ ("ELTcode" for loading from disc, "ELITEcode" for
                        \ loading from tape)

 L% = &0F47             \ L% points to the start of the actual game code from
                        \ elite-source.asm, after the &28 bytes of header code
                        \ that are inserted by elite-bcfs.asm

ENDIF

 LEN1 = 15              \ Size of the BEGIN% routine that gets pushed onto the
                        \ stack and executed there

 LEN2 = 18              \ Size of the MVDL routine that gets pushed onto the
                        \ stack and executed there

 LEN = LEN1 + LEN2      \ Total number of bytes that get pushed on the stack for
                        \ execution there (33)

 VSCAN = 57-1           \ Defines the split position in the split-screen mode

 LE% = &0B00            \ LE% is the address to which the code from UU% onwards
                        \ is copied in part 3. It contains:
                        \
                        \   * ENTRY2, the entry point for the second block of
                        \     loader code
                        \
                        \   * IRQ1, the interrupt routine for the split-screen
                        \     mode
                        \
                        \   * BLOCK, which by this point has already been put
                        \     on the stack by this point
                        \
                        \   * The variables used by the above

 NETV = &0224           \ The NETV vector that we intercept as part of the copy
                        \ protection

 IRQ1V = &0204          \ The IRQ1V vector that we intercept to implement the
                        \ split-screen mode

 OSPRNT = &0234         \ The address for the OSPRNT vector

 C% = &0F40             \ C% is set to the location that the main game code gets
                        \ moved to after it is loaded

 S% = C%                \ S% points to the entry point for the main game code

IF _SOURCE_DISC

 D% = &563A             \ D% is set to the address of the byte after the end of
                        \ the code, i.e. the byte after checksum0 at XX21

ELIF _TEXT_SOURCES

 D% = &5638             \ D% is set to the address of the byte after the end of
                        \ the code, i.e. the byte after checksum0 at XX21

ELIF _STH_CASSETTE

 D% = &563A             \ D% is set to the address of the byte after the end of
                        \ the code, i.e. the byte after checksum0 at XX21

ENDIF

 LC% = &6000 - C%       \ LC% is set to the maximum size of the main game code
                        \ (as the code starts at C% and screen memory starts
                        \ at &6000)

 N% = 67                \ N% is set to the number of bytes in the VDU table, so
                        \ we can loop through them in part 2 below

 SVN = &7FFD            \ SVN is where we store the "saving in progress" flag,
                        \ and it matches the location in elite-source.asm

 VEC = &7FFE            \ VEC is where we store the original value of the IRQ1
                        \ vector, and it matches the value in elite-source.asm

 VIA = &FE00            \ Memory-mapped space for accessing internal hardware,
                        \ such as the video ULA, 6845 CRTC and 6522 VIAs (also
                        \ known as SHEILA)

 OSWRCH = &FFEE         \ The address for the OSWRCH routine

 OSBYTE = &FFF4         \ The address for the OSBYTE routine

 OSWORD = &FFF1         \ The address for the OSWORD routine

\ ******************************************************************************
\
\       Name: ZP
\       Type: Workspace
\    Address: &0004 to &0005 and &0070 to &0086
\   Category: Workspaces
\    Summary: Important variables used by the loader
\
\ ******************************************************************************

 ORG &0004              \ Set the assembly address to &0004

.TRTB%

 SKIP 2                 \ Contains the address of the keyboard translation
                        \ table, which is used to translate internal key
                        \ numbers to ASCII

 ORG &0070              \ Set the assembly address to &0070

.ZP

 SKIP 2                 \ Stores addresses used for moving content around

.P

 SKIP 1                 \ Temporary storage, used in a number of places

.Q

 SKIP 1                 \ Temporary storage, used in a number of places

.YY

 SKIP 1                 \ Temporary storage, used in a number of places

.T

 SKIP 1                 \ Temporary storage, used in a number of places

.SC

 SKIP 1                 \ Screen address (low byte)
                        \
                        \ Elite draws on-screen by poking bytes directly into
                        \ screen memory, and SC(1 0) is typically set to the
                        \ address of the character block containing the pixel
                        \ we want to draw

.SCH

 SKIP 1                 \ Screen address (high byte)

.BLPTR

 SKIP 2                 \ Gets set to &03CA as part of the obfuscation code

.V219

 SKIP 2                 \ Gets set to &0218 as part of the obfuscation code

 SKIP 4                 \ These bytes appear to be unused

.K3

 SKIP 1                 \ Temporary storage, used in a number of places

.BLCNT

 SKIP 2                 \ Stores the tape loader block count as part of the copy
                        \ protection code in IRQ1

.BLN

 SKIP 2                 \ Gets set to &03C6 as part of the obfuscation code

.EXCN

 SKIP 2                 \ Gets set to &03C2 as part of the obfuscation code

\ ******************************************************************************
\
\ ELITE LOADER
\
\ ******************************************************************************

 ORG CODE%              \ Set the assembly address to CODE%

\ ******************************************************************************
\
\       Name: Elite loader (Part 1 of 6)
\       Type: Subroutine
\   Category: Loader
\    Summary: Include binaries for recursive tokens, Python blueprint and images
\
\ ------------------------------------------------------------------------------
\
\ The loader bundles a number of binary files in with the loader code, and moves
\ them to their correct memory locations in part 3 below.
\
\ There are two files containing code:
\
\   * WORDS9.bin contains the recursive token table, which is moved to &0400
\     before the main game is loaded
\
\   * PYTHON.bin contains the Python ship blueprint, which gets moved to &7F00
\     before the main game is loaded
\
\ and four files containing images, which are all moved into screen memory by
\ the loader:
\
\   * P.A-SOFT.bin contains the "ACORNSOFT" title across the top of the loading
\     screen, which gets moved to screen address &6100, on the second character
\     row of the monochrome mode 4 screen
\
\   * P.ELITE.bin contains the "ELITE" title across the top of the loading
\     screen, which gets moved to screen address &6300, on the fourth character
\     row of the monochrome mode 4 screen
\
\   * P.(C)ASFT.bin contains the "(C) Acornsoft 1984" title across the bottom
\     of the loading screen, which gets moved to screen address &7600, the
\     penultimate character row of the monochrome mode 4 screen, just above the
\     dashboard
\
\   * P.DIALS.bin contains the dashboard, which gets moved to screen address
\     &7800, which is the starting point of the four-colour mode 5 portion at
\     the bottom of the split screen
\
\ The routine ends with a jump to the start of the loader code at ENTRY.
\
\ ******************************************************************************

 PRINT "WORDS9 = ", ~P%
 INCBIN "3-assembled-output/WORDS9.bin"

 ALIGN 256

 PRINT "P.DIALS = ", ~P%
 INCBIN "1-source-files/images/P.DIALS.bin"

 PRINT "PYTHON = ", ~P%
 INCBIN "3-assembled-output/PYTHON.bin"

 PRINT "P.ELITE = ", ~P%
 INCBIN "1-source-files/images/P.ELITE.bin"

 PRINT "P.A-SOFT = ", ~P%
 INCBIN "1-source-files/images/P.A-SOFT.bin"

 PRINT "P.(C)ASFT = ", ~P%
 INCBIN "1-source-files/images/P.(C)ASFT.bin"

.run

 JMP ENTRY              \ Jump to ENTRY to start the loading process

\ ******************************************************************************
\
\       Name: B%
\       Type: Variable
\   Category: Drawing the screen
\    Summary: VDU commands for setting the square mode 4 screen
\  Deep dive: The split-screen mode in BBC Micro Elite
\             Drawing monochrome pixels on the BBC Micro
\
\ ------------------------------------------------------------------------------
\
\ This block contains the bytes that get written by OSWRCH to set up the screen
\ mode (this is equivalent to using the VDU statement in BASIC).
\
\ It defines the whole screen using a square, monochrome mode 4 configuration;
\ the mode 5 part for the dashboard is implemented in the IRQ1 routine.
\
\ The top part of Elite's screen mode is based on mode 4 but with the following
\ differences:
\
\   * 32 columns, 31 rows (256 x 248 pixels) rather than 40, 32
\
\   * The horizontal sync position is at character 45 rather than 49, which
\     pushes the screen to the right (which centres it as it's not as wide as
\     the normal screen modes)
\
\   * Screen memory goes from &6000 to &7EFF, which leaves another whole page
\     for code (i.e. 256 bytes) after the end of the screen. This is where the
\     Python ship blueprint slots in
\
\   * The text window is 1 row high and 13 columns wide, and is at (2, 16)
\
\   * The cursor is disabled
\
\ This almost-square mode 4 variant makes life a lot easier when drawing to the
\ screen, as there are 256 pixels on each row (or, to put it in screen memory
\ terms, there's one page of memory per row of pixels).
\
\ There is also an interrupt-driven routine that switches the bytes-per-pixel
\ setting from that of mode 4 to that of mode 5, when the raster reaches the
\ split between the space view and the dashboard.
\
\ ******************************************************************************

.B%

 EQUB 22, 4             \ Switch to screen mode 4

 EQUB 28                \ Define a text window as follows:
 EQUB 2, 17, 15, 16     \
                        \   * Left = 2
                        \   * Right = 15
                        \   * Top = 16
                        \   * Bottom = 17
                        \
                        \ i.e. 1 row high, 13 columns wide at (2, 16)

 EQUB 23, 0, 6, 31      \ Set 6845 register R6 = 31
 EQUB 0, 0, 0           \
 EQUB 0, 0, 0           \ This is the "vertical displayed" register, and sets
                        \ the number of displayed character rows to 31. For
                        \ comparison, this value is 32 for standard modes 4 and
                        \ 5, but we claw back the last row for storing code just
                        \ above the end of screen memory

 EQUB 23, 0, 12, &0C    \ Set 6845 register R12 = &0C and R13 = &00
 EQUB 0, 0, 0           \
 EQUB 0, 0, 0           \ This sets 6845 registers (R12 R13) = &0C00 to point
 EQUB 23, 0, 13, &00    \ to the start of screen memory in terms of character
 EQUB 0, 0, 0           \ rows. There are 8 pixel lines in each character row,
 EQUB 0, 0, 0           \ so to get the actual address of the start of screen
                        \ memory, we multiply by 8:
                        \
                        \   &0C00 * 8 = &6000
                        \
                        \ So this sets the start of screen memory to &6000

 EQUB 23, 0, 1, 32      \ Set 6845 register R1 = 32
 EQUB 0, 0, 0           \
 EQUB 0, 0, 0           \ This is the "horizontal displayed" register, which
                        \ defines the number of character blocks per horizontal
                        \ character row. For comparison, this value is 40 for
                        \ modes 4 and 5, but our custom screen is not as wide at
                        \ only 32 character blocks across

 EQUB 23, 0, 2, 45      \ Set 6845 register R2 = 45
 EQUB 0, 0, 0           \
 EQUB 0, 0, 0           \ This is the "horizontal sync position" register, which
                        \ defines the position of the horizontal sync pulse on
                        \ the horizontal line in terms of character widths from
                        \ the left-hand side of the screen. For comparison this
                        \ is 49 for modes 4 and 5, but needs to be adjusted for
                        \ our custom screen's width

 EQUB 23, 0, 10, 32     \ Set 6845 register R10 = %00100000 = 32
 EQUB 0, 0, 0           \
 EQUB 0, 0, 0           \ This is the "cursor start" register, and bits 5 and 6
                        \ define the "cursor display mode", as follows:
                        \
                        \   * %00 = steady, non-blinking cursor
                        \
                        \   * %01 = do not display a cursor
                        \
                        \   * %10 = fast blinking cursor (blink at 1/16 of the
                        \           field rate)
                        \
                        \   * %11 = slow blinking cursor (blink at 1/32 of the
                        \           field rate)
                        \
                        \ We can therefore turn off the cursor completely by
                        \ setting cursor display mode %01, with bit 6 of R10
                        \ clear and bit 5 of R10 set

\ ******************************************************************************
\
\       Name: E%
\       Type: Variable
\   Category: Sound
\    Summary: Sound envelope definitions
\
\ ------------------------------------------------------------------------------
\
\ This table contains the sound envelope data, which is passed to OSWORD by the
\ FNE macro to create the four sound envelopes used in-game. Refer to chapter 30
\ of the "BBC Microcomputer User Guide" by John Coll for details of sound
\ envelopes and what all the parameters mean.
\
\ The envelopes are as follows:
\
\   * Envelope 1 is the sound of our own laser firing
\
\   * Envelope 2 is the sound of lasers hitting us, or hyperspace
\
\   * Envelope 3 is the first sound in the two-part sound of us dying, or the
\     second sound in the two-part sound of us hitting or killing an enemy ship
\
\   * Envelope 4 is the sound of E.C.M. firing
\
\ ******************************************************************************

.E%

 EQUB 1, 1, 0, 111, -8, 4, 1, 8, 8, -2, 0, -1, 112, 44
 EQUB 2, 1, 14, -18, -1, 44, 32, 50, 6, 1, 0, -2, 120, 126
 EQUB 3, 1, 1, -1, -3, 17, 32, 128, 1, 0, 0, -1, 1, 1
 EQUB 4, 1, 4, -8, 44, 4, 6, 8, 22, 0, 0, -127, 126, 0

\ ******************************************************************************
\
\       Name: swine
\       Type: Subroutine
\   Category: Copy protection
\    Summary: Resets the machine if the copy protection detects a problem
\
\ ******************************************************************************

.swine

 LDA #%01111111         \ Set 6522 System VIA interrupt enable register IER
 STA &FE4E              \ (SHEILA &4E) bits 0-6 (i.e. disable all hardware
                        \ interrupts from the System VIA)

 JMP (&FFFC)            \ Jump to the address in &FFFC to reset the machine

\ ******************************************************************************
\
\       Name: OSB
\       Type: Subroutine
\   Category: Utility routines
\    Summary: A convenience routine for calling OSBYTE with Y = 0
\
\ ******************************************************************************

.OSB

 LDY #0                 \ Call OSBYTE with Y = 0, returning from the subroutine
 JMP OSBYTE             \ using a tail call (so we can call OSB to call OSBYTE
                        \ for when we know we want Y set to 0)

\ ******************************************************************************
\
\       Name: Authors' names
\       Type: Variable
\   Category: Copy protection
\    Summary: The authors' names, buried in the code
\
\ ------------------------------------------------------------------------------
\
\ Contains the authors' names, plus an unused OS command string that would
\ *RUN the main game code, which isn't what actually happens (so presumably
\ this is to throw the crackers off the scent).
\
\ ******************************************************************************

 EQUS "R.ELITEcode"     \ This is short for "*RUN ELITEcode"
 EQUB 13

 EQUS "By D.Braben/I.Bell"
 EQUB 13

 EQUB &B0

\ ******************************************************************************
\
\       Name: oscliv
\       Type: Variable
\   Category: Utility routines
\    Summary: Contains the address of OSCLIV, for executing OS commands
\
\ ******************************************************************************

.oscliv

 EQUW &FFF7             \ Address of OSCLIV, for executing OS commands
                        \ (specifically the *LOAD that loads the main game code)

\ ******************************************************************************
\
\       Name: David9
\       Type: Variable
\   Category: Copy protection
\    Summary: Address used as part of the stack-based decryption loop
\
\ ------------------------------------------------------------------------------
\
\ This address is used in the decryption loop starting at David2 in part 4, and
\ is used to jump back into the loop at David5.
\
\ ******************************************************************************

.David9

 EQUW David5            \ The address of David5

 CLD                    \ This instruction is not used

\ ******************************************************************************
\
\       Name: David23
\       Type: Variable
\   Category: Copy protection
\    Summary: Address pointer to the start of the 6502 stack
\
\ ------------------------------------------------------------------------------
\
\ This two-byte address points to the start of the 6502 stack, which descends
\ from the end of page 2, less LEN bytes, which comes out as &01DF. So when we
\ push 33 bytes onto the stack (LEN being 33), this address will point to the
\ start of those bytes, which means we can push executable code onto the stack
\ and run it by calling this address with a JMP (David23) instruction. Sneaky
\ stuff!
\
\ ******************************************************************************

.David23

 EQUW (512-LEN)         \ The address of LEN bytes before the start of the stack

\ ******************************************************************************
\
\       Name: doPROT1
\       Type: Subroutine
\   Category: Copy protection
\    Summary: Routine to self-modify the loader code
\
\ ------------------------------------------------------------------------------
\
\ This routine modifies various bits of code in-place as part of the copy
\ protection mechanism. It is called with A = &48 and X = 255.
\
\ ******************************************************************************

.doPROT1

 LDY #&DB               \ Store &EFDB in TRTB%(1 0) to point to the keyboard
 STY TRTB%              \ translation table for OS 0.1 (which we will overwrite
 LDY #&EF               \ with a call to OSBYTE later)
 STY TRTB%+1

 LDY #2                 \ Set the high byte of V219(1 0) to 2
 STY V219+1

 STA PROT1-255,X        \ Poke &48 into PROT1, which changes the instruction
                        \ there to a PHA

 LDY #&18               \ Set the low byte of V219(1 0) to &18 (as X = 255), so
 STY V219+1,X           \ V219(1 0) now contains &0218

 RTS                    \ Return from the subroutine

\ ******************************************************************************
\
\       Name: MHCA
\       Type: Variable
\   Category: Copy protection
\    Summary: Used to set one of the vectors in the copy protection code
\
\ ------------------------------------------------------------------------------
\
\ This value is used to set the low byte of BLPTR(1 0), when it's set in PLL1
\ as part of the copy protection.
\
\ ******************************************************************************

.MHCA

 EQUB &CA               \ The low byte of BLPTR(1 0)

\ ******************************************************************************
\
\       Name: David7
\       Type: Subroutine
\   Category: Copy protection
\    Summary: Part of the multi-jump obfuscation code in PROT1
\
\ ------------------------------------------------------------------------------
\
\ This instruction is part of the multi-jump obfuscation in PROT1 (see part 2 of
\ the loader), which does the following jumps:
\
\   David8 -> FRED1 -> David7 -> Ian1 -> David3
\
\ ******************************************************************************

.David7

 BCC Ian1               \ This instruction is part of the multi-jump obfuscation
                        \ in PROT1

\ ******************************************************************************
\
\       Name: FNE
\       Type: Macro
\   Category: Sound
\    Summary: Macro definition for defining a sound envelope
\
\ ------------------------------------------------------------------------------
\
\ The following macro is used to define the four sound envelopes used in the
\ game. It uses OSWORD 8 to create an envelope using the 14 parameters in the
\ I%-th block of 14 bytes at location E%. This OSWORD call is the same as BBC
\ BASIC's ENVELOPE command.
\
\ See variable E% for more details of the envelopes themselves.
\
\ ******************************************************************************

MACRO FNE I%

 LDX #LO(E%+I%*14)      \ Set (Y X) to point to the I%-th set of envelope data
 LDY #HI(E%+I%*14)      \ in E%

 LDA #8                 \ Call OSWORD with A = 8 to set up sound envelope I%
 JSR OSWORD

ENDMACRO

\ ******************************************************************************
\
\       Name: Elite loader (Part 2 of 6)
\       Type: Subroutine
\   Category: Loader
\    Summary: Perform a number of OS calls, set up sound, push routines on stack
\
\ ------------------------------------------------------------------------------
\
\ This part of the loader does a number of calls to OS routines, sets up the
\ sound envelopes, pushes 33 bytes onto the stack that will be used later, and
\ sends us on a wild goose chase, just for kicks.
\
\ ------------------------------------------------------------------------------
\
\ Other entry points:
\
\   Ian1                Re-entry point following the wild goose chase
\                       obfuscation
\
\ ******************************************************************************

.ENTRY

 SEI                    \ Disable all interrupts

 CLD                    \ Clear the decimal flag, so we're not in decimal mode

IF NOT(DISC)

 LDA #0                 \ Call OSBYTE with A = 0 and X = 255 to fetch the
 LDX #255               \ operating system version into X
 JSR OSBYTE

 TXA                    \ If X = 0 then this is OS 1.00, so jump down to OS100
 BEQ OS100              \ to skip the following

 LDY &FFB6              \ Otherwise this is OS 1.20, so set Y to the contents of
                        \ &FFB6, which contains the length of the default vector
                        \ table

 LDA &FFB7              \ Set ZP(1 0) to the location stored in &FFB7-&FFB8,
 STA ZP                 \ which contains the address of the default vector table
 LDA &FFB8
 STA ZP+1

 DEY                    \ Decrement Y so we can use it as an index for setting
                        \ all the vectors to their default states

.ABCDEFG

 LDA (ZP),Y             \ Copy the Y-th byte from the default vector table into
 STA &0200,Y            \ the vector table in &0200

 DEY                    \ Decrement the loop counter

 BPL ABCDEFG            \ Loop back for the next vector until we have done them
                        \ all

.OS100

ENDIF

 LDA #%01111111         \ Set 6522 System VIA interrupt enable register IER
 STA &FE4E              \ (SHEILA &4E) bits 0-6 (i.e. disable all hardware
                        \ interrupts from the System VIA)

 STA &FE6E              \ Set 6522 User VIA interrupt enable register IER
                        \ (SHEILA &6E) bits 0-6 (i.e. disable all hardware
                        \ interrupts from the User VIA)

 LDA &FFFC              \ Fetch the low byte of the reset address in &FFFC,
                        \ which will reset the machine if called

 STA &0200              \ Set the low bytes of USERV, BRKV, IRQ2V and EVENTV
 STA &0202
 STA &0206
 STA &0220

 LDA &FFFD              \ Fetch the high byte of the reset address in &FFFD,
                        \ which will reset the machine if called

 STA &0201              \ Set the high bytes of USERV, BRKV, IRQ2V and EVENTV
 STA &0203
 STA &0207
 STA &0221

 LDX #&2F-2             \ We now step through all the vectors from &0204 to
                        \ &022F and OR their high bytes with &C0, so they all
                        \ point into the MOS ROM space (which is from &C000 and
                        \ upwards), so we set a counter in X to count through
                        \ them

.purge

 LDA &0202,X            \ Set the high byte of the vector in &0202+X so it
 ORA #&C0               \ points to the MOS ROM
 STA &0202,X

 DEX                    \ Increment the counter to point to the next high byte
 DEX

 BPL purge              \ Loop back until we have done all the vectors

 LDA #&60               \ Store an RTS instruction in location &0232
 STA &0232

 LDA #&2                \ Point the NETV vector to &0232, which we just filled
 STA NETV+1             \ with an RTS
 LDA #&32
 STA NETV

 LDA #&20               \ Set A to the op code for a JSR call with absolute
                        \ addressing

 EQUB &2C               \ Skip the next instruction by turning it into
                        \ &2C &D0 &66, or BIT &66D0, which does nothing apart
                        \ from affect the flags

.Ian1

 BNE David3             \ This instruction is skipped if we came from above,
                        \ otherwise this is part of the multi-jump obfuscation
                        \ in PROT1

 STA David2             \ Store &20 in location David2, which modifies the
                        \ instruction there (see David2 for details)

 LSR A                  \ Set A = 16

 LDX #3                 \ Set the high bytes of BLPTR(1 0), BLN(1 0) and
 STX BLPTR+1            \ EXCN(1 0) to &3. We will fill in the high bytes in
 STX BLN+1              \ the PLL1 routine, and will then use these values in
 STX EXCN+1             \ the IRQ1 handler

 DEX                    \ Set X = 2

 JSR OSBYTE             \ Call OSBYTE with A = 16 and X = 2 to set the ADC to
                        \ sample 2 channels from the joystick

 EQUB &2C               \ Skip the next instruction by turning it into
                        \ &2C &D0 &A1, or BIT &A1D0, which does nothing apart
                        \ from affect the flags

.FRED1

 BNE David7             \ This instruction is skipped if we came from above,
                        \ otherwise this is part of the multi-jump obfuscation
                        \ in PROT1

 LDX #255               \ Call doPROT1 to change an instruction in the PROT1
 LDA #&48               \ routine and set up another couple of variables
 JSR doPROT1

 LDA #144               \ Call OSBYTE with A = 144, X = 255 and Y = 0 to move
 JSR OSB                \ the screen down one line and turn screen interlace on

 LDA #247               \ Call OSBYTE with A = 247 and X = Y = 0 to disable the
 LDX #0                 \ BREAK intercept code by poking 0 into the first value
 JSR OSB

\LDA #129               \ These instructions are commented out in the original
\LDY #255               \ source, along with the comment "Damn 0.1", so
\LDX #1                 \ presumably MOS version 0.1 was a bit of a pain to
\JSR OSBYTE             \ support - which is probably why Elite doesn't bother
\                       \ and only supports 1.0 and 1.2
\TXA
\
\BPL OS01
\
\Damn 0.1

 LDA #190               \ Call OSBYTE with A = 190, X = 8 and Y = 0 to set the
 LDX #8                 \ ADC conversion type to 8 bits, for the joystick
 JSR OSB

 EQUB &2C               \ Skip the next instruction by turning it into
                        \ &2C &D0 &E1, or BIT &E1D0, which does nothing apart
                        \ from affect the flags

.David8

 BNE FRED1              \ This instruction is skipped if we came from above,
                        \ otherwise this is part of the multi-jump obfuscation
                        \ in PROT1

 LDA #143               \ Call OSBYTE 143 to issue a paged ROM service call of
 LDX #&C                \ type &C with argument &FF, which is the "NMI claim"
 LDY #&FF               \ service call that asks the current user of the NMI
 JSR OSBYTE             \ space to clear it out

 LDA #13                \ Set A = 13 for the next OSBYTE call

.abrk

 LDX #0                 \ Call OSBYTE with A = 13, X = 0 and Y = 0 to disable
 JSR OSB                \ the "output buffer empty" event

 LDA #225               \ Call OSBYTE with A = 225, X = 128 and Y = 0 to set
 LDX #128               \ the function keys to return ASCII codes for SHIFT-fn
 JSR OSB                \ keys (i.e. add 128)

 LDA #172               \ Call OSBYTE 172 to read the address of the MOS
 LDX #0                 \ keyboard translation table into (Y X)
 LDY #255
 JSR OSBYTE

 STX TRTB%              \ Store the address of the keyboard translation table in
 STY TRTB%+1            \ TRTB%(1 0)

 LDA #200               \ Call OSBYTE with A = 200, X = 3 and Y = 0 to disable
 LDX #3                 \ the ESCAPE key and clear memory if the BREAK key is
 JSR OSB                \ pressed

IF PROT AND NOT(DISC)

 CPX #3                 \ If the previous value of X from the call to OSBYTE 200
 BNE abrk+1             \ was not 3 (ESCAPE disabled, clear memory), jump to
                        \ abrk+1, which contains a BRK instruction which will
                        \ reset the computer (as we set BRKV to point to the
                        \ reset address above)

ENDIF

 LDA #13                \ Call OSBYTE with A = 13, X = 2 and Y = 0 to disable
 LDX #2                 \ the "character entering keyboard buffer" event
 JSR OSB

.OS01

 LDX #&FF               \ Set the stack pointer to &01FF, which is the standard
 TXS                    \ location for the 6502 stack, so this instruction
                        \ effectively resets the stack

 INX                    \ Set X = 0, to use as a counter in the following loop

.David3

 LDA BEGIN%,X           \ This routine pushes 33 bytes from BEGIN% onto the
                        \ stack, so fetch the X-th byte from BEGIN%

.PROT1

 INY                    \ This instruction gets changed to a PHA instruction by
                        \ the doPROT1 routine that's called above, so by the
                        \ time we get here, this instruction actually pushes the
                        \ X-th byte from BEGIN% onto the stack

 INX                    \ Increment the loop counter

 CPX #LEN               \ If X < #LEN (which is 33), loop back for the next one.
 BNE David8             \ This branch actually takes us on a wild goose chase
                        \ through the following locations, where each BNE is
                        \ prefaced by an EQUB &2C that disables the branch
                        \ instruction during the normal instruction flow:
                        \
                        \   David8 -> FRED1 -> David7 -> Ian1 -> David3
                        \
                        \ so in the end this just loops back to push the next
                        \ byte onto the stack, but in a really sneaky way

 LDA #LO(B%)            \ Set the low byte of ZP(1 0) to point to the VDU code
 STA ZP                 \ table at B%

 LDA #&C8               \ Poke &C8 into PROT1 to change the instruction that we
 STA PROT1              \ modified back to an INY instruction, rather than a PHA

 LDA #HI(B%)            \ Set the high byte of ZP(1 0) to point to the VDU code
 STA ZP+1               \ table at B%

 LDY #0                 \ We are now going to send the N% VDU bytes in the table
                        \ at B% to OSWRCH to set up the special mode 4 screen
                        \ that forms the basis for the split-screen mode

.LOOP

 LDA (ZP),Y             \ Pass the Y-th byte of the B% table to OSWRCH
 JSR OSWRCH

 INY                    \ Increment the loop counter

 CPY #N%                \ Loop back for the next byte until we have done them
 BNE LOOP               \ all (the number of bytes was set in N% above)

 LDA #1                 \ In doPROT1 above we set V219(1 0) = &0218, so this
 TAX                    \ code sets the contents of &0219 (the high byte of
 TAY                    \ BPUTV) to 1. We will see why this later, at the start
 STA (V219),Y           \ of part 4

 LDA #4                 \ Call OSBYTE with A = 4, X = 1 and Y = 0 to disable
 JSR OSB                \ cursor editing, so the cursor keys return ASCII values
                        \ and can therefore be used in-game

 LDA #9                 \ Call OSBYTE with A = 9, X = 0 and Y = 0 to disable
 LDX #0                 \ flashing colours
 JSR OSB

 LDA #&6C               \ Poke &6C into crunchit after EOR'ing it first (which
 EOR crunchit           \ has no effect as crunchit contains a BRK instruction
 STA crunchit           \ with opcode 0), to change crunchit to an indirect JMP

 FNE 0                  \ Set up sound envelopes 0-3 using the FNE macro
 FNE 1
 FNE 2
 FNE 3

\ ******************************************************************************
\
\       Name: Elite loader (Part 3 of 6)
\       Type: Subroutine
\   Category: Loader
\    Summary: Move and decrypt recursive tokens, Python blueprint and images
\
\ ------------------------------------------------------------------------------
\
\ Move and decrypt the following memory blocks:
\
\   * WORDS9: move 4 pages (1024 bytes) from CODE% to &0400
\
\   * P.ELITE: move 1 page (256 bytes) from CODE% + &0C00 to &6300
\
\   * P.A-SOFT: move 1 page (256 bytes) from CODE% + &0D00 to &6100
\
\   * P.(C)ASFT: move 1 page (256 bytes) from CODE% + &0E00 to &7600
\
\   * P.DIALS and PYTHON: move 8 pages (2048 bytes) from CODE% + &0400 to &7800
\
\   * Move 2 pages (512 bytes) from UU% to &0B00-&0CFF
\
\ and call the routine to draw Saturn between P.(C)ASFT and P.DIALS.
\
\ See part 1 above for more details on the above files and the locations that
\ they are moved to.
\
\ The code at UU% (see below) forms part of the loader code and is moved before
\ being run, so it's tucked away safely while the main game code is loaded and
\ decrypted.
\
\ ******************************************************************************

 LDX #4                 \ Set the following:
 STX P+1                \
 LDA #HI(CODE%)         \   P(1 0) = &0400
 STA ZP+1               \   ZP(1 0) = CODE%
 LDY #0                 \   (X Y) = &400 = 1024
 LDA #256-LEN1          \
 STA (V219-4,X)         \ In doPROT1 above we set V219(1 0) = &0218, so this
 STY ZP                 \ also sets the contents of &0218 (the low byte of
 STY P                  \ BPUTV) to 256 - LEN1, or &F1. We set the low byte to
                        \ 1 above, so BPUTV now contains &01F1, which we will
                        \ use at the start of part 4

 JSR crunchit           \ Call crunchit, which has now been modified to call the
                        \ MVDL routine on the stack, to move and decrypt &400
                        \ bytes from CODE% to &0400. We loaded WORDS9.bin to
                        \ CODE% in part 1, so this moves WORDS9

 LDX #1                 \ Set the following:
 LDA #(HI(CODE%)+&C)    \
 STA ZP+1               \   P(1 0) = &6300
 LDA #&63               \   ZP(1 0) = CODE% + &C
 STA P+1                \   (X Y) = &100 = 256
 LDY #0

 JSR crunchit           \ Call crunchit to move and decrypt &100 bytes from
                        \ CODE% + &C to &6300, so this moves P.ELITE

 LDX #1                 \ Set the following:
 LDA #(HI(CODE%)+&D)    \
 STA ZP+1               \   P(1 0) = &6100
 LDA #&61               \   ZP(1 0) = CODE% + &D
 STA P+1                \   (X Y) = &100 = 256
 LDY #0

 JSR crunchit           \ Call crunchit to move and decrypt &100 bytes from
                        \ CODE% + &D to &6100, so this moves P.A-SOFT

 LDX #1                 \ Set the following:
 LDA #(HI(CODE%)+&E)    \
 STA ZP+1               \   P(1 0) = &7600
 LDA #&76               \   ZP(1 0) = CODE% + &E
 STA P+1                \   (X Y) = &100 = 256
 LDY #0

 JSR crunchit           \ Call crunchit to move and decrypt &100 bytes from
                        \ CODE% + &E to &7600, so this moves P.(C)ASFT

 JSR PLL1               \ Call PLL1 to draw Saturn

 LDX #8                 \ Set the following:
 LDA #(HI(CODE%)+4)     \
 STA ZP+1               \   P(1 0) = &7800
 LDA #&78               \   ZP(1 0) = CODE% + &4
 STA P+1                \   (X Y) = &800 = 2048
 LDY #0                 \
 STY ZP                 \ Also set BLCNT = 0
 STY BLCNT
 STY P

 JSR crunchit           \ Call crunchit to move and decrypt &800 bytes from
                        \ CODE% + &4 to &7800, so this moves P.DIALS and PYTHON

IF DISC

 LDX #2                 \ Set the following:
 LDA #HI(UU%)           \
 STA ZP+1               \   P(1 0) = LE%
 LDA #LO(UU%)           \   ZP(1 0) = UU%
 STA ZP                 \   (X Y) = &200 = 512 (as we are building for disc)
 LDA #HI(LE%)
 STA P+1
 LDY #0
 STY P

ELSE

 LDX #3                 \ Set the following:
 LDA #HI(UU%)           \
 STA ZP+1               \   P(1 0) = LE%
 LDA #LO(UU%)           \   ZP(1 0) = UU%
 STA ZP                 \   (X Y) = &300 = 768 (as we are building for tape)
 LDA #HI(LE%)
 STA P+1
 LDY #0
 STY P

ENDIF

 JSR crunchit           \ Call crunchit to move and decrypt either &200 or &300
                        \ bytes from UU% to LE%, leaving X = 0

\ ******************************************************************************
\
\       Name: Elite loader (Part 4 of 6)
\       Type: Subroutine
\   Category: Loader
\    Summary: Copy more code onto stack, decrypt TUT block, set up IRQ1 handler
\
\ ------------------------------------------------------------------------------
\
\ This part copies more code onto the stack (from BLOCK to ENDBLOCK), decrypts
\ the code from TUT onwards, and sets up the IRQ1 handler for the split-screen
\ mode.
\
\ ******************************************************************************

 STY David3-2           \ Y was set to 0 above, so this modifies the OS01
                        \ routine above by changing the TXS instruction to BRK,
                        \ so calls to OS01 will now do this:
                        \
                        \   LDX #&FF
                        \   BRK
                        \
                        \ This is presumably just to confuse any cracker, as we
                        \ don't call OS01 again

                        \ We now enter a loop that starts with the counter in Y
                        \ (initially set to 0). It calls JSR &01F1 on the stack,
                        \ which pushes the Y-th byte of BLOCK on the stack
                        \ before encrypting the Y-th byte of BLOCK in-place. It
                        \ then jumps back to David5 below, where we increment Y
                        \ until it reaches a value of ENDBLOCK - BLOCK. So this
                        \ loop basically decrypts the code from TUT onwards, and
                        \ at the same time it pushes the code between BLOCK and
                        \ ENDBLOCK onto the stack, so it's there ready to be run
                        \ (at address &0163)

.David2

 EQUB &AC               \ This byte was changed to &20 by part 2, so by the time
 EQUW &FFD4             \ we get here, these three bytes together become JSR
                        \ &FFD4, or JSR OSBPUT. Amongst all the code above,
                        \ we've also managed to set BPUTV to &01F1, and as BPUTV
                        \ is the vector that OSBPUT goes through, these three
                        \ bytes are actually doing JSR &01F1
                        \
                        \ That address is in the stack, and is the address of
                        \ the BEGIN% routine, which we pushed onto the stack in
                        \ the modified PROT1 routine. That routine doesn't
                        \ return with an RTS, but instead it removes the return
                        \ address from the stack and jumps to David5 below after
                        \ pushing the Y-th byte of BLOCK onto the stack and
                        \ EOR'ing the Y-th byte of TUT with the Y-th byte of
                        \ BLOCK
                        \
                        \ This obfuscation probably kept the crackers busy for a
                        \ while - it's difficult enough to work out when you
                        \ have the source code in front of you!

.LBLa

                        \ If, for some reason, the above JSR doesn't call the
                        \ routine on the stack and returns normally, which might
                        \ happen if crackers manage to unpick the BPUTV
                        \ redirection, then we end up here. We now obfuscate the
                        \ first 255 bytes of the location where the main game
                        \ gets loaded (which is set in C%), just to make things
                        \ hard, and then we reset the machine... all in a
                        \ completely twisted manner, of course

 LDA C%,X               \ Obfuscate the X-th byte of C% by EOR'ing with &A5
 EOR #&A5
 STA C%,X

 DEX                    \ Decrement the loop counter

 BNE LBLa               \ Loop back until X wraps around, after EOR'ing a whole
                        \ page

 JMP (C%+&CF)           \ C%+&CF is &100F, which in the main game code contains
                        \ an LDA KY17 instruction (it's in the main loader in
                        \ the MA76 section). This has opcode &A5 &4E, and the
                        \ EOR above changes the first of these to &00, so this
                        \ jump goes to a BRK instruction, which in turn goes to
                        \ BRKV, which in turn resets the computer (as we set
                        \ BRKV to point to the reset address in part 2)

.swine2

 JMP swine              \ Jump to swine to reset the machine

 EQUW &4CFF             \ This data doesn't appear to be used

.crunchit

 BRK                    \ This instruction gets changed to an indirect JMP at
 EQUW David23           \ the end of part 2, so this does JMP (David23). David23
                        \ contains &01DF, so these bytes are actually doing JMP
                        \ &01DF. That address is in the stack, and is the
                        \ address of the MVDL routine, which we pushed onto the
                        \ stack in the modified PROT1 routine... so this
                        \ actually does the following:
                        \
                        \   JMP MVDL
                        \
                        \ meaning that this instruction:
                        \
                        \   JSR crunchit
                        \
                        \ actually does this, because it's a tail call:
                        \
                        \   JSR MVDL
                        \
                        \ It's yet another impressive bit of obfuscation and
                        \ misdirection

.RAND

 EQUD &6C785349         \ The random number seed used for drawing Saturn

.David5

 INY                    \ Increment the loop counter

 CPY #(ENDBLOCK-BLOCK)  \ Loop back to copy the next byte until we have copied
 BNE David2             \ all the bytes between BLOCK and ENDBLOCK

 SEI                    \ Disable interrupts while we set up our interrupt
                        \ handler to support the split-screen mode

 LDA #%11000010         \ Clear 6522 System VIA interrupt enable register IER
 STA VIA+&4E            \ (SHEILA &4E) bits 1 and 7 (i.e. enable CA1 and TIMER1
                        \ interrupts from the System VIA, which enable vertical
                        \ sync and the 1 MHz timer, which we need enabled for
                        \ the split-screen interrupt code to work)

 LDA #%01111111         \ Set 6522 User VIA interrupt enable register IER
 STA &FE6E              \ (SHEILA &6E) bits 0-7 (i.e. disable all hardware
                        \ interrupts from the User VIA)

 LDA IRQ1V              \ Store the low byte of the current IRQ1V vector in VEC
 STA VEC

 LDA IRQ1V+1            \ If the current high byte of the IRQ1V vector is less
 BPL swine2             \ than &80, which means it points to user RAM rather
                        \ the MOS ROM, then something is probably afoot, so jump
                        \ to swine2 to reset the machine

 STA VEC+1              \ Otherwise all is well, so store the high byte of the
                        \ current IRQ1V vector in VEC+1, so VEC(1 0) now
                        \ contains the original address of the IRQ1 handler

 LDA #HI(IRQ1)          \ Set the IRQ1V vector to IRQ1, so IRQ1 is now the
 STA IRQ1V+1            \ interrupt handler
 LDA #LO(IRQ1)
 STA IRQ1V

 LDA #VSCAN             \ Set 6522 System VIA T1C-L timer 1 high-order counter
 STA VIA+&45            \ (SHEILA &45) to VSCAN (56) to start the T1 counter
                        \ counting down from 14080 at a rate of 1 MHz (this is
                        \ a different value to the main game code)

 CLI                    \ Re-enable interrupts

IF DISC

 LDA #%10000001         \ Clear 6522 System VIA interrupt enable register IER
 STA &FE4E              \ (SHEILA &4E) bit 1 (i.e. enable the CA2 interrupt,
                        \ which comes from the keyboard)

 LDY #20                \ Set Y = 20 for the following OSBYTE call

IF _REMOVE_CHECKSUMS

 NOP                    \ If we have disabled checksums, skip the OSBYTE call
 NOP
 NOP

ELSE

 JSR OSBYTE             \ A was set to 129 above, so this calls OSBYTE with
                        \ A = 129 and Y = 20, as well as a value of X = 0,
                        \ which was set by the call to crunchit at the end of
                        \ part 3
                        \
                        \ This reads the keyboard with a time limit of (Y X)
                        \ centiseconds, or 20 * 256 = 5120 centiseconds, or
                        \ 51.2 seconds

ENDIF

 LDA #%00000001         \ Set 6522 System VIA interrupt enable register IER
 STA &FE4E              \ (SHEILA &4E) bit 1 (i.e. disable the CA2 interrupt,
                        \ which comes from the keyboard)

ENDIF

 RTS                    \ This RTS actually does a jump to ENTRY2, to the next
                        \ step of the loader in part 5. See the documentation
                        \ for the stack routine at BEGIN% for more details

\ ******************************************************************************
\
\       Name: PLL1 (Part 1 of 3)
\       Type: Subroutine
\   Category: Drawing planets
\    Summary: Draw Saturn on the loading screen (draw the planet)
\  Deep dive: Drawing Saturn on the loading screen
\
\ ******************************************************************************

.PLL1

                        \ The following loop iterates CNT(1 0) times, i.e. &500
                        \ or 1280 times, and draws the planet part of the
                        \ loading screen's Saturn

 LDA VIA+&44            \ Read the 6522 System VIA T1C-L timer 1 low-order
 STA RAND+1             \ counter (SHEILA &44), which decrements one million
                        \ times a second and will therefore be pretty random,
                        \ and store it in location RAND+1, which is among the
                        \ main game code's random seeds in RAND (so this seeds
                        \ the random number generator)

 JSR DORND              \ Set A and X to signed random numbers between -128 and
                        \ 127, so let's say A = r1

 JSR SQUA2              \ Set (A P) = A * A
                        \           = r1^2

 STA ZP+1               \ Set ZP(1 0) = (A P)
 LDA P                  \             = r1^2
 STA ZP

 JSR DORND              \ Set A and X to signed random numbers between -128 and
                        \ 127, so let's say A = r2

 STA YY                 \ Set YY = A
                        \        = r2

 JSR SQUA2              \ Set (A P) = A * A
                        \           = r2^2

 TAX                    \ Set (X P) = (A P)
                        \           = r2^2

 LDA P                  \ Set (A ZP) = (X P) + ZP(1 0)
 ADC ZP                 \
 STA ZP                 \ first adding the low bytes

 TXA                    \ And then adding the high bytes
 ADC ZP+1

 BCS PLC1               \ If the addition overflowed, jump down to PLC1 to skip
                        \ to the next pixel

 STA ZP+1               \ Set ZP(1 0) = (A ZP)
                        \             = r1^2 + r2^2

 LDA #1                 \ Set ZP(1 0) = &4001 - ZP(1 0) - (1 - C)
 SBC ZP                 \             = 128^2 - ZP(1 0)
 STA ZP                 \
                        \ (as the C flag is clear), first subtracting the low
                        \ bytes

 LDA #&40               \ And then subtracting the high bytes
 SBC ZP+1
 STA ZP+1

 BCC PLC1               \ If the subtraction underflowed, jump down to PLC1 to
                        \ skip to the next pixel

                        \ If we get here, then both calculations fitted into
                        \ 16 bits, and we have:
                        \
                        \   ZP(1 0) = 128^2 - (r1^2 + r2^2)
                        \
                        \ where ZP(1 0) >= 0

 JSR ROOT               \ Set ZP = SQRT(ZP(1 0))

 LDA ZP                 \ Set X = ZP >> 1
 LSR A                  \       = SQRT(128^2 - (a^2 + b^2)) / 2
 TAX

 LDA YY                 \ Set A = YY
                        \       = r2

 CMP #128               \ If YY >= 128, set the C flag (so the C flag is now set
                        \ to bit 7 of A)

 ROR A                  \ Rotate A and set the sign bit to the C flag, so A is
                        \ halved while retaining its sign
                        \
                        \ A is still a signed number from -128 to 127

 JSR PIX                \ Draw a pixel at screen coordinate (X + 128, A + 128),
                        \ where:
                        \
                        \   X = ZP / 2
                        \   A = r2 / 2
                        \   ZP = SQRT(128^2 - (r1^2 + r2^2))
                        \
                        \ So this is the same as plotting at (x, y) where:
                        \
                        \   r1 = random number from -128 to 127
                        \   r2 = random number from -128 to 127
                        \
                        \   (r1^2 + r2^2) < 128^2
                        \
                        \   x = (SQRT(128^2 - (r1^2 + r2^2)) / 2) + 128
                        \   y = (r2 / 2) + 128
                        \
                        \ which is what we want

.PLC1

 DEC CNT                \ Decrement the counter in CNT (the low byte)

 BNE PLL1               \ Loop back to PLL1 until CNT = 0

 DEC CNT+1              \ Decrement the counter in CNT+1 (the high byte)

 BNE PLL1               \ Loop back to PLL1 until CNT+1 = 0

 LDX #&C2               \ Set the low byte of EXCN(1 0) to &C2, so we now have
 STX EXCN               \ EXCN(1 0) = &03C2, which we will use in the IRQ1
                        \ handler (this has nothing to do with drawing Saturn,
                        \ it's all part of the copy protection)

\ ******************************************************************************
\
\       Name: PLL1 (Part 2 of 3)
\       Type: Subroutine
\   Category: Drawing planets
\    Summary: Draw Saturn on the loading screen (draw the stars)
\  Deep dive: Drawing Saturn on the loading screen
\
\ ******************************************************************************

                        \ The following loop iterates CNT2(1 0) times, i.e. &1DD
                        \ or 477 times, and draws the background stars on the
                        \ loading screen

.PLL2

 JSR DORND              \ Set A and X to signed random numbers between -128 and
                        \ 127, so let's say A = r3

 TAX                    \ Set X = A
                        \       = r3

 JSR SQUA2              \ Set (A P) = A * A
                        \           = r3^2

 STA ZP+1               \ Set ZP+1 = A
                        \          = r3^2 / 256

 JSR DORND              \ Set A and X to signed random numbers between -128 and
                        \ 127, so let's say A = r4

 STA YY                 \ Set YY = r4

 JSR SQUA2              \ Set (A P) = A * A
                        \           = r4^2

 ADC ZP+1               \ Set A = A + r3^2 / 256
                        \       = r4^2 / 256 + r3^2 / 256
                        \       = (r3^2 + r4^2) / 256

 CMP #&11               \ If A < 17, jump down to PLC2 to skip to the next pixel
 BCC PLC2

 LDA YY                 \ Set A = r4

 JSR PIX                \ Draw a pixel at screen coordinate (X + 128, A + 128),
                        \ where:
                        \
                        \   X = r3
                        \   A = r4
                        \
                        \ So this is the same as plotting at (x, y) where:
                        \
                        \   r3 = random number from -128 to 127
                        \   r4 = random number from -128 to 127
                        \
                        \   (r3^2 + r4^2) / 256 >= 17
                        \
                        \   x = r3
                        \   y = r4
                        \
                        \ which is what we want

.PLC2

 DEC CNT2               \ Decrement the counter in CNT2 (the low byte)

 BNE PLL2               \ Loop back to PLL2 until CNT2 = 0

 DEC CNT2+1             \ Decrement the counter in CNT2+1 (the high byte)

 BNE PLL2               \ Loop back to PLL2 until CNT2+1 = 0

 LDX MHCA               \ Set the low byte of BLPTR(1 0) to the contents of MHCA
 STX BLPTR              \ (which is &CA), so we now have BLPTR(1 0) = &03CA,
                        \ which we will use in the IRQ1 handler (this has
                        \ nothing to do with drawing Saturn, it's all part of
                        \ the copy protection)

 LDX #&C6               \ Set the low byte of BLN(1 0) to &C6, so we now have
 STX BLN                \ BLN(1 0) = &03C6, which we will use in the IRQ1
                        \ handler (this has nothing to do with drawing Saturn,
                        \ it's all part of the copy protection)

\ ******************************************************************************
\
\       Name: PLL1 (Part 3 of 3)
\       Type: Subroutine
\   Category: Drawing planets
\    Summary: Draw Saturn on the loading screen (draw the rings)
\  Deep dive: Drawing Saturn on the loading screen
\
\ ******************************************************************************

                        \ The following loop iterates CNT3(1 0) times, i.e. &500
                        \ or 1280 times, and draws the rings around the loading
                        \ screen's Saturn

.PLL3

 JSR DORND              \ Set A and X to signed random numbers between -128 and
                        \ 127, so let's say A = r5

 STA ZP                 \ Set ZP = r5

 JSR SQUA2              \ Set (A P) = A * A
                        \           = r5^2

 STA ZP+1               \ Set ZP+1 = A
                        \          = r5^2 / 256

 JSR DORND              \ Set A and X to signed random numbers between -128 and
                        \ 127, so let's say A = r6

 STA YY                 \ Set YY = r6

 JSR SQUA2              \ Set (A P) = A * A
                        \           = r6^2

 STA T                  \ Set T = A
                        \       = r6^2 / 256

 ADC ZP+1               \ Set ZP+1 = A + r5^2 / 256
 STA ZP+1               \          = r6^2 / 256 + r5^2 / 256
                        \          = (r5^2 + r6^2) / 256

 LDA ZP                 \ Set A = ZP
                        \       = r5

 CMP #128               \ If A >= 128, set the C flag (so the C flag is now set
                        \ to bit 7 of ZP, i.e. bit 7 of A)

 ROR A                  \ Rotate A and set the sign bit to the C flag, so bits
                        \ 6 and 7 are now the same

 CMP #128               \ If A >= 128, set the C flag (so again, the C flag is
                        \ set to bit 7 of A)

 ROR A                  \ Rotate A and set the sign bit to the C flag, so bits
                        \ 5-7 are now the same, i.e. A is a random number in one
                        \ of these ranges:
                        \
                        \   %00000000 - %00011111  = 0-31
                        \   %11100000 - %11111111  = 224-255
                        \
                        \ In terms of signed 8-bit integers, this is a random
                        \ number from -32 to 31. Let's call it r7

 ADC YY                 \ Set A = A + YY
                        \       = r7 + r6

 TAX                    \ Set X = A
                        \       = r6 + r7

 JSR SQUA2              \ Set (A P) = A * A
                        \           = (r6 + r7)^2

 TAY                    \ Set Y = A
                        \       = (r6 + r7)^2 / 256

 ADC ZP+1               \ Set A = A + ZP+1
                        \       = (r6 + r7)^2 / 256 + (r5^2 + r6^2) / 256
                        \       = ((r6 + r7)^2 + r5^2 + r6^2) / 256

 BCS PLC3               \ If the addition overflowed, jump down to PLC3 to skip
                        \ to the next pixel

 CMP #80                \ If A >= 80, jump down to PLC3 to skip to the next
 BCS PLC3               \ pixel

 CMP #32                \ If A < 32, jump down to PLC3 to skip to the next pixel
 BCC PLC3

 TYA                    \ Set A = Y + T
 ADC T                  \       = (r6 + r7)^2 / 256 + r6^2 / 256
                        \       = ((r6 + r7)^2 + r6^2) / 256

 CMP #16                \ If A >= 16, skip to PL1 to plot the pixel
 BCS PL1

 LDA ZP                 \ If ZP is positive (i.e. r5 < 128), jump down to PLC3
 BPL PLC3               \ to skip to the next pixel

.PL1

                        \ If we get here then the following is true:
                        \
                        \   32 <= ((r6 + r7)^2 + r5^2 + r6^2) / 256 < 80
                        \
                        \ and either this is true:
                        \
                        \   ((r6 + r7)^2 + r6^2) / 256 >= 16
                        \
                        \ or both these are true:
                        \
                        \   ((r6 + r7)^2 + r6^2) / 256 < 16
                        \   r5 >= 128

 LDA YY                 \ Set A = YY
                        \       = r6

 JSR PIX                \ Draw a pixel at screen coordinate (X + 128, A + 128),
                        \ where:
                        \
                        \   X = (random -32 to 31) + r6
                        \   A = r6
                        \
                        \ So this is the same as plotting at (x, y) where:
                        \
                        \   r5 = random number from -128 to 127
                        \   r6 = random number from -128 to 127
                        \   r7 = r5, squashed into -32 to 31
                        \
                        \   32 <= ((r6 + r7)^2 + r5^2 + r6^2) / 256 < 80
                        \
                        \   Either: ((r6 + r7)^2 + r6^2) / 256 >= 16
                        \
                        \   Or:     ((r6 + r7)^2 + r6^2) / 256 <  16
                        \           r5 >= 128
                        \
                        \   x = r6 + r7 + 128
                        \   y = r6 + 128
                        \
                        \ which is what we want

.PLC3

 DEC CNT3               \ Decrement the counter in CNT3 (the low byte)

 BNE PLL3               \ Loop back to PLL3 until CNT3 = 0

 DEC CNT3+1             \ Decrement the counter in CNT3+1 (the high byte)

 BNE PLL3               \ Loop back to PLL3 until CNT3+1 = 0

\ ******************************************************************************
\
\       Name: DORND
\       Type: Subroutine
\   Category: Maths (Arithmetic)
\    Summary: Generate random numbers
\  Deep dive: Generating random numbers
\             Fixing ship positions
\
\ ------------------------------------------------------------------------------
\
\ Set A and X to random numbers (though note that X is set to the random number
\ that was returned in A the last time DORND was called).
\
\ The C and V flags are also set randomly.
\
\ This is a simplified version of the DORND routine in the main game code. It
\ swaps the two calculations around and omits the ROL A instruction, but is
\ otherwise very similar. See the DORND routine in the main game code for more
\ details.
\
\ ******************************************************************************

.DORND

 LDA RAND+1             \ r1´ = r1 + r3 + C
 TAX                    \ r3´ = r1
 ADC RAND+3
 STA RAND+1
 STX RAND+3

 LDA RAND               \ X = r2´ = r0
 TAX                    \ A = r0´ = r0 + r2
 ADC RAND+2
 STA RAND
 STX RAND+2

 RTS                    \ Return from the subroutine

\ ******************************************************************************
\
\       Name: SQUA2
\       Type: Subroutine
\   Category: Maths (Arithmetic)
\    Summary: Calculate (A P) = A * A
\  Deep dive: Shift-and-add multiplication
\
\ ------------------------------------------------------------------------------
\
\ Do the following multiplication of signed 8-bit numbers:
\
\   (A P) = A * A
\
\ This uses a similar approach to routine SQUA2 in the main game code, which
\ itself uses the MU11 routine to do the multiplication. However, this version
\ first ensures that A is positive, so it can support signed numbers.
\
\ ******************************************************************************

.SQUA2

 BPL SQUA               \ If A > 0, jump to SQUA

 EOR #&FF               \ Otherwise we need to negate A for the SQUA algorithm
 CLC                    \ to work, so we do this using two's complement, by
 ADC #1                 \ setting A = ~A + 1

.SQUA

 STA Q                  \ Set Q = A and P = A

 STA P                  \ Set P = A

 LDA #0                 \ Set A = 0 so we can start building the answer in A

 LDY #8                 \ Set up a counter in Y to count the 8 bits in P

 LSR P                  \ Set P = P >> 1
                        \ and C flag = bit 0 of P

.SQL1

 BCC SQ1                \ If C (i.e. the next bit from P) is set, do the
 CLC                    \ addition for this bit of P:
 ADC Q                  \
                        \   A = A + Q

.SQ1

 ROR A                  \ Shift A right to catch the next digit of our result,
                        \ which the next ROR sticks into the left end of P while
                        \ also extracting the next bit of P

 ROR P                  \ Add the overspill from shifting A to the right onto
                        \ the start of P, and shift P right to fetch the next
                        \ bit for the calculation into the C flag

 DEY                    \ Decrement the loop counter

 BNE SQL1               \ Loop back for the next bit until P has been rotated
                        \ all the way

 RTS                    \ Return from the subroutine

\ ******************************************************************************
\
\       Name: PIX
\       Type: Subroutine
\   Category: Drawing pixels
\    Summary: Draw a single pixel at a specific coordinate
\
\ ------------------------------------------------------------------------------
\
\ Draw a pixel at screen coordinate (X + 128, A + 128). The routine uses the
\ same approach as the PIXEL routine in the main game code, except it plots a
\ single pixel from TWOS instead of a two pixel dash from TWOS2. This applies
\ to the top part of the screen (the monochrome mode 4 space view).
\
\ See the PIXEL routine in the main game code for more details.
\
\ ------------------------------------------------------------------------------
\
\ Arguments:
\
\   X                   The signed screen x-coordinate of the pixel to draw,
\                       from -128 to 127, to be plotted relative to the origin
\                       at (128, 128)
\
\   A                   The signed screen y-coordinate of the pixel to draw,
\                       from -128 to 127, to be plotted relative to the origin
\                       at (128, 128)
\
\ ******************************************************************************

.PIX

 TAY                    \ Copy A into Y, for use later

 EOR #%10000000         \ Add 128 to A and treat this as an unsigned number from
                        \ now on

 LSR A                  \ Set ZP+1 = &60 + A >> 3
 LSR A
 LSR A
 ORA #&60
 STA ZP+1

 TXA                    \ Set A = X + 128 and treat this as an unsigned number
 EOR #%10000000         \ from now on

 AND #%11111000         \ Set ZP = (A >> 3) * 8
 STA ZP

 TYA                    \ Set Y = Y mod 8, which is the pixel row within the
 AND #7                 \ character block at which we want to draw our pixel
 TAY                    \ (as each character block has 8 rows)

 TXA                    \ Set X = X mod 8, which is the horizontal pixel number
 AND #7                 \ within the character block where the pixel lies (as
 TAX                    \ each pixel line in the character block is 8 pixels
                        \ wide)

 LDA TWOS,X             \ Fetch a pixel from TWOS and OR it into ZP+Y
 ORA (ZP),Y
 STA (ZP),Y

 RTS                    \ Return from the subroutine

\ ******************************************************************************
\
\       Name: TWOS
\       Type: Variable
\   Category: Drawing pixels
\    Summary: Ready-made single-pixel character row bytes for mode 4
\
\ ------------------------------------------------------------------------------
\
\ Ready-made bytes for plotting one-pixel points in mode 4 (the top part of the
\ split screen). See the PIX routine for details.
\
\ ******************************************************************************

.TWOS

 EQUB %10000000
 EQUB %01000000
 EQUB %00100000
 EQUB %00010000
 EQUB %00001000
 EQUB %00000100
 EQUB %00000010
 EQUB %00000001

\ ******************************************************************************
\
\       Name: CNT
\       Type: Variable
\   Category: Drawing planets
\    Summary: A counter for use in drawing Saturn's planetary body
\
\ ------------------------------------------------------------------------------
\
\ Defines the number of iterations of the PLL1 loop, which draws the planet part
\ of the loading screen's Saturn.
\
\ ******************************************************************************

.CNT

 EQUW &0500             \ The number of iterations of the PLL1 loop (1280)

\ ******************************************************************************
\
\       Name: CNT2
\       Type: Variable
\   Category: Drawing planets
\    Summary: A counter for use in drawing Saturn's background stars
\
\ ------------------------------------------------------------------------------
\
\ Defines the number of iterations of the PLL2 loop, which draws the background
\ stars on the loading screen.
\
\ ******************************************************************************

.CNT2

 EQUW &01DD             \ The number of iterations of the PLL2 loop (477)

\ ******************************************************************************
\
\       Name: CNT3
\       Type: Variable
\   Category: Drawing planets
\    Summary: A counter for use in drawing Saturn's rings
\
\ ------------------------------------------------------------------------------
\
\ Defines the number of iterations of the PLL3 loop, which draws the rings
\ around the loading screen's Saturn.
\
\ ******************************************************************************

.CNT3

 EQUW &0500             \ The number of iterations of the PLL3 loop (1280)

\ ******************************************************************************
\
\       Name: ROOT
\       Type: Subroutine
\   Category: Maths (Arithmetic)
\    Summary: Calculate ZP = SQRT(ZP(1 0))
\
\ ------------------------------------------------------------------------------
\
\ Calculate the following square root:
\
\   ZP = SQRT(ZP(1 0))
\
\ This routine is identical to LL5 in the main game code - it even has the same
\ label names. The only difference is that LL5 calculates Q = SQRT(R Q), but
\ apart from the variables used, the instructions are identical, so see the LL5
\ routine in the main game code for more details on the algorithm used here.
\
\ ******************************************************************************

.ROOT

 LDY ZP+1               \ Set (Y Q) = ZP(1 0)
 LDA ZP
 STA Q

                        \ So now to calculate ZP = SQRT(Y Q)

 LDX #0                 \ Set X = 0, to hold the remainder

 STX ZP                 \ Set ZP = 0, to hold the result

 LDA #8                 \ Set P = 8, to use as a loop counter
 STA P

.LL6

 CPX ZP                 \ If X < ZP, jump to LL7
 BCC LL7

 BNE LL8                \ If X > ZP, jump to LL8

 CPY #64                \ If Y < 64, jump to LL7 with the C flag clear,
 BCC LL7                \ otherwise fall through into LL8 with the C flag set

.LL8

 TYA                    \ Set Y = Y - 64
 SBC #64                \
 TAY                    \ This subtraction will work as we know C is set from
                        \ the BCC above, and the result will not underflow as we
                        \ already checked that Y >= 64, so the C flag is also
                        \ set for the next subtraction

 TXA                    \ Set X = X - ZP
 SBC ZP
 TAX

.LL7

 ROL ZP                 \ Shift the result in Q to the left, shifting the C flag
                        \ into bit 0 and bit 7 into the C flag

 ASL Q                  \ Shift the dividend in (Y S) to the left, inserting
 TYA                    \ bit 7 from above into bit 0
 ROL A
 TAY

 TXA                    \ Shift the remainder in X to the left
 ROL A
 TAX

 ASL Q                  \ Shift the dividend in (Y S) to the left
 TYA
 ROL A
 TAY

 TXA                    \ Shift the remainder in X to the left
 ROL A
 TAX

 DEC P                  \ Decrement the loop counter

 BNE LL6                \ Loop back to LL6 until we have done 8 loops

 RTS                    \ Return from the subroutine

\ ******************************************************************************
\
\       Name: BEGIN%
\       Type: Subroutine
\   Category: Copy protection
\    Summary: Single-byte decryption and copying routine, run on the stack
\
\ ------------------------------------------------------------------------------
\
\ This routine is copied to the stack at &01F1. It pushes BLOCK to ENDBLOCK onto
\ the stack, and decrypts the code from TUT onwards.
\
\ The 15 instructions for this routine are pushed onto the stack and executed
\ there. The instructions are pushed onto the stack in reverse (as the stack
\ grows downwards in memory), so first the JMP gets pushed, then the STA, and
\ so on.
\
\ This is the code that is pushed onto the stack. It gets run by a JMP call to
\ David2, which then calls the routine on the stack with JSR &01F1.
\
\    01F1 : PLA             \ Remove the return address from the stack that was
\    01F2 : PLA             \ put here by the JSR that called this routine
\
\    01F3 : LDA BLOCK,Y     \ Set A = the Y-th byte of BLOCK
\
\    01F6 : PHA             \ Push A onto the stack
\
\    01F7 : EOR TUT,Y       \ EOR the Y-th byte of TUT with A
\    01FA : STA TUT,Y
\
\    01FD : JMP (David9)    \ Jump to the address in David9
\
\ The routine is called inside a loop with Y as the counter. It counts from 0 to
\ ENDBLOCK - BLOCK, so the routine eventually pushes every byte between BLOCK
\ and ENDBLOCK onto the stack, as well as EOR'ing each byte from TUT onwards to
\ decrypt that section.
\
\ The elite-checksums.py script reverses the order of the bytes between BLOCK
\ and ENDBLOCK in the final file, so pushing them onto the stack (which is a
\ descending stack) realigns them in memory as assembled below. Not only that,
\ but the last two bytes pushed on the stack are the ones that are at the start
\ of the block at BLOCK, and these contain the address of ENTRY2. This is why
\ the RTS at the end of part 4 above actually jumps to ENTRY2 in part 5.
\
\ ******************************************************************************

.BEGIN%

 EQUB HI(David9)        \ JMP (David9)
 EQUB LO(David9)
 EQUB &6C

 EQUB HI(TUT)           \ STA TUT,Y
 EQUB LO(TUT)
 EQUB &99

IF _REMOVE_CHECKSUMS

 EQUB HI(TUT)           \ If we have disabled checksums, then just load the Y-th
 EQUB LO(TUT)           \ byte of TUT with LDA TUT,Y
 EQUB &B9

ELSE

 EQUB HI(TUT)           \ EOR TUT,Y
 EQUB LO(TUT)
 EQUB &59

ENDIF

 PHA                    \ PHA

 EQUB HI(BLOCK)         \ LDA BLOCK,Y
 EQUB LO(BLOCK)
 EQUB &B9

 PLA                    \ PLA

 PLA                    \ PLA

\ ******************************************************************************
\
\       Name: DOMOVE
\       Type: Subroutine
\   Category: Copy protection
\    Summary: Multi-byte decryption and copying routine, run on the stack
\
\ ------------------------------------------------------------------------------
\
\ This routine is copied to the stack at &01DF. It moves and decrypts a block of
\ memory. The original source refers to the stack routine as MVDL.
\
\ The 18 instructions for this routine are pushed onto the stack and executed
\ there. The instructions are pushed onto the stack in reverse (as the stack
\ grows downwards in memory), so first the RTS gets pushed, then the BNE, and
\ so on.
\
\ This is the code that is pushed onto the stack. It gets run by a JMP call to
\ crunchit, which then calls the routine on the stack at MVDL, or &01DF. The
\ label MVDL comes from a comment in the original source file ELITES.
\
\    01DF : .MVDL
\
\    01DF : LDA (ZP),Y      \ Set A = the Y-th byte from the block whose address
\                           \ is in ZP(1 0)
\
\    01E1 : EOR OSB,Y       \ EOR A with the Y-th byte on from OSB
\
\    01E4 : STA (P),Y       \ Store A in the Y-th byte of the block whose
\                           \ address is in P(1 0)
\
\    01E6 : DEY             \ Decrement the loop counter
\
\    01E7 : BNE MVDL        \ Loop back to copy and EOR the next byte until we
\                           \ have copied an entire page (256 bytes)
\
\    01E9 : INC P+1         \ Increment the high byte of P(1 0) so it points to
\                           \ the next page of 256 bytes
\
\    01EB : INC ZP+1        \ Increment ZP(1 0) so it points to the next page of
\                           \ 256 bytes
\
\    01ED : DEX             \ Decrement X
\
\    01EE : BNE MVDL        \ Loop back to copy the next page
\
\    01F0 : RTS             \ Return from the subroutine, which takes us back
\                           \ to the caller of the crunchit routine using a
\                           \ tail call, as we called this with JMP crunchit
\
\ We call MVDL with the following arguments:
\
\   (X Y)               The number of bytes to copy
\
\   ZP(1 0)             The source address
\
\   P(1 0)              The destination address
\
\ The routine moves and decrypts a block of memory, and is used in part 3 to
\ move blocks of code and images that are embedded within the loader binary,
\ either into low memory locations below PAGE (for the recursive token table and
\ page at UU%), or into screen memory (for the loading screen and dashboard
\ images).
\
\ If checksums are disabled in the build, we don't do the EOR instruction, so
\ the routine just moves and doesn't decrypt.
\
\ ******************************************************************************

.DOMOVE

 RTS                    \ RTS

 EQUW &D0EF             \ BNE MVDL

 DEX                    \ DEX

 EQUB ZP+1              \ INC ZP+1
 INC P+1                \ INC P+1
 EQUB &E6

 EQUW &D0F6             \ BNE MVDL

 DEY                    \ DEY

 EQUB P                 \ STA(P),Y
 EQUB &91

IF _REMOVE_CHECKSUMS

 NOP                    \ If we have disabled checksums, skip the EOR so the
 NOP                    \ routine just does the copying part
 NOP

ELSE

 EQUB HI(OSB)           \ EOR OSB,Y
 EQUB LO(OSB)
 EQUB &59

ENDIF

 EQUB ZP                \ LDA(ZP),Y
 EQUB &B1

\ ******************************************************************************
\
\       Name: UU%
\       Type: Workspace
\    Address: &0B00
\   Category: Workspaces
\    Summary: Marker for a block that is moved as part of the obfuscation
\
\ ------------------------------------------------------------------------------
\
\ The code from here to the end of the file gets copied to &0B00 (LE%) by part
\ 3. It is called from the end of part 4, via ENTRY2 in part 5 below.
\
\ ******************************************************************************

.UU%

 Q% = P% - LE%

 ORG LE%                \ Set the assembly address to LE%

\ ******************************************************************************
\
\       Name: CHECKbyt
\       Type: Variable
\   Category: Copy protection
\    Summary: Checksum for the validity of the UU% workspace
\
\ ------------------------------------------------------------------------------
\
\ We calculate the value of the CHECKbyt checksum in elite-checksum.py, so this
\ just reserves a byte. It checks the validity of the first two pages of the UU%
\ workspace, which gets copied to LE%.
\
\ ******************************************************************************

.CHECKbyt

 BRK                    \ This could be an EQUB 0 directive instead of a BRK,
                        \ but this is what's in the source code

\ ******************************************************************************
\
\       Name: MAINSUM
\       Type: Variable
\   Category: Copy protection
\    Summary: Two checksums for the decryption header and text token table
\
\ ------------------------------------------------------------------------------
\
\ Contains two checksum values, one for the header code at LBL, and the other
\ for the recursive token table from &0400 to &07FF.
\
\ ******************************************************************************

.MAINSUM

 EQUB &CB               \ This is the checksum value of the decryption header
                        \ code (from LBL to elitea) that gets prepended to the
                        \ main game code by elite-bcfs.asm and saved as
                        \ ELThead.bin

 EQUB 0                 \ This is the checksum value for the recursive token
                        \ table from &0400 to &07FF. We calculate the value in
                        \ elite-checksum.py, so this just reserves a byte

\ ******************************************************************************
\
\       Name: FOOLV
\       Type: Variable
\   Category: Copy protection
\    Summary: Part of the AFOOL roundabout obfuscation routine
\
\ ------------------------------------------------------------------------------
\
\ FOOLV contains the address of FOOL. This is part of the JSR AFOOL obfuscation
\ routine, which calls AFOOL, which then jumps to the address in FOOLV, which
\ contains the address of FOOL, which contains an RTS instruction... so overall
\ it does nothing, but in a rather roundabout fashion.
\
\ ******************************************************************************

.FOOLV

 EQUW FOOL              \ The address of FOOL, which contains an RTS

\ ******************************************************************************
\
\       Name: CHECKV
\       Type: Variable
\   Category: Copy protection
\    Summary: The address of the LBL routine in the decryption header
\
\ ------------------------------------------------------------------------------
\
\ CHECKV contains the address of the LBL routine at the very start of the main
\ game code file, in the decryption header code that gets prepended to the main
\ game code by elite-bcfs.asm and saved as ELThead.bin
\
\ ******************************************************************************

.CHECKV

 EQUW LOAD%+1           \ The address of the LBL routine

\ ******************************************************************************
\
\       Name: block1
\       Type: Variable
\   Category: Drawing the screen
\    Summary: Palette data for the two dashboard colour scheme
\
\ ------------------------------------------------------------------------------
\
\ Palette bytes for use with the split-screen mode 5. See TVT1 in the main game
\ code for an explanation.
\
\ ******************************************************************************

.block1

 EQUB &F5, &E5
 EQUB &B5, &A5
 EQUB &76, &66
 EQUB &36, &26
 EQUB &D4, &C4
 EQUB &94, &84

\ ******************************************************************************
\
\       Name: block2
\       Type: Variable
\   Category: Drawing the screen
\    Summary: Palette data for the space part of the screen
\
\ ------------------------------------------------------------------------------
\
\ Palette bytes for use with the split-screen mode 4. See TVT1 in the main game
\ code for an explanation.
\
\ ******************************************************************************

.block2

 EQUB &D0, &C0
 EQUB &B0, &A0
 EQUB &F0, &E0
 EQUB &90, &80
 EQUB &77, &67
 EQUB &37, &27

\ ******************************************************************************
\
\       Name: TT26
\       Type: Subroutine
\   Category: Text
\    Summary: Print a character at the text cursor (WRCHV points here)
\
\ ------------------------------------------------------------------------------
\
\ This routine prints a character at the text cursor (XC, YC). It is very
\ similar to the routine of the same name in the main game code, so refer to
\ that routine for a more detailed description.
\
\ This routine, however, only works within a small 14x14 character text window,
\ which we use for the tape loading messages, so there is extra code for fitting
\ the text into the window (and it also reverses the effect of line feeds and
\ carriage returns).
\
\ ------------------------------------------------------------------------------
\
\ Arguments:
\
\   A                   The character to be printed
\
\   XC                  Contains the text column to print at (the x-coordinate)
\
\   YC                  Contains the line number to print on (the y-coordinate)
\
\ ------------------------------------------------------------------------------
\
\ Returns:
\
\   A                   A is preserved
\
\   X                   X is preserved
\
\   Y                   Y is preserved
\
\ ******************************************************************************

.TT26

 STA K3                 \ Store the A, X and Y registers (in K3 for A, and on
 TYA                    \ the stack for the others), so we can restore them at
 PHA                    \ the end (so they don't get changed by this routine)
 TXA
 PHA

.rr

 LDA K3                 \ Set A = the character to be printed

 CMP #7                 \ If this is a beep character (A = 7), jump to R5,
 BEQ R5                 \ which will emit the beep, restore the registers and
                        \ return from the subroutine

 CMP #32                \ If this is an ASCII character (A >= 32), jump to RR1
 BCS RR1                \ below, which will print the character, restore the
                        \ registers and return from the subroutine

 CMP #13                \ If this is control code 13 (carriage return) then jump
 BEQ RRX1               \ to RRX1, which will move along on character, restore
                        \ the registers and return from the subroutine (as we
                        \ don't have room in the text window for new lines)

 INC YC                 \ If we get here, then this is control code 10, a line
                        \ feed, so move down one line and fall through into RRX1
                        \ to move the cursor to the start of the line

.RRX1

 LDX #7                 \ Set the column number (x-coordinate) of the text
 STX XC                 \ to 7

 BNE RR4                \ Jump to RR4 to restore the registers and return from
                        \ the subroutine (this BNE is effectively a JMP as Y
                        \ will never be zero)

.RR1

 LDX #&BF               \ Set X to point to the first font page in ROM minus 1,
                        \ which is &C0 - 1, or &BF

 ASL A                  \ If bit 6 of the character is clear (A is 32-63)
 ASL A                  \ then skip the following instruction
 BCC P%+4

 LDX #&C1               \ A is 64-126, so set X to point to page &C1

 ASL A                  \ If bit 5 of the character is clear (A is 64-95)
 BCC P%+3               \ then skip the following instruction

 INX                    \ Increment X, so X now contains the high byte
                        \ (the page) of the address of the definition that we
                        \ want, while A contains the low byte (the offset into
                        \ the page) of the address

 STA P                  \ Store the address of this character's definition in
 STX P+1                \ P(1 0)

 LDA XC                 \ If the column number (x-coordinate) of the text is
 CMP #20                \ less than 20, skip to NOLF
 BCC NOLF

 LDA #7                 \ Otherwise we just reached the end of the line, so
 STA XC                 \ move the text cursor to column 7, and down onto the
 INC YC                 \ next line

.NOLF

 ASL A                  \ Multiply the x-coordinate (column) of the text by 8
 ASL A                  \ and store in ZP, to get the low byte of the screen
 ASL A                  \ address for the character we want to print
 STA ZP

 INC XC                 \ Once we print the character, we want to move the text
                        \ cursor to the right, so we do this by incrementing XC

 LDA YC                 \ If the row number (y-coordinate) of the text is less
 CMP #19                \ than 19, skip to RR3
 BCC RR3

                        \ Otherwise we just reached the bottom of the screen,
                        \ which is a small 14x14 character text window we use
                        \ for showing the tape loading messages, so now we need
                        \ to clear that window and move the cursor to the top

 LDA #7                 \ Move the text cursor to column 7
 STA XC

 LDA #&65               \ Set the high byte of the SC(1 0) to &65, for character
 STA SC+1               \ row 5 of the screen

 LDY #7*8               \ Set Y = 7 * 8, for column 7 (as there are 8 bytes per
                        \ character block)

 LDX #14                \ Set X = 14, to count the number of character rows we
                        \ need to clear

 STY SC                 \ Set the low byte of SC(1 0) to 7*8, so SC(1 0) now
                        \ points to the character block at row 5, column 7, at
                        \ the top-left corner of the small text window

 LDA #0                 \ Set A = 0 for use in clearing the screen (which we do
                        \ by setting the screen memory to 0)

 TAY                    \ Set Y = 0

.David1

 STA (SC),Y             \ Clear the Y-th byte of the block pointed to by SC(1 0)

 INY                    \ Increment the counter in Y

 CPY #14*8              \ Loop back to clear the next byte until we have done 14
 BCC David1             \ lots of 8 bytes (i.e. 14 characters, the width of the
                        \ small text window)

 TAY                    \ Set Y = 0, ready for the next row

 INC SC+1               \ Point SC(1 0) to the next page in memory, i.e. the
                        \ next character row

 DEX                    \ Decrement the counter in X

 BPL David1             \ Loop back to David1 until we have done 14 character
                        \ rows (the height of the small text window)

 LDA #5                 \ Move the text cursor to row 5
 STA YC

 BNE rr                 \ Jump to rr to print the character we were about to
                        \ print when we ran out of space (this BNE is
                        \ effectively a JMP as A will never be zero)

.RR3

 ORA #&60               \ Add &60 to YC, giving us the page number that we want

 STA ZP+1               \ Store the page number of the destination screen
                        \ location in ZP+1, so ZP now points to the full screen
                        \ location where this character should go

 LDY #7                 \ We want to print the 8 bytes of character data to the
                        \ screen (one byte per row), so set up a counter in Y
                        \ to count these bytes

.RRL1

 LDA (P),Y              \ The character definition is at P(1 0) - we set this up
                        \ above -  so load the Y-th byte from P(1 0)

 STA (ZP),Y             \ Store the Y-th byte at the screen address for this
                        \ character location

 DEY                    \ Decrement the loop counter

 BPL RRL1               \ Loop back for the next byte to print to the screen

.RR4

 PLA                    \ We're done printing, so restore the values of the
 TAX                    \ A, X and Y registers that we saved above, loading them
 PLA                    \ from K3 (for A) and the stack (for X and Y)
 TAY
 LDA K3

.FOOL

 RTS                    \ Return from the subroutine

.R5

 LDA #7                 \ Control code 7 makes a beep, so load this into A

 JSR osprint            \ Call OSPRINT to "print" the beep character

 JMP RR4                \ Jump to RR4 to restore the registers and return from
                        \ the subroutine using a tail call

\ ******************************************************************************
\
\       Name: osprint
\       Type: Subroutine
\   Category: Utility routines
\    Summary: Print a character
\
\ ------------------------------------------------------------------------------
\
\ Arguments:
\
\   A                   The character to print
\
\ ******************************************************************************

.TUT

.osprint

 JMP (OSPRNT)           \ Jump to the address in OSPRNT and return using a
                        \ tail call

 EQUB &6C               \ This byte appears to be unused

\ ******************************************************************************
\
\       Name: command
\       Type: Subroutine
\   Category: Utility routines
\    Summary: Execute an OS command
\
\ ------------------------------------------------------------------------------
\
\ Arguments:
\
\   (Y X)               The address of the OS command string to execute
\
\ ******************************************************************************

.command

 JMP (oscliv)           \ Jump to &FFF7 to execute the OS command pointed to
                        \ by (Y X) and return using a tail call

\ ******************************************************************************
\
\       Name: MESS1
\       Type: Variable
\   Category: Utility routines
\    Summary: Contains an OS command string for loading the main game code
\
\ ******************************************************************************

.MESS1

IF DISC

 EQUS "L.ELTcode 1100"  \ This is short for "*LOAD ELTcode 1100"

ELSE

 EQUS "L.ELITEcode F1F" \ This is short for "*LOAD ELITEcode F1F"

ENDIF

 EQUB 13

\ ******************************************************************************
\
\       Name: Elite loader (Part 5 of 6)
\       Type: Subroutine
\   Category: Loader
\    Summary: Load main game code, decrypt it, move it to the correct location
\
\ ------------------------------------------------------------------------------
\
\ This part loads the main game code, decrypts it and moves it to the correct
\ location for it to run.
\
\ The code in this part is encrypted by elite-checksum.py and is decrypted in
\ part 4 by the same routine that moves part 6 onto the stack.
\
\ ******************************************************************************

.ENTRY2

                        \ We start this part of the loader by setting the
                        \ following:
                        \
                        \   OSPRNT(1 0) = WRCHV
                        \   WRCHV(1 0) = TT26
                        \   (Y X) = MESS1(1 0)
                        \
                        \ so any character printing will use the TT26 routine

 LDA &020E              \ Copy the low byte of WRCHV to the low byte of OSPRNT
 STA OSPRNT

 LDA #LO(TT26)          \ Set the low byte of WRCHV to the low byte of TT26
 STA &020E

 LDX #LO(MESS1)         \ Set X to the low byte of MESS1

 LDA &020F              \ Copy the high byte of WRCHV to the high byte of OSPRNT
 STA OSPRNT+1

 LDA #HI(TT26)          \ Set the high byte of WRCHV to the high byte of TT26
 LDY #HI(MESS1)         \ and set Y to the high byte of MESS1
 STA &020F

 JSR AFOOL              \ This calls AFOOL, which jumps to the address in FOOLV,
                        \ which contains the address of FOOL, which contains an
                        \ RTS instruction... so overall this does nothing, but
                        \ in a rather roundabout fashion

 JSR command            \ Call command to execute the OSCLI command pointed to
                        \ by (Y X) in MESS1, which starts loading the main game
                        \ code

 JSR 512-LEN+CHECKER-ENDBLOCK \ Call the CHECKER routine in its new location on
                              \ the stack, to run a number of checksums on the
                              \ code (this routine, along with the whole of part
                              \ 6, was pushed onto the stack in part 4)

 JSR AFOOL              \ Another call to the round-the-houses routine to try
                        \ and distract the crackers, presumably

IF DISC

 LDA #140               \ Call OSBYTE with A = 140 and X = 12 to select the
 LDX #12                \ tape filing system (i.e. do a *TAPE command)
 JSR OSBYTE

ENDIF

 LDA #0                 \ Set SVN to 0, as the main game code checks the value
 STA SVN                \ of this location in its IRQ1 routine, so it needs to
                        \ be set to 0 so it can work properly once it takes over
                        \ when the game itself runs

                        \ We now decrypt and move the main game code from &1128
                        \ to &0F40

 LDX #HI(LC%)           \ Set X = high byte of LC%, the maximum size of the main
                        \ game code, so if we move this number of pages, we will
                        \ have definitely moved all the game code down

 LDA #LO(L%)            \ Set ZP(1 0) = L% (the start of the game code)
 STA ZP
 LDA #HI(L%)
 STA ZP+1

 LDA #LO(C%)            \ Set P(1 0) = C% = &0F40
 STA P
 LDA #HI(C%)
 STA P+1

 LDY #0                 \ Set Y as a counter for working our way through every
                        \ byte of the game code. We EOR the counter with the
                        \ current byte to decrypt it

.ML1

 TYA                    \ Copy the counter into A

IF _REMOVE_CHECKSUMS

 LDA (ZP),Y             \ If we have disabled checksums, just fetch the byte to
                        \ copy from the Y-th block pointed to by ZP(1 0)

ELSE

 EOR (ZP),Y             \ Fetch the byte and EOR it with the counter

ENDIF

 STA (P),Y              \ Store the copied (and decrypted) byte in the Y-th byte
                        \ of the block pointed to by P(1 0)

 INY                    \ Increment the loop counter

 BNE ML1                \ Loop back for the next byte until we have finished the
                        \ first 256 bytes

 INC ZP+1               \ Increment the high bytes of both ZP(1 0) and P(1 0) to
 INC P+1                \ point to the next 256 bytes

 DEX                    \ Decrement the number of pages we need to copy in X

 BPL ML1                \ Loop back to copy and decrypt the next page of bytes
                        \ until we have done them all

                        \ S% points to the entry point for the main game code,
                        \ so the following copies the addresses from the start
                        \ of the main code (see the S% label in the main game
                        \ code for the vector values)

 LDA S%+6               \ Set BRKV to point to the BR1 routine in the main game
 STA &0202              \ code
 LDA S%+7
 STA &0203

 LDA S%+2               \ Set WRCHV to point to the TT26 routine in the main
 STA &020E              \ game code
 LDA S%+3
 STA &020F

 RTS                    \ This RTS actually does a jump to the first instruction
                        \ in BLOCK, after the two EQUW operatives, which is now
                        \ on the stack. This takes us to the next and final
                        \ step of the loader in part 6. See the documentation
                        \ for the stack routine at BEGIN% for more details

.AFOOL

 JMP (FOOLV)            \ This jumps to the address in FOOLV as part of the
                        \ JSR AFOOL instruction above, which does nothing except
                        \ take us on wild goose chase

\ ******************************************************************************
\
\       Name: M2
\       Type: Variable
\   Category: Utility routines
\    Summary: Used for testing the 6522 System VIA status byte in IRQ1
\
\ ------------------------------------------------------------------------------
\
\ Used for testing bit 1 of the 6522 System VIA status byte in the IRQ1 routine,
\ as well as bit 1 of the block flag.
\
\ ******************************************************************************

.M2

 EQUB %00000010         \ Bit 1 is set

\ ******************************************************************************
\
\       Name: IRQ1
\       Type: Subroutine
\   Category: Drawing the screen
\    Summary: The loader's screen-mode interrupt handler (IRQ1V points here)
\  Deep dive: The split-screen mode in BBC Micro Elite
\
\ ------------------------------------------------------------------------------
\
\ The main interrupt handler, which implements Elite's split-screen mode.
\
\ This routine is similar to the main IRQ1 routine in the main game code, except
\ it's a bit simpler (it doesn't need to support the mode-flashing effect of
\ hyperspace, for example).
\
\ It also sets Timer 1 to a different value, 14386 instead of 14622. The split
\ in the split-screen mode does overlap more in the loader than in the game, so
\ it's interesting that they didn't fine-tune this version as much.
\
\ For more details on how the following works, see the IRQ1 routine in the main
\ game code.
\
\ ******************************************************************************

.VIA2

 LDA #%00000100         \ Set the Video ULA control register (SHEILA &20) to
 STA &FE20              \ %00000100, which is the same as switching to mode 5,
                        \ (i.e. the bottom part of the screen) but with no
                        \ cursor

 LDY #11                \ We now apply the palette bytes from block1 to the
                        \ mode 5 screen, so set a counter in Y for 12 bytes

.inlp1

 LDA block1,Y           \ Copy the Y-th palette byte from block1 to SHEILA &21
 STA &FE21              \ to map logical to actual colours for the bottom part
                        \ of the screen (i.e. the dashboard)

 DEY                    \ Decrement the palette byte counter

 BPL inlp1              \ Loop back to the inlp1 until we have copied all the
                        \ palette bytes

 PLA                    \ Restore Y from the stack
 TAY

 JMP (VEC)              \ Jump to the address in VEC, which was set to the
                        \ original IRQ1V vector in part 4, so this instruction
                        \ passes control to the next interrupt handler

.IRQ1

 TYA                    \ Store Y on the stack
 PHA

IF PROT AND NOT(DISC)

                        \ By this point, we have set up the following in
                        \ various places throughout the loader code (such as
                        \ part 2 and PLL1):
                        \
                        \   BLPTR(1 0) = &03CA
                        \   BLN(1 0)   = &03C6
                        \   EXCN(1 0)  = &03C2
                        \
                        \ BLPTR (&03CA) is a byte in the MOS workspace that
                        \ stores the block flag of the most recent block loaded
                        \ from tape
                        \
                        \ BLN (&03C6) is the low byte of the number of the last
                        \ block loaded from tape
                        \
                        \ EXCN (&03C2) is the low byte of the execution address
                        \ of the file being loaded

 LDY #0                 \ Set A to the block flag of the most recent block
 LDA (BLPTR),Y          \ loaded from tape

 BIT M2                 \ If bit 1 of the block flag is set, jump to itdone
 BNE itdone

 EOR #%10000011         \ Otherwise flip bits 0, 1 and 7 of A. This has two
                        \ main effects:
                        \
                        \   * Bit 0 of the block flag gets cleared. Most
                        \     cassette versions of Acornsoft games are saved to
                        \     tape with locked blocks, so you can't just load
                        \     the game into memory (you'll get a "Locked" error
                        \     for each block). Locked blocks have bit 0 set, so
                        \     this clears the locked status, so when the MOS
                        \     gets round to checking whether the block is
                        \     locked, we've already cleared it and updated it in
                        \     memory (which we do below), so the block loads
                        \     without throwing an error
                        \
                        \   * Bit 1 of the block flag gets set, so we won't
                        \     increment BLCNT again until the next block starts
                        \     loading (so in this way we count the number of
                        \     blocks loaded in BLCNT)

 INC BLCNT              \ Increment BLCNT, which was initialised to 0 in part 3

 BNE ZQK                \ If BLCNT is non-zero, skip the next instruction

 DEC BLCNT              \ If incrementing BLCNT set it to zero, decrement it, so
                        \ this sets a maximum of 255 on BLCNT

.ZQK

 STA (BLPTR),Y          \ Store the updated value of A in the block flag, so the
                        \ block gets unlocked

 LDA #35                \ If the block number in BLN is 35, skip the next
 CMP (BLN),Y            \ instruction, leaving A = 32 = &23
 BEQ P%+4

 EOR #17                \ Set A = 35 EOR 17 = 50 = &32

 CMP (EXCN),Y           \ If the low byte of the execution address of the file
 BEQ itdone             \ we are loading is equal to A (which is either &23 or
                        \ &32), skip to itdone

 DEC LOAD%              \ Otherwise decrement LOAD%, which is the address of the
                        \ first byte of the main game code file (i.e. the load
                        \ address of "ELTcode"), so this decrements the first
                        \ byte of the file we are loading, i.e. the LBL variable
                        \ added by the Big Code File source

.itdone

ENDIF

 LDA VIA+&4D            \ Read the 6522 System VIA status byte bit 1 (SHEILA
 BIT M2                 \ &4D), which is set if vertical sync has occurred on
                        \ the video system

 BNE LINSCN             \ If we are on the vertical sync pulse, jump to LINSCN
                        \ to set up the timers to enable us to switch the
                        \ screen mode between the space view and dashboard

 AND #%01000000         \ If the 6522 System VIA status byte bit 6 is set, which
 BNE VIA2               \ means timer 1 has timed out, jump to VIA2

 PLA                    \ Restore Y from the stack
 TAY

 JMP (VEC)              \ Jump to the address in VEC, which was set to the
                        \ original IRQ1V vector in part 4, so this instruction
                        \ passes control to the next interrupt handler

.LINSCN

 LDA #50                \ Set 6522 System VIA T1C-L timer 1 low-order counter
 STA VIA+&44            \ (SHEILA &44) to 50

 LDA #VSCAN             \ Set 6522 System VIA T1C-L timer 1 high-order counter
 STA VIA+&45            \ (SHEILA &45) to VSCAN (56) to start the T1 counter
                        \ counting down from 14386 at a rate of 1 MHz

 LDA #8                 \ Set the Video ULA control register (SHEILA &20) to
 STA &FE20              \ %00001000, which is the same as switching to mode 4
                        \ (i.e. the top part of the screen) but with no cursor

 LDY #11                \ We now apply the palette bytes from block2 to the
                        \ mode 4 screen, so set a counter in Y for 12 bytes

.inlp2

 LDA block2,Y           \ Copy the Y-th palette byte from block2 to SHEILA &21
 STA &FE21              \ to map logical to actual colours for the top part of
                        \ the screen (i.e. the space view)

 DEY                    \ Decrement the palette byte counter

 BPL inlp2              \ Loop back to the inlp1 until we have copied all the
                        \ palette bytes

 PLA                    \ Restore Y from the stack
 TAY

 JMP (VEC)              \ Jump to the address in VEC, which was set to the
                        \ original IRQ1V vector in part 4, so this instruction
                        \ passes control to the next interrupt handler

\ ******************************************************************************
\
\       Name: BLOCK
\       Type: Variable
\   Category: Copy protection
\    Summary: Addresses for the obfuscated jumps that use RTS not JMP
\
\ ------------------------------------------------------------------------------
\
\ These two addresses get pushed onto the stack in part 4. The first EQUW is the
\ address of ENTRY2, while the second is the address of the first instruction in
\ part 6, after it is pushed onto the stack.
\
\ This entire section from BLOCK to ENDBLOCK gets copied into the stack at
\ location &015E by part 4, so by the time we call the routine at the second
\ EQUW address at the start, the entry point is on the stack at &0163.
\
\ This means that the RTS instructions at the end of parts 4 and 5 jump to
\ ENTRY2 and the start of part 6 respectively. See part 4 for details.
\
\ ******************************************************************************

.BLOCK

 EQUW ENTRY2-1

 EQUW 512-LEN+BLOCK-ENDBLOCK+3

\ ******************************************************************************
\
\       Name: Elite loader (Part 6 of 6)
\       Type: Subroutine
\   Category: Loader
\    Summary: Set up interrupt vectors, calculate checksums, run main game code
\
\ ------------------------------------------------------------------------------
\
\ This is the final part of the loader. It sets up some of the main game's
\ interrupt vectors and calculates various checksums, before finally handing
\ over to the main game.
\
\ ------------------------------------------------------------------------------
\
\ Other entry points:
\
\   nononono            Reset the machine
\
\ ******************************************************************************

 LDA VIA+&44            \ Read the 6522 System VIA T1C-L timer 1 low-order
 STA &0001              \ counter (SHEILA &44), which decrements one million
                        \ times a second and will therefore be pretty random,
                        \ and store it in location &0001, which is among the
                        \ main game code's random seeds (so this seeds the
                        \ random number generator for the main game)

 SEI                    \ Disable all interrupts

 LDA #%00111001         \ Set 6522 System VIA interrupt enable register IER
 STA VIA+&4E            \ (SHEILA &4E) bits 0 and 3-5 (i.e. disable the Timer1,
                        \ CB1, CB2 and CA2 interrupts from the System VIA)

\LDA #&7F               \ These instructions are commented out in the original
\STA &FE6E              \ source with the comment "already done", which they
\LDA IRQ1V              \ were, in part 4
\STA VEC
\LDA IRQ1V+1
\STA VEC+1

 LDA S%+4               \ S% points to the entry point for the main game code,
 STA IRQ1V              \ so this copies the address of the main game's IRQ1
 LDA S%+5               \ routine from the start of the main code into IRQ1V
 STA IRQ1V+1

 LDA #VSCAN             \ Set 6522 System VIA T1C-L timer 1 high-order counter
 STA VIA+&45            \ (SHEILA &45) to VSCAN (56) to start the T1 counter
                        \ counting down from 14080 at a rate of 1 MHz (this is
                        \ a different value to the main game code)

 CLI                    \ Re-enable interrupts

\LDA #129               \ These instructions are commented out in the original
\LDY #&FF               \ source. They call OSBYTE with A = 129, X = 1 and
\LDX #1                 \ Y = &FF, which returns the machine type in X, so
\JSR OSBYTE             \ this code would detect the MOS version
\
\TXA
\EOR #&FF
\STA MOS
\
\BMI BLAST

 LDY #0                 \ Call OSBYTE with A = 200, X = 3 and Y = 0 to disable
 LDA #200               \ the ESCAPE key and clear memory if the BREAK key is
 LDX #3                 \ pressed
 JSR OSBYTE

                        \ The rest of the routine calculates various checksums
                        \ and makes sure they are correct before proceeding, to
                        \ prevent code tampering. We start by calculating the
                        \ checksum for the main game code from &0F40 to &5540,
                        \ which just adds up every byte and checks it against
                        \ the checksum stored at the end of the main game code

.BLAST

 LDA #HI(S%)            \ Set ZP(1 0) = S%
 STA ZP+1               \
 LDA #LO(S%)            \ so ZP(1 0) points to the start of the main game code
 STA ZP

 LDX #&45               \ We are going to checksum &45 pages from &0F40 to &5540
                        \ so set a page counter in X

 LDY #0                 \ Set Y to count through each byte within each page

 TYA                    \ Set A = 0 for building the checksum

.CHK

 CLC                    \ Add the Y-th byte of this page of the game code to A
 ADC (ZP),Y

 INY                    \ Increment the counter for this page

 BNE CHK                \ Loop back for the next byte until we have finished
                        \ adding up this page

 INC ZP+1               \ Increment the high byte of ZP(1 0) to point to the
                        \ next page

 DEX                    \ Decrement the page counter we set in X

 BPL CHK                \ Loop back to add up the next page until we have done
                        \ them all

IF _REMOVE_CHECKSUMS

 LDA #0                 \ If we have disabled checksums, just set A to 0 so the
 NOP                    \ BEQ below jumps to itsOK

ELSE

 CMP D%-1               \ D% is set to the address of the byte after the end of
                        \ the code, so this compares the result to the last byte
                        \ in the main game code at location checksum0

ENDIF

 BEQ itsOK              \ If the checksum we just calculated matches the value
                        \ in location checksum0, jump to itsOK

.nononono

 STA S%+1               \ If we get here then the checksum was wrong, so first
                        \ we store the incorrect checksum value in the low byte
                        \ of the address stored at the start of the main game
                        \ code, which contains the address of TT170, the entry
                        \ point for the main game (so this hides this address
                        \ from prying eyes)

 LDA #%01111111         \ Set 6522 System VIA interrupt enable register IER
 STA &FE4E              \ (SHEILA &4E) bits 0-6 (i.e. disable all hardware
                        \ interrupts from the System VIA)

 JMP (&FFFC)            \ Jump to the address in &FFFC to reset the machine

.itsOK

 JMP (S%)               \ The checksum was correct, so we call the address held
                        \ in the first two bytes of the main game code, which
                        \ point to TT170, the entry point for the main game
                        \ code, so this, finally, is where we hand over to the
                        \ game itself

\ ******************************************************************************
\
\       Name: CHECKER
\       Type: Subroutine
\   Category: Copy protection
\    Summary: Run checksum checks on tokens, loader and tape block count
\
\ ------------------------------------------------------------------------------
\
\ This routine runs checksum checks on the recursive token table and the loader
\ code at the start of the main game code file, to prevent tampering with these
\ areas of memory. It also runs a check on the tape loading block count.
\
\ ------------------------------------------------------------------------------
\
\ Other entry points:
\
\   ENDBLOCK            Denotes the end of the encrypted code that starts at
\                       BLOCK
\
\ ******************************************************************************

.CHECKER

                        \ First we check the MAINSUM+1 checksum for the
                        \ recursive token table from &0400 to &07FF

 LDY #0                 \ Set Y = 0 to count through each byte within each page

 LDX #4                 \ We are going to checksum 4 pages from &0400 to &07FF
                        \ so set a page counter in X

 STX ZP+1               \ Set ZP(1 0) = &0400, to point to the start of the code
 STY ZP                 \ we want to checksum

 TYA                    \ Set A = 0 for building the checksum

.CHKq

 CLC                    \ Add the Y-th byte of this page of the token table to A
 ADC (ZP),Y

 INY                    \ Increment the counter for this page

 BNE CHKq               \ Loop back for the next byte until we have finished
                        \ adding up this page

 INC ZP+1               \ Increment the high byte of ZP(1 0) to point to the
                        \ next page

 DEX                    \ Decrement the page counter we set in X

 BNE CHKq               \ Loop back to add up the next page until we have done
                        \ them all

 CMP MAINSUM+1          \ Compare the result to the contents of MAINSUM+1, which
                        \ contains the checksum for the table (this gets set by
                        \ elite-checksum.py)

IF _REMOVE_CHECKSUMS

 NOP                    \ If we have disabled checksums, do nothing
 NOP

ELSE

 BNE nononono           \ If the checksum we just calculated does not match the
                        \ contents of MAINSUM+1, jump to nononono to reset the
                        \ machine

ENDIF

                        \ Next, we check the LBL routine in the header that's
                        \ appended to the main game code in elite-bcfs.asm, and
                        \ which is currently loaded at LOAD% (which contains the
                        \ load address of the main game code file)

 TYA                    \ Set A = 0 for building the checksum (as Y is still 0
                        \ from the above checksum loop)

.CHKb

 CLC                    \ Add the Y-th byte of LOAD% to A
 ADC LOAD%,Y

 INY                    \ Increment the counter

 CPY #40                \ There are 40 bytes in the loader, so loop back until
 BNE CHKb               \ we have added them all

 CMP MAINSUM            \ Compare the result to the contents of MAINSUM, which
                        \ contains the checksum for loader code

IF _REMOVE_CHECKSUMS

 NOP                    \ If we have disabled checksums, do nothing
 NOP

ELSE

 BNE nononono           \ If the checksum we just calculated does not match the
                        \ contents of MAINSUM, jump to nononono to reset the
                        \ machine

ENDIF

                        \ Finally, we check the block count from the tape
                        \ loading code in the IRQ1 routine, which counts the
                        \ number of blocks in the main game code

IF PROT AND NOT(DISC)

 LDA BLCNT              \ If the tape protection is enabled and we are loading
 CMP #&4F               \ from tape (as opposed to disc), check that the block
 BCC nononono           \ count in BLCNT is &4F, and if it isn't, jump to
                        \ nononono to reset the machine

ENDIF

IF _REMOVE_CHECKSUMS

 RTS                    \ If we have disabled checksums, return from the
 NOP                    \ subroutine
 NOP

ELSE

 JMP (CHECKV)           \ Call the LBL routine in the header (whose address is
                        \ in CHECKV). This routine is inserted before the main
                        \ game code by elite-bcfs.asm, and it checks the
                        \ validity of the first two pages of the UU% routine,
                        \ which was copied to LE% above, and which contains a
                        \ checksum byte in CHECKbyt. We then return from the
                        \ subroutine using a tail call

ENDIF

.ENDBLOCK

\ ******************************************************************************
\
\       Name: XC
\       Type: Variable
\   Category: Text
\    Summary: The x-coordinate of the text cursor
\
\ ------------------------------------------------------------------------------
\
\ Contains the x-coordinate of the text cursor (i.e. the text column) with an
\ initial value of column 7, at the top-left corner of the 14x14 text window
\ where we show the tape loading messages (see TT26 for details).
\
\ ******************************************************************************

.XC

 EQUB 7

\ ******************************************************************************
\
\       Name: YC
\       Type: Variable
\   Category: Text
\    Summary: The y-coordinate of the text cursor
\
\ ------------------------------------------------------------------------------
\
\ Contains the y-coordinate of the text cursor (i.e. the text row) with an
\ initial value of row 6, at the top-left corner of the 14x14 text window where
\ we show the tape loading messages (see TT26 for details).
\
\ ******************************************************************************

.YC

 EQUB 6

\ ******************************************************************************
\
\ Save ELITE.unprot.bin
\
\ ******************************************************************************

 COPYBLOCK LE%, P%, UU%         \ Copy the block that we assembled at LE% to
                                \ UU%, which is where it will actually run

 PRINT "Addresses for the scramble routines in elite-checksum.py"
 PRINT "BLOCK_offset = ", ~(BLOCK - LE%) + (UU% - CODE%)
 PRINT "ENDBLOCK_offset = ", ~(ENDBLOCK - LE%) + (UU% - CODE%)
 PRINT "MAINSUM_offset = ", ~(MAINSUM - LE%) + (UU% - CODE%)
 PRINT "TUT_offset = ", ~(TUT - LE%) + (UU% - CODE%)
 PRINT "CHECKbyt_offset = ", ~(CHECKbyt - LE%) + (UU% - CODE%)
 PRINT "CODE_offset = ", ~(OSB - CODE%)
 PRINT "UU% = ", ~UU%
 PRINT "Q% = ", ~Q%
 PRINT "OSB = ", ~OSB

 PRINT "Memory usage: ", ~LE%, " - ", ~P%
 PRINT "Stack: ",LEN + ENDBLOCK - BLOCK

 PRINT "S. ELITE ", ~CODE%, " ", ~UU% + (P% - LE%), " ", ~run, " ", ~CODE%
 SAVE "3-assembled-output/ELITE.unprot.bin", CODE%, UU% + (P% - LE%), run, CODE%


================================================
FILE: 1-source-files/main-sources/elite-readme.asm
================================================
\ ******************************************************************************
\
\ BBC MICRO CASSETTE ELITE README SOURCE
\
\ BBC Micro cassette Elite was written by Ian Bell and David Braben and is
\ copyright Acornsoft 1984
\
\ The code in this file is identical to the source discs released on Ian Bell's
\ personal website at http://www.elitehomepage.org/ (it's just been reformatted
\ to be more readable)
\
\ The commentary is copyright Mark Moxon, and any misunderstandings or mistakes
\ in the documentation are entirely my fault
\
\ The terminology and notations used in this commentary are explained at
\ https://elite.bbcelite.com/terminology
\
\ The deep dive articles referred to in this commentary can be found at
\ https://elite.bbcelite.com/deep_dives
\
\ ------------------------------------------------------------------------------
\
\ This source file produces a README file for BBC Micro cassette Elite.
\
\ ------------------------------------------------------------------------------
\
\ This source file produces the following binary file:
\
\   * README.txt
\
\ ******************************************************************************

 INCLUDE "1-source-files/main-sources/elite-build-options.asm"

 _SOURCE_DISC           = (_VARIANT = 1)
 _TEXT_SOURCES          = (_VARIANT = 2)
 _STH_CASSETTE          = (_VARIANT = 3)

.readme

 EQUB 10, 13
 EQUS "---------------------------------------"
 EQUB 10, 13
 EQUS "Acornsoft Elite"
 EQUB 10, 13
 EQUB 10, 13
 EQUS "Version: BBC Micro cassette"
 EQUB 10, 13

IF _SOURCE_DISC

 EQUS "Variant: Ian Bell's source disc"
 EQUB 10, 13

ELIF _TEXT_SOURCES

 EQUS "Variant: Ian Bell's text sources"
 EQUB 10, 13

ELIF _STH_CASSETTE

 EQUS "Variant: Stairway to Hell cassette"
 EQUB 10, 13
 EQUS "Product: Acornsoft SBG38"
 EQUB 10, 13

ENDIF

 EQUB 10, 13
 EQUS "See www.bbcelite.com for details"
 EQUB 10, 13
 EQUS "---------------------------------------"
 EQUB 10, 13

 SAVE "3-assembled-output/README.txt", readme, P%



================================================
FILE: 1-source-files/main-sources/elite-source.asm
================================================
\ ******************************************************************************
\
\ BBC MICRO CASSETTE ELITE MAIN GAME SOURCE
\
\ BBC Micro cassette Elite was written by Ian Bell and David Braben and is
\ copyright Acornsoft 1984
\
\ The code in this file is identical to the source discs released on Ian Bell's
\ personal website at http://www.elitehomepage.org/ (it's just been reformatted
\ to be more readable)
\
\ The commentary is copyright Mark Moxon, and any misunderstandings or mistakes
\ in the documentation are entirely my fault
\
\ The terminology and notations used in this commentary are explained at
\ https://elite.bbcelite.com/terminology
\
\ The deep dive articles referred to in this commentary can be found at
\ https://elite.bbcelite.com/deep_dives
\
\ ------------------------------------------------------------------------------
\
\ This source file contains the main game code for BBC Micro cassette Elite. It
\ also contains the ship blueprints and game text.
\
\ ------------------------------------------------------------------------------
\
\ This source file produces the following binary files:
\
\   * ELTA.bin
\   * ELTB.bin
\   * ELTC.bin
\   * ELTD.bin
\   * ELTE.bin
\   * ELTF.bin
\   * ELTG.bin
\   * PYTHON.bin
\   * SHIPS.bin
\   * WORDS9.bin
\
\ ******************************************************************************

 INCLUDE "1-source-files/main-sources/elite-build-options.asm"

 _SOURCE_DISC           = (_VARIANT = 1)
 _TEXT_SOURCES          = (_VARIANT = 2)
 _STH_CASSETTE          = (_VARIANT = 3)

 GUARD &6000            \ Guard against assembling over screen memory

\ ******************************************************************************
\
\ Configuration variables
\
\ ******************************************************************************

 CODE% = &0F40          \ The address where the code will be run

 LOAD% = &1128          \ The address where the code will be loaded

 CODE_WORDS% = &0400    \ The address where the text data will be run

 LOAD_WORDS% = &1100    \ The address where the text data will be loaded

 Q% = _MAX_COMMANDER    \ Set Q% to TRUE to max out the default commander, FALSE
                        \ for the standard default commander

 NOST = 18              \ The number of stardust particles in normal space (this
                        \ goes down to 3 in witchspace)

 NOSH = 12              \ The maximum number of ships in our local bubble of
                        \ universe

 NTY = 13               \ The number of different ship types

 COPS = 2               \ Ship type for a Viper

 THG = 6                \ Ship type for a Thargoid

 CYL = 7                \ Ship type for a Cobra Mk III (trader)

 SST = 8                \ Ship type for the space station

 MSL = 9                \ Ship type for a missile

 AST = 10               \ Ship type for an asteroid

 OIL = 11               \ Ship type for a cargo canister

 TGL = 12               \ Ship type for a Thargon

 ESC = 13               \ Ship type for an escape pod

 POW = 15               \ Pulse laser power

 NI% = 36               \ The number of bytes in each ship's data block (as
                        \ stored in INWK and K%)

 VSCAN = 57             \ Defines the split position in the split-screen mode

 X = 128                \ The centre x-coordinate of the 256 x 192 space view

 Y = 96                 \ The centre y-coordinate of the 256 x 192 space view

 f0 = &20               \ Internal key number for red key f0 (Launch, Front)

 f1 = &71               \ Internal key number for red key f1 (Buy Cargo, Rear)

 f2 = &72               \ Internal key number for red key f2 (Sell Cargo, Left)

 f3 = &73               \ Internal key number for red key f3 (Equip Ship, Right)

 f4 = &14               \ Internal key number for red key f4 (Long-range Chart)

 f5 = &74               \ Internal key number for red key f5 (Short-range Chart)

 f6 = &75               \ Internal key number for red key f6 (Data on System)

 f7 = &16               \ Internal key number for red key f7 (Market Price)

 f8 = &76               \ Internal key number for red key f8 (Status Mode)

 f9 = &77               \ Internal key number for red key f9 (Inventory)

 RE = &23               \ The obfuscation byte used to hide the recursive tokens
                        \ table from crackers viewing the binary code

 VIA = &FE00            \ Memory-mapped space for accessing internal hardware,
                        \ such as the video ULA, 6845 CRTC and 6522 VIAs (also
                        \ known as SHEILA)

 OSBYTE = &FFF4         \ The address for the OSBYTE routine, which is used
                        \ three times in the main game code

 OSWORD = &FFF1         \ The address for the OSWORD routine, which is used
                        \ twice in the main game code

 OSFILE = &FFDD         \ The address for the OSFILE routine, which is used
                        \ once in the main game code

\ ******************************************************************************
\
\       Name: ZP
\       Type: Workspace
\    Address: &0000 to &00E1
\   Category: Workspaces
\    Summary: Lots of important variables are stored in the zero page workspace
\             as it is quicker and more space-efficient to access memory here
\
\ ******************************************************************************

 ORG &0000              \ Set the assembly address to &0000

.ZP

 SKIP 0                 \ The start of the zero page workspace

.RAND

 SKIP 4                 \ Four 8-bit seeds for the random number generation
                        \ system implemented in the DORND routine

.TRTB%

 SKIP 2                 \ Contains the address of the keyboard translation
                        \ table, which is used to translate internal key
                        \ numbers to ASCII

.T1

 SKIP 1                 \ Temporary storage, used in a number of places

.SC

 SKIP 1                 \ Screen address (low byte)
                        \
                        \ Elite draws on-screen by poking bytes directly into
                        \ screen memory, and SC(1 0) is typically set to the
                        \ address of the character block containing the pixel
                        \ we want to draw

.SCH

 SKIP 1                 \ Screen address (high byte)

.XX16

 SKIP 18                \ Temporary storage for a block of values, used in a
                        \ number of places

.P

 SKIP 3                 \ Temporary storage, used in a number of places

.XX0

 SKIP 2                 \ Temporary storage, used to store the address of a ship
                        \ blueprint. For example, it is used when we add a new
                        \ ship to the local bubble in routine NWSHP, and it
                        \ contains the address of the current ship's blueprint
                        \ as we loop through all the nearby ships in the main
                        \ flight loop

.INF

 SKIP 2                 \ Temporary storage, typically used for storing the
                        \ address of a ship's data block, so it can be copied
                        \ to and from the internal workspace at INWK

.V

 SKIP 2                 \ Temporary storage, typically used for storing an
                        \ address pointer

.XX

 SKIP 2                 \ Temporary storage, typically used for storing a 16-bit
                        \ x-coordinate

.YY

 SKIP 2                 \ Temporary storage, typically used for storing a 16-bit
                        \ y-coordinate

.SUNX

 SKIP 2                 \ The 16-bit x-coordinate of the vertical centre axis
                        \ of the sun (which might be off-screen)

.BETA

 SKIP 1                 \ The current pitch angle beta, which is reduced from
                        \ JSTY to a sign-magnitude value between -8 and +8
                        \
                        \ This describes how fast we are pitching our ship, and
                        \ determines how fast the universe pitches around us
                        \
                        \ The sign bit is also stored in BET2, while the
                        \ opposite sign is stored in BET2+1

.BET1

 SKIP 1                 \ The magnitude of the pitch angle beta, i.e. |beta|,
                        \ which is a positive value between 0 and 8

.XC

 SKIP 1                 \ The x-coordinate of the text cursor (i.e. the text
                        \ column), which can be from 0 to 32
                        \
                        \ A value of 0 denotes the leftmost column and 32 the
                        \ rightmost column, but because the top part of the
                        \ screen (the space view) has a border box that
                        \ clashes with columns 0 and 32, text is only shown
                        \ in columns 1-31

.YC

 SKIP 1                 \ The y-coordinate of the text cursor (i.e. the text
                        \ row), which can be from 0 to 23
                        \
                        \ The screen actually has 31 character rows if you
                        \ include the dashboard, but the text printing routines
                        \ only work on the top part (the space view), so the
                        \ text cursor only goes up to a maximum of 23, the row
                        \ just before the screen splits
                        \
                        \ A value of 0 denotes the top row, but because the
                        \ top part of the screen has a border box that clashes
                        \ with row 0, text is always shown at row 1 or greater

.QQ22

 SKIP 2                 \ The two hyperspace countdown counters
                        \
                        \ Before a hyperspace jump, both QQ22 and QQ22+1 are
                        \ set to 15
                        \
                        \ QQ22 is an internal counter that counts down by 1
                        \ each time TT102 is called, which happens every
                        \ iteration of the main game loop. When it reaches
                        \ zero, the on-screen counter in QQ22+1 gets
                        \ decremented, and QQ22 gets set to 5 and the countdown
                        \ continues (so the first tick of the hyperspace counter
                        \ takes 15 iterations to happen, but subsequent ticks
                        \ take 5 iterations each)
                        \
                        \ QQ22+1 contains the number that's shown on-screen
                        \ during the countdown. It counts down from 15 to 1, and
                        \ when it hits 0, the hyperspace engines kick in

.ECMA

 SKIP 1                 \ The E.C.M. countdown timer, which determines whether
                        \ an E.C.M. system is currently operating
                        \
                        \   * 0 = E.C.M. is off
                        \
                        \   * Non-zero = E.C.M. is on and is counting down
                        \
                        \ The counter starts at 32 when an E.C.M. is activated,
                        \ either by us or by an opponent, and it decreases by 1
                        \ in each iteration of the main flight loop until it
                        \ reaches zero, at which point the E.C.M. switches off.
                        \ Only one E.C.M. can be active at any one time, so
                        \ there is only one counter

.XX15

 SKIP 0                 \ Temporary storage, typically used for storing screen
                        \ coordinates in line-drawing routines
                        \
                        \ There are six bytes of storage, from XX15 TO XX15+5.
                        \ The first four bytes have the following aliases:
                        \
                        \   X1 = XX15
                        \   Y1 = XX15+1
                        \   X2 = XX15+2
                        \   Y2 = XX15+3
                        \
                        \ These are typically used for describing lines in terms
                        \ of screen coordinates, i.e. (X1, Y1) to (X2, Y2)
                        \
                        \ The last two bytes of XX15 do not have aliases

.X1

 SKIP 1                 \ Temporary storage, typically used for x-coordinates in
                        \ the line-drawing routines

.Y1

 SKIP 1                 \ Temporary storage, typically used for y-coordinates in
                        \ line-drawing routines

.X2

 SKIP 1                 \ Temporary storage, typically used for x-coordinates in
                        \ the line-drawing routines

.Y2

 SKIP 1                 \ Temporary storage, typically used for y-coordinates in
                        \ line-drawing routines

 SKIP 2                 \ The last two bytes of the XX15 block

.XX12

 SKIP 6                 \ Temporary storage for a block of values, used in a
                        \ number of places

.K

 SKIP 4                 \ Temporary storage, used in a number of places

.KL

 SKIP 1                 \ The following bytes implement a key logger that
                        \ enables Elite to scan for concurrent key presses of
                        \ the primary flight keys, plus a secondary flight key
                        \
                        \ If a key is being pressed that is not in the keyboard
                        \ table at KYTB, it can be stored here (as seen in
                        \ routine DK4, for example)

.KY1

 SKIP 1                 \ "?" is being pressed (slow down)
                        \
                        \   * 0 = no
                        \
                        \   * Non-zero = yes

.KY2

 SKIP 1                 \ Space is being pressed (speed up)
                        \
                        \   * 0 = no
                        \
                        \   * Non-zero = yes

.KY3

 SKIP 1                 \ "<" is being pressed (roll left)
                        \
                        \   * 0 = no
                        \
                        \   * Non-zero = yes

.KY4

 SKIP 1                 \ ">" is being pressed (roll right)
                        \
                        \   * 0 = no
                        \
                        \   * Non-zero = yes

.KY5

 SKIP 1                 \ "X" is being pressed (pull up)
                        \
                        \   * 0 = no
                        \
                        \   * Non-zero = yes

.KY6

 SKIP 1                 \ "S" is being pressed (pitch down)
                        \
                        \   * 0 = no
                        \
                        \   * Non-zero = yes

.KY7

 SKIP 1                 \ "A" is being pressed (fire lasers)
                        \
                        \   * 0 = no
                        \
                        \   * Non-zero = yes
                        \
                        \ This is also set when the joystick fire button has
                        \ been pressed

.KY12

 SKIP 1                 \ TAB is being pressed (energy bomb)
                        \
                        \   * 0 = no
                        \
                        \   * Non-zero = yes

.KY13

 SKIP 1                 \ ESCAPE is being pressed (launch escape pod)
                        \
                        \   * 0 = no
                        \
                        \   * Non-zero = yes

.KY14

 SKIP 1                 \ "T" is being pressed (target missile)
                        \
                        \   * 0 = no
                        \
                        \   * Non-zero = yes

.KY15

 SKIP 1                 \ "U" is being pressed (unarm missile)
                        \
                        \   * 0 = no
                        \
                        \   * Non-zero = yes

.KY16

 SKIP 1                 \ "M" is being pressed (fire missile)
                        \
                        \   * 0 = no
                        \
                        \   * Non-zero = yes

.KY17

 SKIP 1                 \ "E" is being pressed (activate E.C.M.)
                        \
                        \   * 0 = no
                        \
                        \   * Non-zero = yes

.KY18

 SKIP 1                 \ "J" is being pressed (in-system jump)
                        \
                        \   * 0 = no
                        \
                        \   * Non-zero = yes

.KY19

 SKIP 1                 \ "C" is being pressed (activate docking computer)
                        \
                        \   * 0 = no
                        \
                        \   * Non-zero = yes

.LAS

 SKIP 1                 \ Contains the laser power of the laser fitted to the
                        \ current space view (or 0 if there is no laser fitted
                        \ to the current view)
                        \
                        \ This gets set to bits 0-6 of the laser power byte from
                        \ the commander data block, which contains the laser's
                        \ power (bit 7 doesn't denote laser power, just whether
                        \ or not the laser pulses, so that is not stored here)

.MSTG

 SKIP 1                 \ The current missile lock target
                        \
                        \   * &FF = no target
                        \
                        \   * 1-12 = the slot number of the ship that our
                        \            missile is locked onto

.XX1

 SKIP 0                 \ This is an alias for INWK that is used in the main
                        \ ship-drawing routine at LL9

.INWK

 SKIP 33                \ The zero-page internal workspace for the current ship
                        \ data block
                        \
                        \ As operations on zero page locations are faster and
                        \ have smaller opcodes than operations on the rest of
                        \ the addressable memory, Elite tends to store oft-used
                        \ data here. A lot of the routines in Elite need to
                        \ access and manipulate ship data, so to make this an
                        \ efficient exercise, the ship data is first copied from
                        \ the ship data blocks at K% into INWK (or, when new
                        \ ships are spawned, from the blueprints at XX21)

.XX19

 SKIP NI% - 33          \ XX19(1 0) shares its location with INWK(34 33), which
                        \ contains the address of the ship line heap

.LSP

 SKIP 1                 \ The ball line heap pointer, which contains the number
                        \ of the first free byte after the end of the LSX2 and
                        \ LSY2 heaps

.QQ15

 SKIP 6                 \ The three 16-bit seeds for the selected system, i.e.
                        \ the one in the crosshairs in the Short-range Chart

.K5

 SKIP 0                 \ Temporary storage used to store segment coordinates
                        \ across successive calls to BLINE, the ball line
                        \ routine

.XX18

 SKIP 0                 \ Temporary storage used to store coordinates in the
                        \ LL9 ship-drawing routine

.QQ17

 SKIP 1                 \ Contains a number of flags that affect how text tokens
                        \ are printed, particularly capitalisation
                        \
                        \   * If all bits are set (255) then text printing is
                        \     disabled
                        \
                        \   * Bit 7: 0 = ALL CAPS
                        \            1 = Sentence Case, bit 6 determines the
                        \                case of the next letter to print
                        \
                        \   * Bit 6: 0 = print the next letter in upper case
                        \            1 = print the next letter in lower case
                        \
                        \   * Bits 0-5: If any of bits 0-5 are set, print in
                        \               lower case
                        \
                        \ So:
                        \
                        \   * QQ17 = 0 means case is set to ALL CAPS
                        \
                        \   * QQ17 = %10000000 means Sentence Case, currently
                        \            printing upper case
                        \
                        \   * QQ17 = %11000000 means Sentence Case, currently
                        \            printing lower case
                        \
                        \   * QQ17 = %11111111 means printing is disabled

.QQ19

 SKIP 3                 \ Temporary storage, used in a number of places

.K6

 SKIP 5                 \ Temporary storage, typically used for storing
                        \ coordinates during vector calculations

.ALP1

 SKIP 1                 \ Magnitude of the roll angle alpha, i.e. |alpha|,
                        \ which is a positive value between 0 and 31

.ALP2

 SKIP 2                 \ Bit 7 of ALP2 = sign of the roll angle in ALPHA
                        \
                        \ Bit 7 of ALP2+1 = opposite sign to ALP2 and ALPHA

.BET2

 SKIP 2                 \ Bit 7 of BET2 = sign of the pitch angle in BETA
                        \
                        \ Bit 7 of BET2+1 = opposite sign to BET2 and BETA

.DELTA

 SKIP 1                 \ Our current speed, in the range 1-40

.DELT4

 SKIP 2                 \ Our current speed * 64 as a 16-bit value
                        \
                        \ This is stored as DELT4(1 0), so the high byte in
                        \ DELT4+1 therefore contains our current speed / 4

.U

 SKIP 1                 \ Temporary storage, used in a number of places

.Q

 SKIP 1                 \ Temporary storage, used in a number of places

.R

 SKIP 1                 \ Temporary storage, used in a number of places

.S

 SKIP 1                 \ Temporary storage, used in a number of places

.XSAV

 SKIP 1                 \ Temporary storage for saving the value of the X
                        \ register, used in a number of places

.YSAV

 SKIP 1                 \ Temporary storage for saving the value of the Y
                        \ register, used in a number of places

.XX17

 SKIP 1                 \ Temporary storage, used in BPRNT to store the number
                        \ of characters to print, and as the edge counter in the
                        \ main ship-drawing routine

.QQ11

 SKIP 1                 \ The type of the current view:
                        \
                        \   0   = Space view
                        \   1   = Data on System screen (red key f6)
                        \         Get commander name ("@", save/load commander)
                        \         In-system jump just arrived ("J")
                        \         Title screen
                        \         Buy Cargo screen (red key f1)
                        \         Mis-jump just arrived (witchspace)
                        \   4   = Sell Cargo screen (red key f2)
                        \   6   = Death screen
                        \   8   = Status Mode screen (red key f8)
                        \         Inventory screen (red key f9)
                        \   16  = Market Price screen (red key f7)
                        \   32  = Equip Ship screen (red key f3)
                        \   64  = Long-range Chart (red key f4)
                        \   128 = Short-range Chart (red key f5)
                        \
                        \ This value is typically set by calling routine TT66

.ZZ

 SKIP 1                 \ Temporary storage, typically used for distance values

.XX13

 SKIP 1                 \ Temporary storage, typically used in the line-drawing
                        \ routines

.MCNT

 SKIP 1                 \ The main loop counter
                        \
                        \ This counter determines how often certain actions are
                        \ performed within the main loop

.DL

 SKIP 1                 \ Vertical sync flag
                        \
                        \ DL gets set to 30 every time we reach vertical sync on
                        \ the video system, which happens 50 times a second
                        \ (50Hz). The WSCAN routine uses this to pause until the
                        \ vertical sync, by setting DL to 0 and then monitoring
                        \ its value until it changes to 30

.TYPE

 SKIP 1                 \ The current ship type
                        \
                        \ This is where we store the current ship type for when
                        \ we are iterating through the ships in the local bubble
                        \ as part of the main flight loop. See the table at XX21
                        \ for information about ship types

.JSTX

 SKIP 1                 \ Our current roll rate
                        \
                        \ This value is shown in the dashboard's RL indicator,
                        \ and determines the rate at which we are rolling
                        \
                        \ The value ranges from 1 to 255 with 128 as the centre
                        \ point, so 1 means roll is decreasing at the maximum
                        \ rate, 128 means roll is not changing, and 255 means
                        \ roll is increasing at the maximum rate
                        \
                        \ This value is updated by "<" and ">" key presses, or
                        \ if joysticks are enabled, from the joystick. If
                        \ keyboard damping is enabled (which it is by default),
                        \ the value is slowly moved towards the centre value of
                        \ 128 (no roll) if there are no key presses or joystick
                        \ movement

.JSTY

 SKIP 1                 \ Our current pitch rate
                        \
                        \ This value is shown in the dashboard's DC indicator,
                        \ and determines the rate at which we are pitching
                        \
                        \ The value ranges from 1 to 255 with 128 as the centre
                        \ point, so 1 means pitch is decreasing at the maximum
                        \ rate, 128 means pitch is not changing, and 255 means
                        \ pitch is increasing at the maximum rate
                        \
                        \ This value is updated by "S" and "X" key presses, or
                        \ if joysticks are enabled, from the joystick. If
                        \ keyboard damping is enabled (which it is by default),
                        \ the value is slowly moved towards the centre value of
                        \ 128 (no pitch) if there are no key presses or joystick
                        \ movement

.ALPHA

 SKIP 1                 \ The current roll angle alpha, which is reduced from
                        \ JSTX to a sign-magnitude value between -31 and +31
                        \
                        \ This describes how fast we are rolling our ship, and
                        \ determines how fast the universe rolls around us
                        \
                        \ The sign bit is also stored in ALP2, while the
                        \ opposite sign is stored in ALP2+1

.QQ12

 SKIP 1                 \ Our "docked" status
                        \
                        \   * 0 = we are not docked
                        \
                        \   * &FF = we are docked

.TGT

 SKIP 1                 \ Temporary storage, typically used as a target value
                        \ for counters when drawing explosion clouds and partial
                        \ circles

.SWAP

 SKIP 1                 \ Temporary storage, used to store a flag that records
                        \ whether or not we had to swap a line's start and end
                        \ coordinates around when clipping the line in routine
                        \ LL145 (the flag is used in places like BLINE to swap
                        \ them back)

.COL

 SKIP 1                 \ Temporary storage, used to store colour information
                        \ when drawing pixels in the dashboard

.FLAG

 SKIP 1                 \ A flag that's used to define whether this is the first
                        \ call to the ball line routine in BLINE, so it knows
                        \ whether to wait for the second call before storing
                        \ segment data in the ball line heap

.CNT

 SKIP 1                 \ Temporary storage, typically used for storing the
                        \ number of iterations required when looping

.CNT2

 SKIP 1                 \ Temporary storage, used in the planet-drawing routine
                        \ to store the segment number where the arc of a partial
                        \ circle should start

.STP

 SKIP 1                 \ The step size for drawing circles
                        \
                        \ Circles in Elite are split up into 64 points, and the
                        \ step size determines how many points to skip with each
                        \ straight-line segment, so the smaller the step size,
                        \ the smoother the circle. The values used are:
                        \
                        \   * 2 for big planets and the circles on the charts
                        \
                        \   * 4 for medium planets and the launch tunnel
                        \
                        \   * 8 for small planets and the hyperspace tunnel
                        \
                        \ As the step size increases we move from smoother
                        \ circles at the top to more polygonal at the bottom.
                        \ See the CIRCLE2 routine for more details

.XX4

 SKIP 1                 \ Temporary storage, used in a number of places

.XX20

 SKIP 1                 \ Temporary storage, used in a number of places

.XX14

 SKIP 1                 \ This byte appears to be unused

.RAT

 SKIP 1                 \ Used to store different signs depending on the current
                        \ space view, for use in calculating stardust movement

.RAT2

 SKIP 1                 \ Temporary storage, used to store the pitch and roll
                        \ signs when moving objects and stardust

.K2

 SKIP 4                 \ Temporary storage, used in a number of places

 ORG &00D1              \ Set the assembly address to &00D1

.T

 SKIP 1                 \ Temporary storage, used in a number of places

.K3

 SKIP 0                 \ Temporary storage, used in a number of places

.XX2

 SKIP 14                \ Temporary storage, used to store the visibility of the
                        \ ship's faces during the ship-drawing routine at LL9

.K4

 SKIP 2                 \ Temporary storage, used in a number of places

 PRINT "ZP workspace from ", ~ZP, "to ", ~P%-1, "inclusive"

\ ******************************************************************************
\
\       Name: XX3
\       Type: Workspace
\    Address: &0100 to the top of the descending stack
\   Category: Workspaces
\    Summary: Temporary storage space for complex calculations
\
\ ------------------------------------------------------------------------------
\
\ Used as heap space for storing temporary data during calculations. Shared with
\ the descending 6502 stack, which works down from &01FF.
\
\ ******************************************************************************

 ORG &0100              \ Set the assembly address to &0100

.XX3

 SKIP 256               \ Temporary storage, typically used for storing tables
                        \ of values such as screen coordinates or ship data

\ ******************************************************************************
\
\       Name: T%
\       Type: Workspace
\    Address: &0300 to &0371
\   Category: Workspaces
\    Summary: Current commander data and stardust data blocks
\
\ ------------------------------------------------------------------------------
\
\ Contains the current commander data (NT% bytes at location TP), and the
\ stardust data blocks (NOST bytes at location SX)
\
\ ******************************************************************************

 ORG &0300              \ Set the assembly address to &0300

.T%

 SKIP 0                 \ The start of the T% workspace

.TP

 SKIP 1                 \ The current mission status, which is always 0 for the
                        \ cassette version of Elite as there are no missions

.QQ0

 SKIP 1                 \ The current system's galactic x-coordinate (0-256)

.QQ1

 SKIP 1                 \ The current system's galactic y-coordinate (0-256)

.QQ21

 SKIP 6                 \ The three 16-bit seeds for the current galaxy
                        \
                        \ These seeds define system 0 in the current galaxy, so
                        \ they can be used as a starting point to generate all
                        \ 256 systems in the galaxy
                        \
                        \ Using a galactic hyperdrive rotates each byte to the
                        \ left (rolling each byte within itself) to get the
                        \ seeds for the next galaxy, so after eight galactic
                        \ jumps, the seeds roll around to the first galaxy again

.CASH

 SKIP 4                 \ Our current cash pot
                        \
                        \ The cash stash is stored as a 32-bit unsigned integer,
                        \ with the most significant byte in CASH and the least
                        \ significant in CASH+3. This is big-endian, which is
                        \ the opposite way round to most of the numbers used in
                        \ Elite - to use our notation for multi-byte numbers,
                        \ the amount of cash is CASH(0 1 2 3)

.QQ14

 SKIP 1                 \ Our current fuel level (0-70)
                        \
                        \ The fuel level is stored as the number of light years
                        \ multiplied by 10, so QQ14 = 1 represents 0.1 light
                        \ years, and the maximum possible value is 70, for 7.0
                        \ light years

.COK

 SKIP 1                 \ Flags used to generate the competition code

.GCNT

 SKIP 1                 \ The number of the current galaxy (0-7)
                        \
                        \ When this is displayed in-game, 1 is added to the
                        \ number, so we start in galaxy 1 in-game, but it's
                        \ stored as galaxy 0 internally
                        \
                        \ The galaxy number increases by one every time a
                        \ galactic hyperdrive is used, and wraps back around to
                        \ the start after eight galaxies

.LASER

 SKIP 4                 \ The specifications of the lasers fitted to each of the
                        \ four space views
                        \
                        \   * Byte #0 = front view
                        \
                        \   * Byte #1 = rear view
                        \
                        \   * Byte #2 = left view
                        \
                        \   * Byte #3 = right view
                        \
                        \ The value for each view is as follows:
                        \
                        \   * 0 = no laser is fitted to this view
                        \
                        \   * Non-zero = a laser is fitted to this view, with
                        \     the following specification:
                        \
                        \     * Bits 0-6 contain the laser's power
                        \
                        \     * Bit 7 determines whether or not the laser pulses
                        \       (0 = pulse laser) or is always on (1 = beam
                        \       laser)

 SKIP 2                 \ These bytes appear to be unused (they were originally
                        \ used for up/down lasers, but they were dropped)

.CRGO

 SKIP 1                 \ Our ship's cargo capacity
                        \
                        \   * 22 = standard cargo bay of 20 tonnes
                        \
                        \   * 37 = large cargo bay of 35 tonnes
                        \
                        \ The value is two greater than the actual capacity to
                        \ make the maths in tnpr slightly more efficient

.QQ20

 SKIP 17                \ The contents of our cargo hold
                        \
                        \ The amount of market item X that we have in our hold
                        \ can be found in the X-th byte of QQ20. For example:
                        \
                        \   * QQ20 contains the amount of food (item 0)
                        \
                        \   * QQ20+7 contains the amount of computers (item 7)
                        \
                        \ See QQ23 for a list of market item numbers and their
                        \ storage units

.ECM

 SKIP 1                 \ E.C.M. system
                        \
                        \   * 0 = not fitted
                        \
                        \   * &FF = fitted

.BST

 SKIP 1                 \ Fuel scoops (BST stands for "barrel status")
                        \
                        \   * 0 = not fitted
                        \
                        \   * &FF = fitted

.BOMB

 SKIP 1                 \ Energy bomb
                        \
                        \   * 0 = not fitted
                        \
                        \   * &7F = fitted

.ENGY

 SKIP 1                 \ Energy unit
                        \
                        \   * 0 = not fitted
                        \
                        \   * Non-zero = fitted
                        \
                        \ The actual value determines the refresh rate of our
                        \ energy banks, as they refresh by ENGY+1 each time (so
                        \ our ship's energy level goes up by 2 each time if we
                        \ have an energy unit fitted, otherwise it goes up by 1)

.DKCMP

 SKIP 1                 \ Docking computer
                        \
                        \   * 0 = not fitted
                        \
                        \   * &FF = fitted

.GHYP

 SKIP 1                 \ Galactic hyperdrive
                        \
                        \   * 0 = not fitted
                        \
                        \   * &FF = fitted

.ESCP

 SKIP 1                 \ Escape pod
                        \
                        \   * 0 = not fitted
                        \
                        \   * &FF = fitted

 SKIP 4                 \ These bytes appear to be unused

.NOMSL

 SKIP 1                 \ The number of missiles we have fitted (0-4)

.FIST

 SKIP 1                 \ Our legal status (FIST stands for "fugitive/innocent
                        \ status")
                        \
                        \   * 0 = Clean
                        \
                        \   * 1-49 = Offender
                        \
                        \   * 50+ = Fugitive
                        \
                        \ You get 64 points if you kill a cop, so that's a fast
                        \ ticket to fugitive status

.AVL

 SKIP 17                \ Market availability in the current system
                        \
                        \ The available amount of market item X is stored in
                        \ the X-th byte of AVL, so for example:
                        \
                        \   * AVL contains the amount of food (item 0)
                        \
                        \   * AVL+7 contains the amount of computers (item 7)
                        \
                        \ See QQ23 for a list of market item numbers and their
                        \ storage units

.QQ26

 SKIP 1                 \ A random value used to randomise market data
                        \
                        \ This value is set to a new random number for each
                        \ change of system, so we can add a random factor into
                        \ the calculations for market prices

.TALLY

 SKIP 2                 \ Our combat rank
                        \
                        \ The combat rank is stored as the number of kills, in a
                        \ 16-bit number TALLY(1 0) - so the high byte is in
                        \ TALLY+1 and the low byte in TALLY
                        \
                        \ If the high byte in TALLY+1 is 0 then we have between
                        \ 0 and 255 kills, so our rank is Harmless, Mostly
                        \ Harmless, Poor, Average Above Average or Competent,
                        \ according to the value of the low byte in TALLY:
                        \
                        \   Harmless         %00000000 to %00000111 = 0 to 7
                        \   Mostly Harmless  %00001000 to %00001111 = 8 to 15
                        \   Poor             %00010000 to %00011111 = 16 to 31
                        \   Average          %00100000 to %00111111 = 32 to 63
                        \   Above Average    %01000000 to %01111111 = 64 to 127
                        \   Competent        %10000000 to %11111111 = 128 to 255
                        \
                        \ Note that the Competent range also covers kill counts
                        \ from 256 to 511, as follows
                        \
                        \ If the high byte in TALLY+1 is non-zero then we are
                        \ Competent, Dangerous, Deadly or Elite, according to
                        \ the value of TALLY(1 0):
                        \
                        \   Competent   (1 0) to (1 255)   = 256 to 511 kills
                        \   Dangerous   (2 0) to (9 255)   = 512 to 2559 kills
                        \   Deadly      (10 0) to (24 255) = 2560 to 6399 kills
                        \   Elite       (25 0) and up      = 6400 kills and up
                        \
                        \ You can see the rating calculation in the STATUS
                        \ subroutine

.SVC

 SKIP 1                 \ The save count
                        \
                        \ When a new commander is created, the save count gets
                        \ set to 128. This value gets halved each time the
                        \ commander file is saved, but it is otherwise unused.
                        \ It is presumably part of the security system for the
                        \ competition, possibly another flag to catch out
                        \ entries with manually altered commander files

 SKIP 2                 \ The commander file checksum
                        \
                        \ These two bytes are reserved for the commander file
                        \ checksum, so when the current commander block is
                        \ copied from here to the last saved commander block at
                        \ NA%, CHK and CHK2 get overwritten

 NT% = SVC + 2 - TP     \ This sets the variable NT% to the size of the current
                        \ commander data block, which starts at TP and ends at
                        \ SVC+2 (inclusive)

.SX

 SKIP NOST + 1          \ This is where we store the x_hi coordinates for all
                        \ the stardust particles

.SXL

 SKIP NOST + 1          \ This is where we store the x_lo coordinates for all
                        \ the stardust particles

 PRINT "T% workspace from ", ~T%, "to ", ~P%-1, "inclusive"

\ ******************************************************************************
\
\ ELITE RECURSIVE TEXT TOKEN FILE
\
\ Produces the binary file WORDS9.bin that gets loaded by elite-loader.asm.
\
\ The recursive token table is loaded at &1100 and is moved down to &0400 as
\ part of elite-loader.asm, so it ends up at &0400 to &07FF.
\
\ ******************************************************************************

 ORG CODE_WORDS%        \ Set the assembly address to CODE_WORDS%

\ ******************************************************************************
\
\       Name: CHAR
\       Type: Macro
\   Category: Text
\    Summary: Macro definition for characters in the recursive token table
\  Deep dive: Printing text tokens
\
\ ------------------------------------------------------------------------------
\
\ The following macro is used when building the recursive token table:
\
\   CHAR 'x'            Insert ASCII character "x"
\
\ To include an apostrophe, use a backtick character, as in CHAR '`'.
\
\ ------------------------------------------------------------------------------
\
\ Arguments:
\
\   'x'                 The character to insert into the table
\
\ ******************************************************************************

MACRO CHAR x

 IF x = '`'
   EQUB 39 EOR RE
 ELSE
   EQUB x EOR RE
 ENDIF

ENDMACRO

\ ******************************************************************************
\
\       Name: TWOK
\       Type: Macro
\   Category: Text
\    Summary: Macro definition for two-letter tokens in the token table
\  Deep dive: Printing text tokens
\
\ ------------------------------------------------------------------------------
\
\ The following macro is used when building the recursive token table:
\
\   TWOK 'x', 'y'       Insert two-letter token "xy"
\
\ ------------------------------------------------------------------------------
\
\ Arguments:
\
\   'x'                 The first letter of the two-letter token to insert into
\                       the table
\
\   'y'                 The second letter of the two-letter token to insert into
\                       the table
\
\ ******************************************************************************

MACRO TWOK t, k

 IF t = 'A' AND k = 'L'
  EQUB 128 EOR RE
 ENDIF

 IF t = 'L' AND k = 'E'
  EQUB 129 EOR RE
 ENDIF

 IF t = 'X' AND k = 'E'
  EQUB 130 EOR RE
 ENDIF

 IF t = 'G' AND k = 'E'
  EQUB 131 EOR RE
 ENDIF

 IF t = 'Z' AND k = 'A'
  EQUB 132 EOR RE
 ENDIF

 IF t = 'C' AND k = 'E'
  EQUB 133 EOR RE
 ENDIF

 IF t = 'B' AND k = 'I'
  EQUB 134 EOR RE
 ENDIF

 IF t = 'S' AND k = 'O'
  EQUB 135 EOR RE
 ENDIF

 IF t = 'U' AND k = 'S'
  EQUB 136 EOR RE
 ENDIF

 IF t = 'E' AND k = 'S'
  EQUB 137 EOR RE
 ENDIF

 IF t = 'A' AND k = 'R'
  EQUB 138 EOR RE
 ENDIF

 IF t = 'M' AND k = 'A'
  EQUB 139 EOR RE
 ENDIF

 IF t = 'I' AND k = 'N'
  EQUB 140 EOR RE
 ENDIF

 IF t = 'D' AND k = 'I'
  EQUB 141 EOR RE
 ENDIF

 IF t = 'R' AND k = 'E'
  EQUB 142 EOR RE
 ENDIF

 IF t = 'A' AND k = '?'
  EQUB 143 EOR RE
 ENDIF

 IF t = 'E' AND k = 'R'
  EQUB 144 EOR RE
 ENDIF

 IF t = 'A' AND k = 'T'
  EQUB 145 EOR RE
 ENDIF

 IF t = 'E' AND k = 'N'
  EQUB 146 EOR RE
 ENDIF

 IF t = 'B' AND k = 'E'
  EQUB 147 EOR RE
 ENDIF

 IF t = 'R' AND k = 'A'
  EQUB 148 EOR RE
 ENDIF

 IF t = 'L' AND k = 'A'
  EQUB 149 EOR RE
 ENDIF

 IF t = 'V' AND k = 'E'
  EQUB 150 EOR RE
 ENDIF

 IF t = 'T' AND k = 'I'
  EQUB 151 EOR RE
 ENDIF

 IF t = 'E' AND k = 'D'
  EQUB 152 EOR RE
 ENDIF

 IF t = 'O' AND k = 'R'
  EQUB 153 EOR RE
 ENDIF

 IF t = 'Q' AND k = 'U'
  EQUB 154 EOR RE
 ENDIF

 IF t = 'A' AND k = 'N'
  EQUB 155 EOR RE
 ENDIF

 IF t = 'T' AND k = 'E'
  EQUB 156 EOR RE
 ENDIF

 IF t = 'I' AND k = 'S'
  EQUB 157 EOR RE
 ENDIF

 IF t = 'R' AND k = 'I'
  EQUB 158 EOR RE
 ENDIF

 IF t = 'O' AND k = 'N'
  EQUB 159 EOR RE
 ENDIF

ENDMACRO

\ ******************************************************************************
\
\       Name: CONT
\       Type: Macro
\   Category: Text
\    Summary: Macro definition for control codes in the recursive token table
\  Deep dive: Printing text tokens
\
\ ------------------------------------------------------------------------------
\
\ The following macro is used when building the recursive token table:
\
\   CONT n              Insert control code token {n}
\
\ ------------------------------------------------------------------------------
\
\ Arguments:
\
\   n                   The control code to insert into the table
\
\ ******************************************************************************

MACRO CONT n

 EQUB n EOR RE

ENDMACRO

\ ******************************************************************************
\
\       Name: RTOK
\       Type: Macro
\   Category: Text
\    Summary: Macro definition for recursive tokens in the recursive token table
\  Deep dive: Printing text tokens
\
\ ------------------------------------------------------------------------------
\
\ The following macro is used when building the recursive token table:
\
\   RTOK n              Insert recursive token [n]
\
\                         * Tokens 0-95 get stored as n + 160
\
\                         * Tokens 128-145 get stored as n - 114
\
\                         * Tokens 96-127 get stored as n
\
\ ------------------------------------------------------------------------------
\
\ Arguments:
\
\   n                   The number of the recursive token to insert into the
\                       table, in the range 0 to 145
\
\ ******************************************************************************

MACRO RTOK n

 IF n >= 0 AND n <= 95
  t = n + 160
 ELIF n >= 128
  t = n - 114
 ELSE
  t = n
 ENDIF

 EQUB t EOR RE

ENDMACRO

\ ******************************************************************************
\
\       Name: QQ18
\       Type: Variable
\   Category: Text
\    Summary: The recursive token table for tokens 0-148
\  Deep dive: Printing text tokens
\
\ ------------------------------------------------------------------------------
\
\ The encodings shown for each recursive text token use the following notation:
\
\   {n}           Control code              n = 0 to 13
\   <n>           Two-letter token          n = 128 to 159
\   [n]           Recursive token           n = 0 to 148
\
\ ******************************************************************************

.QQ18

 RTOK 111               \ Token 0:      "FUEL SCOOPS ON {beep}"
 RTOK 131               \
 CONT 7                 \ Encoded as:   "[111][131]{7}"
 EQUB 0

 CHAR ' '               \ Token 1:      " CHART"
 CHAR 'C'               \
 CHAR 'H'               \ Encoded as:   " CH<138>T"
 TWOK 'A', 'R'
 CHAR 'T'
 EQUB 0

 CHAR 'G'               \ Token 2:      "GOVERNMENT"
 CHAR 'O'               \
 TWOK 'V', 'E'          \ Encoded as:   "GO<150>RNM<146>T"
 CHAR 'R'
 CHAR 'N'
 CHAR 'M'
 TWOK 'E', 'N'
 CHAR 'T'
 EQUB 0

 CHAR 'D'               \ Token 3:      "DATA ON {selected system name}"
 TWOK 'A', 'T'          \
 CHAR 'A'               \ Encoded as:   "D<145>A[131]{3}"
 RTOK 131
 CONT 3
 EQUB 0

 TWOK 'I', 'N'          \ Token 4:      "INVENTORY{crlf}
 TWOK 'V', 'E'          \               "
 CHAR 'N'               \
 CHAR 'T'               \ Encoded as:   "<140><150>NT<153>Y{13}"
 TWOK 'O', 'R'
 CHAR 'Y'
 CONT 13
 EQUB 0

 CHAR 'S'               \ Token 5:      "SYSTEM"
 CHAR 'Y'               \
 CHAR 'S'               \ Encoded as:   "SYS<156>M"
 TWOK 'T', 'E'
 CHAR 'M'
 EQUB 0

 CHAR 'P'               \ Token 6:      "PRICE"
 TWOK 'R', 'I'          \
 TWOK 'C', 'E'          \ Encoded as:   "P<158><133>"
 EQUB 0

 CONT 2                 \ Token 7:      "{current system name} MARKET PRICES"
 CHAR ' '               \
 TWOK 'M', 'A'          \ Encoded as:   "{2} <139>RKET [6]S"
 CHAR 'R'
 CHAR 'K'
 CHAR 'E'
 CHAR 'T'
 CHAR ' '
 RTOK 6
 CHAR 'S'
 EQUB 0

 TWOK 'I', 'N'          \ Token 8:      "INDUSTRIAL"
 CHAR 'D'               \
 TWOK 'U', 'S'          \ Encoded as:   "<140>D<136>T<158><128>"
 CHAR 'T'
 TWOK 'R', 'I'
 TWOK 'A', 'L'
 EQUB 0

 CHAR 'A'               \ Token 9:      "AGRICULTURAL"
 CHAR 'G'               \
 TWOK 'R', 'I'          \ Encoded as:   "AG<158>CULTU<148>L"
 CHAR 'C'
 CHAR 'U'
 CHAR 'L'
 CHAR 'T'
 CHAR 'U'
 TWOK 'R', 'A'
 CHAR 'L'
 EQUB 0

 TWOK 'R', 'I'          \ Token 10:     "RICH "
 CHAR 'C'               \
 CHAR 'H'               \ Encoded as:   "<158>CH "
 CHAR ' '
 EQUB 0

 CHAR 'A'               \ Token 11:     "AVERAGE "
 TWOK 'V', 'E'          \
 TWOK 'R', 'A'          \ Encoded as:   "A<150><148><131> "
 TWOK 'G', 'E'
 CHAR ' '
 EQUB 0

 CHAR 'P'               \ Token 12:     "POOR "
 CHAR 'O'               \
 TWOK 'O', 'R'          \ Encoded as:   "PO<153> "
 CHAR ' '
 EQUB 0

 TWOK 'M', 'A'          \ Token 13:     "MAINLY "
 TWOK 'I', 'N'          \
 CHAR 'L'               \ Encoded as:   "<139><140>LY "
 CHAR 'Y'
 CHAR ' '
 EQUB 0

 CHAR 'U'               \ Token 14:     "UNIT"
 CHAR 'N'               \
 CHAR 'I'               \ Encoded as:   "UNIT"
 CHAR 'T'
 EQUB 0

 CHAR 'V'               \ Token 15:     "VIEW "
 CHAR 'I'               \
 CHAR 'E'               \ Encoded as:   "VIEW "
 CHAR 'W'
 CHAR ' '
 EQUB 0

 TWOK 'Q', 'U'          \ Token 16:     "QUANTITY"
 TWOK 'A', 'N'          \
 TWOK 'T', 'I'          \ Encoded as:   "<154><155><151>TY"
 CHAR 'T'
 CHAR 'Y'
 EQUB 0

 TWOK 'A', 'N'          \ Token 17:     "ANARCHY"
 TWOK 'A', 'R'          \
 CHAR 'C'               \ Encoded as:   "<155><138>CHY"
 CHAR 'H'
 CHAR 'Y'
 EQUB 0

 CHAR 'F'               \ Token 18:     "FEUDAL"
 CHAR 'E'               \
 CHAR 'U'               \ Encoded as:   "FEUD<128>"
 CHAR 'D'
 TWOK 'A', 'L'
 EQUB 0

 CHAR 'M'               \ Token 19:     "MULTI-GOVERNMENT"
 CHAR 'U'               \
 CHAR 'L'               \ Encoded as:   "MUL<151>-[2]"
 TWOK 'T', 'I'
 CHAR '-'
 RTOK 2
 EQUB 0

 TWOK 'D', 'I'          \ Token 20:     "DICTATORSHIP"
 CHAR 'C'               \
 CHAR 'T'               \ Encoded as:   "<141>CT<145><153>[25]"
 TWOK 'A', 'T'
 TWOK 'O', 'R'
 RTOK 25
 EQUB 0

 RTOK 91                \ Token 21:     "COMMUNIST"
 CHAR 'M'               \
 CHAR 'U'               \ Encoded as:   "[91]MUN<157>T"
 CHAR 'N'
 TWOK 'I', 'S'
 CHAR 'T'
 EQUB 0

 CHAR 'C'               \ Token 22:     "CONFEDERACY"
 TWOK 'O', 'N'          \
 CHAR 'F'               \ Encoded as:   "C<159>F<152><144>ACY"
 TWOK 'E', 'D'
 TWOK 'E', 'R'
 CHAR 'A'
 CHAR 'C'
 CHAR 'Y'
 EQUB 0

 CHAR 'D'               \ Token 23:     "DEMOCRACY"
 CHAR 'E'               \
 CHAR 'M'               \ Encoded as:   "DEMOC<148>CY"
 CHAR 'O'
 CHAR 'C'
 TWOK 'R', 'A'
 CHAR 'C'
 CHAR 'Y'
 EQUB 0

 CHAR 'C'               \ Token 24:     "CORPORATE STATE"
 TWOK 'O', 'R'          \
 CHAR 'P'               \ Encoded as:   "C<153>P<153><145>E [43]<145>E"
 TWOK 'O', 'R'
 TWOK 'A', 'T'
 CHAR 'E'
 CHAR ' '
 RTOK 43
 TWOK 'A', 'T'
 CHAR 'E'
 EQUB 0

 CHAR 'S'               \ Token 25:     "SHIP"
 CHAR 'H'               \
 CHAR 'I'               \ Encoded as:   "SHIP"
 CHAR 'P'
 EQUB 0

 CHAR 'P'               \ Token 26:     "PRODUCT"
 CHAR 'R'               \
 CHAR 'O'               \ Encoded as:   "PRODUCT"
 CHAR 'D'
 CHAR 'U'
 CHAR 'C'
 CHAR 'T'
 EQUB 0

 CHAR ' '               \ Token 27:     " LASER"
 TWOK 'L', 'A'          \
 CHAR 'S'               \ Encoded as:   " <149>S<144>"
 TWOK 'E', 'R'
 EQUB 0

 CHAR 'H'               \ Token 28:     "HUMAN COLONIAL"
 CHAR 'U'               \
 CHAR 'M'               \ Encoded as:   "HUM<155> COL<159>I<128>"
 TWOK 'A', 'N'
 CHAR ' '
 CHAR 'C'
 CHAR 'O'
 CHAR 'L'
 TWOK 'O', 'N'
 CHAR 'I'
 TWOK 'A', 'L'
 EQUB 0

 CHAR 'H'               \ Token 29:     "HYPERSPACE "
 CHAR 'Y'               \
 CHAR 'P'               \ Encoded as:   "HYP<144>SPA<133> "
 TWOK 'E', 'R'
 CHAR 'S'
 CHAR 'P'
 CHAR 'A'
 TWOK 'C', 'E'
 CHAR ' '
 EQUB 0

 CHAR 'S'               \ Token 30:     "SHORT RANGE CHART"
 CHAR 'H'               \
 TWOK 'O', 'R'          \ Encoded as:   "SH<153>T [42][1]"
 CHAR 'T'
 CHAR ' '
 RTOK 42
 RTOK 1
 EQUB 0

 TWOK 'D', 'I'          \ Token 31:     "DISTANCE"
 RTOK 43                \
 TWOK 'A', 'N'          \ Encoded as:   "<141>[43]<155><133>"
 TWOK 'C', 'E'
 EQUB 0
Download .txt
gitextract_xn5smrlz/

├── .gitattributes
├── .gitignore
├── 1-source-files/
│   ├── README.md
│   ├── basic-programs/
│   │   └── README.md
│   ├── boot-files/
│   │   └── README.md
│   ├── images/
│   │   └── README.md
│   ├── main-sources/
│   │   ├── README.md
│   │   ├── elite-bcfs.asm
│   │   ├── elite-build-options.asm
│   │   ├── elite-disc.asm
│   │   ├── elite-loader.asm
│   │   ├── elite-readme.asm
│   │   └── elite-source.asm
│   └── original-sources/
│       ├── $.DEFEDIT.inf
│       ├── $.DEFEDIT.txt
│       ├── $.DEFGEN.inf
│       ├── $.DEFGEN.txt
│       ├── $.DEFTRAN.inf
│       ├── $.DEFTRAN.txt
│       ├── $.DIALGEN.inf
│       ├── $.DIALGEN.txt
│       ├── $.ELITEA.inf
│       ├── $.ELITEA.txt
│       ├── $.ELITEB.inf
│       ├── $.ELITEB.txt
│       ├── $.ELITEC.inf
│       ├── $.ELITEC.txt
│       ├── $.ELITED.inf
│       ├── $.ELITED.txt
│       ├── $.ELITEE.inf
│       ├── $.ELITEE.txt
│       ├── $.ELITEF.inf
│       ├── $.ELITEF.txt
│       ├── $.ELITEG.inf
│       ├── $.ELITEG.txt
│       ├── $.ELITES.inf
│       ├── $.ELITES.txt
│       ├── $.FINDSC2.inf
│       ├── $.FINDSC2.txt
│       ├── $.GENTOK.inf
│       ├── $.GENTOK.txt
│       ├── $.GETBIT.inf
│       ├── $.GETBIT.txt
│       ├── $.MAKER.inf
│       ├── $.MAKER.txt
│       ├── $.SBLOCK.inf
│       ├── $.SBLOCK.txt
│       ├── $.SFTPROT.inf
│       ├── $.SFTPROT.txt
│       ├── $.SHPPRTE.inf
│       ├── $.SHPPRTE.txt
│       ├── $.TOKPRI.inf
│       ├── $.TOKPRI.txt
│       ├── $.UNPACK.inf
│       ├── $.UNPACK.txt
│       ├── A.GENTOK.inf
│       ├── A.GENTOK.txt
│       ├── O.ELITED.inf
│       ├── O.ELITED.txt
│       ├── README.md
│       ├── S.BCFS.inf
│       ├── S.BCFS.txt
│       ├── S.GENTOK.inf
│       ├── S.GENTOK.txt
│       ├── S.STEST.inf
│       ├── S.STEST.txt
│       └── text-sources/
│           ├── ELITEA.txt
│           ├── ELITEB.txt
│           ├── ELITEC.txt
│           ├── ELITED.txt
│           ├── ELITEE.txt
│           ├── ELITEF.txt
│           └── ELITEG.txt
├── 2-build-files/
│   ├── README.md
│   ├── crc32.py
│   ├── elite-checksum.py
│   ├── elite-decrypt.py
│   ├── mktibet-0.3.php
│   └── tibetuef-0.8.php
├── 3-assembled-output/
│   ├── README.md
│   ├── README.txt
│   └── compile.txt
├── 4-reference-binaries/
│   └── README.md
├── 5-compiled-game-discs/
│   ├── README.md
│   ├── elite-cassette-from-source-disc.ssd
│   ├── elite-cassette-from-text-sources.ssd
│   ├── elite-cassette-sth.ssd
│   └── elite-cassette-sth.uef
├── Makefile
├── README.md
└── make.bat
Download .txt
SYMBOL INDEX (71 symbols across 3 files)

FILE: 2-build-files/crc32.py
  function main (line 21) | def main():

FILE: 2-build-files/mktibet-0.3.php
  class FileOpts (line 64) | class FileOpts {
    method __construct (line 76) | function __construct() {
    method to_string (line 87) | function to_string() : string {
  class TibetFile (line 100) | class TibetFile {
    method __construct (line 108) | function __construct (int $baud) {
    method to_string (line 118) | function to_string() : string {
  function process (line 129) | function process(array $argv) {
  function build_tibet (line 168) | function build_tibet (array $files, string &$out) : int {
  function tibet_encode (line 219) | function tibet_encode (string $in, int $baud, bool $baud_changed, string...
  function build_block (line 248) | function build_block (int $bn,
  function acorn_crc (line 274) | function acorn_crc (string $s) : int {
  function to_be16 (line 300) | function to_be16 (int $i) : string {
  function to_le16 (line 308) | function to_le16 (int $i) : string {
  function to_le32 (line 316) | function to_le32 (int $i) : string {
  function load_files (line 326) | function load_files (array &$files) : int {
  function fill_missing_names (line 345) | function fill_missing_names (array &$a) : int {
  function parse_cli (line 359) | function parse_cli (array $argv, array &$files, string &$tibet_fn) : int {
  function check_mos_filename (line 475) | function check_mos_filename (string $v) : int {
  function cli_parse_baud (line 494) | function cli_parse_baud (string $v, int &$baud_out) : int {
  function cli_parse_x32 (line 507) | function cli_parse_x32 (string $v, int &$out) : int {
  function usage (line 542) | function usage (string $argv0) {

FILE: 2-build-files/tibetuef-0.8.php
  class Span (line 61) | class Span {
  class TimeHint (line 66) | class TimeHint extends Span {
  class ParsedTibet (line 70) | class ParsedTibet {
    method __construct (line 73) | function __construct() {
  class TibetSilence (line 79) | class TibetSilence extends Span {
  class TibetLeader (line 83) | class TibetLeader extends Span {
  class DataFraming (line 87) | class DataFraming extends Span {
    method to_string (line 92) | function to_string() : string {
    method __construct (line 95) | function __construct() {
  class BaudRate (line 103) | class BaudRate extends Span {
    method to_string (line 105) | function to_string() : string {
    method __construct (line 108) | function __construct() {
  class TibetData (line 114) | class TibetData extends Span {
    method __construct (line 119) | function __construct() {
  class TibetCycle (line 126) | class TibetCycle extends Span {
  class DummyByte (line 130) | class DummyByte extends Span {
  function tbt_main (line 142) | function tbt_main ($argc, $argv) : int {
  function spans_fix_up_long_leader (line 340) | function spans_fix_up_long_leader (ParsedTibet &$tbt) : int {
  function print_chunk_messages (line 366) | function print_chunk_messages ($msg) {
  function cycles_to_bits (line 371) | function cycles_to_bits (ParsedTibet &$tbt) : int {
  function populate_framings_from_tibet (line 502) | function populate_framings_from_tibet (ParsedTibet &$tbt) : int {
  function spans_detect_and_convert_dummy_bits (line 726) | function spans_detect_and_convert_dummy_bits (ParsedTibet &$tbt) : int {
  function build_uef (line 807) | function build_uef (ParsedTibet $tbt,
  function build_dummy_byte (line 957) | function build_dummy_byte (DummyByte $db, string &$chunkbuf) : int {
  function build_uef_baud (line 962) | function build_uef_baud (int $baud, string &$chunkbuf) : int {
  function build_uef_leader (line 967) | function build_uef_leader (int $num_cycs, string &$chunkbuf) : int {
  function build_uef_silence_116 (line 972) | function build_uef_silence_116 (TibetSilence $tbs, string &$chunkbuf) : ...
  function build_uef_silence_112 (line 980) | function build_uef_silence_112 (TibetSilence $tbs, string &$uef, string ...
  function build_uef_squawk (line 998) | function build_uef_squawk (TibetData $tbd,
  function build_uef_data (line 1087) | function build_uef_data (TibetData $tbd,
  function build_uef_data_114 (line 1161) | function build_uef_data_114 (TibetData $tbd,
  function build_uef_data_100 (line 1211) | function build_uef_data_100 (TibetData $tbd,
  function build_uef_data_104 (line 1274) | function build_uef_data_104 (TibetData $tbd,
  function build_uef_data_102 (line 1425) | function build_uef_data_102 (TibetData $tbd,
  function check_parity (line 1559) | function check_parity (int $word, int $parity_bit, string $parity_mode) ...
  function frexp (line 1572) | function frexp ( $f, &$exponent) {
  function uef_float (line 1577) | function uef_float (float $f) : string {
  function wrap_chunk (line 1614) | function wrap_chunk (int $type, string $in, string &$msg) : string {
  function le16 (line 1626) | function le16 (int $i) : string {
  function le32 (line 1633) | function le32 (int $i) : string {
  function le24 (line 1642) | function le24 (int $i) : string {
  function process_line (line 1652) | function process_line (int $ln,
  function parse_float (line 1851) | function parse_float (string $w, float &$f) : int {
  function parse_int (line 1874) | function parse_int (string $w, int &$i) : int {
  function parse_framing (line 1890) | function parse_framing (string $w, DataFraming &$f) : int {
  function parse_baudrate (line 1907) | function parse_baudrate (string $w, BaudRate &$r) : int {
  function parse_version (line 1916) | function parse_version (array $words, int $ln, string &$tbt_version, str...
  function tbt_process (line 1942) | function tbt_process (string $ip, bool $insert_timestamps, ParsedTibet &...
  function usage (line 1960) | function usage(string $argv0) {
Condensed preview — 91 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (2,491K chars).
[
  {
    "path": ".gitattributes",
    "chars": 398,
    "preview": "# Auto detect text files and perform LF normalization\n* text=auto\n\n# Custom for Visual Studio\n*.cs     diff=csharp\n\n# St"
  },
  {
    "path": ".gitignore",
    "chars": 280,
    "preview": "# Windows thumbnail cache files\nThumbs.db\nehthumbs.db\nehthumbs_vista.db\n\n# Folder config file\nDesktop.ini\n\n# Recycle Bin"
  },
  {
    "path": "1-source-files/README.md",
    "chars": 634,
    "preview": "# Source files for the BBC Micro cassette version of Elite\n\nThis folder contains the source files for the BBC Micro cass"
  },
  {
    "path": "1-source-files/basic-programs/README.md",
    "chars": 672,
    "preview": "# BASIC programs for the BBC Micro cassette version of Elite\n\nThis folder contains the BASIC programs from the original "
  },
  {
    "path": "1-source-files/boot-files/README.md",
    "chars": 311,
    "preview": "# Boot files for the BBC Micro cassette version of Elite\n\nThis folder contains the boot file from the original sources f"
  },
  {
    "path": "1-source-files/images/README.md",
    "chars": 569,
    "preview": "# Image binaries for the BBC Micro cassette version of Elite\n\nThis folder contains the image binaries from the original "
  },
  {
    "path": "1-source-files/main-sources/README.md",
    "chars": 972,
    "preview": "# Annotated source code for the BBC Micro cassette version of Elite\n\nThis folder contains the annotated source code for "
  },
  {
    "path": "1-source-files/main-sources/elite-bcfs.asm",
    "chars": 8107,
    "preview": "\\ ******************************************************************************\n\\\n\\ BBC MICRO CASSETTE ELITE BIG CODE F"
  },
  {
    "path": "1-source-files/main-sources/elite-build-options.asm",
    "chars": 90,
    "preview": "_VERSION=1\n_VARIANT=3\n_REMOVE_CHECKSUMS=FALSE\n_MAX_COMMANDER=FALSE\n_DISC=TRUE\n_PROT=FALSE\n"
  },
  {
    "path": "1-source-files/main-sources/elite-disc.asm",
    "chars": 2419,
    "preview": "\\ ******************************************************************************\n\\\n\\ BBC MICRO CASSETTE ELITE DISC IMAGE"
  },
  {
    "path": "1-source-files/main-sources/elite-loader.asm",
    "chars": 125138,
    "preview": "\\ ******************************************************************************\n\\\n\\ BBC MICRO CASSETTE ELITE GAME LOADE"
  },
  {
    "path": "1-source-files/main-sources/elite-readme.asm",
    "chars": 1997,
    "preview": "\\ ******************************************************************************\n\\\n\\ BBC MICRO CASSETTE ELITE README SOU"
  },
  {
    "path": "1-source-files/main-sources/elite-source.asm",
    "chars": 1480879,
    "preview": "\\ ******************************************************************************\n\\\n\\ BBC MICRO CASSETTE ELITE MAIN GAME "
  },
  {
    "path": "1-source-files/original-sources/$.DEFEDIT.inf",
    "chars": 31,
    "preview": "$.DEFEDIT 000000 000000 000557\n"
  },
  {
    "path": "1-source-files/original-sources/$.DEFEDIT.txt",
    "chars": 1310,
    "preview": "   10 REM DEFSHIP EDITOR\n   20 MODE7:@%=3\n   30 PROCPR(\"        DEFSHIP  EDITOR\",3,1)\n   40 INPUT''\"Input filename of DE"
  },
  {
    "path": "1-source-files/original-sources/$.DEFGEN.inf",
    "chars": 31,
    "preview": "$.DEFGEN  000000 000000 0006BB\n"
  },
  {
    "path": "1-source-files/original-sources/$.DEFGEN.txt",
    "chars": 1710,
    "preview": ">LIST\n\r   10 REM DEFSHIP EDITOR\n\r   20 MODE7:@%=3:*OPT1,2\n\r   30 PROCPR(\"      DEFSHIP  GENERATOR\",3,1)\n\r   40 INPUT''\"I"
  },
  {
    "path": "1-source-files/original-sources/$.DEFTRAN.inf",
    "chars": 31,
    "preview": "$.DEFTRAN 000000 000000 0007C4\n"
  },
  {
    "path": "1-source-files/original-sources/$.DEFTRAN.txt",
    "chars": 1978,
    "preview": ">LIST\n\r   10 REM DEFSHIP EDITOR\n\r   20 MODE7:@%=3\n\r   30 PROCPR(\"        DEFSHIP  EDITOR\",3,1)\n\r   40 INPUT''\"Input file"
  },
  {
    "path": "1-source-files/original-sources/$.DIALGEN.inf",
    "chars": 31,
    "preview": "$.DIALGEN 000000 000000 00048D\n"
  },
  {
    "path": "1-source-files/original-sources/$.DIALGEN.txt",
    "chars": 1124,
    "preview": "   10 REM Generate new DIALS bitdump\n   20 \n   30 XMAX=68*4:YMAX=18*4: REM Ellipse\n   32 CYC=53*4:CXC=196*4:RD=11*4\n   3"
  },
  {
    "path": "1-source-files/original-sources/$.ELITEA.inf",
    "chars": 31,
    "preview": "$.ELITEA  000000 000000 002FA2\n"
  },
  {
    "path": "1-source-files/original-sources/$.ELITEA.txt",
    "chars": 12047,
    "preview": "    1GOTO20\n    2*L.ELITEB\n    3GOTO20\n    4*L.ELITEA\n    5GOTO120\n   20REM ELITE <A>\n   30MODE7:VDU28,0,23,39,19\n   40L"
  },
  {
    "path": "1-source-files/original-sources/$.ELITEB.inf",
    "chars": 31,
    "preview": "$.ELITEB  000000 000000 002D20\n"
  },
  {
    "path": "1-source-files/original-sources/$.ELITEB.txt",
    "chars": 11373,
    "preview": "    1GOTO20\n    2*L.ELITEB\n    3GOTO20\n    4*L.ELITEA\n    6*L.ELITEC\n   20REM ELITE <B>\n 1000O%=W%:H%=L%+P%-C%:Q%=FALSE\n"
  },
  {
    "path": "1-source-files/original-sources/$.ELITEC.inf",
    "chars": 31,
    "preview": "$.ELITEC  000000 000000 002F56\n"
  },
  {
    "path": "1-source-files/original-sources/$.ELITEC.txt",
    "chars": 11942,
    "preview": "    1GOTO20\n    2*L.ELITEB\n    3GOTO20\n    4*L.ELITEA\n    6*L.ELITEC\n    7GOTO20\n    8*L.ELITED\n   20REM ELITE <C>\n 1000"
  },
  {
    "path": "1-source-files/original-sources/$.ELITED.inf",
    "chars": 31,
    "preview": "$.ELITED  000000 000000 002E49\n"
  },
  {
    "path": "1-source-files/original-sources/$.ELITED.txt",
    "chars": 11684,
    "preview": "    1GOTO20\n    2*L.ELITEB\n    3GOTO20\n    4*L.ELITEA\n    6*L.ELITEC\n    7GOTO20\n    8*L.ELITED\n    9GOTO20\n   10*L.ELIT"
  },
  {
    "path": "1-source-files/original-sources/$.ELITEE.inf",
    "chars": 31,
    "preview": "$.ELITEE  000000 000000 002DDB\n"
  },
  {
    "path": "1-source-files/original-sources/$.ELITEE.txt",
    "chars": 11593,
    "preview": "    1GOTO20\n    2*L.ELITEB\n    3GOTO20\n    4*L.ELITEA\n    6*L.ELITEC\n    7GOTO20\n    8*L.ELITED\n    9GOTO20\n   10*L.ELIT"
  },
  {
    "path": "1-source-files/original-sources/$.ELITEF.inf",
    "chars": 31,
    "preview": "$.ELITEF  000000 000000 002ED2\n"
  },
  {
    "path": "1-source-files/original-sources/$.ELITEF.txt",
    "chars": 11828,
    "preview": "    1GOTO20\n    2*L.ELITEB\n    3GOTO20\n    4*L.ELITEA\n    6*L.ELITEC\n    7GOTO20\n    8*L.ELITED\n    9GOTO20\n   10*L.ELIT"
  },
  {
    "path": "1-source-files/original-sources/$.ELITEG.inf",
    "chars": 31,
    "preview": "$.ELITEG  000000 000000 002EDB\n"
  },
  {
    "path": "1-source-files/original-sources/$.ELITEG.txt",
    "chars": 11757,
    "preview": "    1GOTO20\n    2*L.ELITEB\n    3GOTO20\n    4*L.ELITEA\n    6*L.ELITEC\n    7GOTO20\n    8*L.ELITED\n    9GOTO20\n   10*L.ELIT"
  },
  {
    "path": "1-source-files/original-sources/$.ELITES.inf",
    "chars": 31,
    "preview": "$.ELITES  000000 000000 002B49\n"
  },
  {
    "path": "1-source-files/original-sources/$.ELITES.txt",
    "chars": 10913,
    "preview": "    1 DISC=TRUE:PROT=(NOT DISC)\n    5REM Source Code for ELITE  (the loader)\n    7MODE7\n    8HIMEM=&4000:CODE=&4000:DIMT"
  },
  {
    "path": "1-source-files/original-sources/$.FINDSC2.inf",
    "chars": 31,
    "preview": "$.FINDSC2 000000 000000 0004FB\n"
  },
  {
    "path": "1-source-files/original-sources/$.FINDSC2.txt",
    "chars": 1237,
    "preview": "   10 REM FIND SOURCE\n   20 R=&76:S=&77:T=&78:J=&79:Q=&7A:FL=&7B\n   40 ctl=&70:add=&74:OSARGS=&FFDA:page=24:OSWRCH=&FFEE"
  },
  {
    "path": "1-source-files/original-sources/$.GENTOK.inf",
    "chars": 31,
    "preview": "$.GENTOK  000000 000000 000931\n"
  },
  {
    "path": "1-source-files/original-sources/$.GENTOK.txt",
    "chars": 2314,
    "preview": "   10 REM Generate TOKENS file\n   20 words=OPENOUT\"WORDS9\"\n   30 ONERRORGOTO150\n   40 REPEATREADA$:FORN%=1TOLENA$:CH%=AS"
  },
  {
    "path": "1-source-files/original-sources/$.GETBIT.inf",
    "chars": 31,
    "preview": "$.GETBIT  000000 000000 0000A1\n"
  },
  {
    "path": "1-source-files/original-sources/$.GETBIT.txt",
    "chars": 141,
    "preview": "   10 *LOAD :2.O.NDIALS 7600\n   20 *LOAD O.DIALSHP 6800\n   30 FORJ%=0TO255STEP4:!(J%+&7EC0)=!(J%+&6F00):NEXT\n   40 *SAVE"
  },
  {
    "path": "1-source-files/original-sources/$.MAKER.inf",
    "chars": 31,
    "preview": "$.MAKER   000000 000000 00023F\n"
  },
  {
    "path": "1-source-files/original-sources/$.MAKER.txt",
    "chars": 543,
    "preview": "    5 HIMEM=&7A00\n   10  REM Create an ELITE software protected file set on cassette\n   12 ON ERROR GOTO 500\n   20 *DISC"
  },
  {
    "path": "1-source-files/original-sources/$.SBLOCK.inf",
    "chars": 31,
    "preview": "$.SBLOCK  000000 000000 0003E1\n"
  },
  {
    "path": "1-source-files/original-sources/$.SBLOCK.txt",
    "chars": 942,
    "preview": "    5REM Prepare DEFAULT and UNIV and serve with WORDS9\n    7MODE0\n   10NA%=&780:POW=15:K%=&C00:NI%=36\n  100GOSUB 1000\n "
  },
  {
    "path": "1-source-files/original-sources/$.SFTPROT.inf",
    "chars": 31,
    "preview": "$.SFTPROT 000000 000000 000215\n"
  },
  {
    "path": "1-source-files/original-sources/$.SFTPROT.txt",
    "chars": 508,
    "preview": "   10 REM SOFTWARE PROTECTION\n   20 REM USING OSFILE\n   25 FILEV=&212:IRQ2=&206:BFLAG=&3CA:USVIA=&FE60\n   30 P%=&C00:[\n "
  },
  {
    "path": "1-source-files/original-sources/$.SHPPRTE.inf",
    "chars": 31,
    "preview": "$.SHPPRTE 000000 000000 000640\n"
  },
  {
    "path": "1-source-files/original-sources/$.SHPPRTE.txt",
    "chars": 1553,
    "preview": "    1REM  Prepare DIALSHP and SHIPS\n    2MODE1\n    5D%=&5490\n   10HIMEM=&2000\n   18*LOAD DMPDIAL\n   20READN%:C%=D%:B%=&7"
  },
  {
    "path": "1-source-files/original-sources/$.TOKPRI.inf",
    "chars": 31,
    "preview": "$.TOKPRI  000000 000000 0004B1\n"
  },
  {
    "path": "1-source-files/original-sources/$.TOKPRI.txt",
    "chars": 1200,
    "preview": ">LIST\n\r  100GOSUB1000\n\r  110FORA%=96TO125:PRINTA%\" \";:CALLTT27:PRINT:NEXT\n\r  120FORA%=129TO255:PRINTA%\" \";:CALLTT27:PRIN"
  },
  {
    "path": "1-source-files/original-sources/$.UNPACK.inf",
    "chars": 31,
    "preview": "$.UNPACK  000000 000000 00045D\n"
  },
  {
    "path": "1-source-files/original-sources/$.UNPACK.txt",
    "chars": 1078,
    "preview": "   10 REM  Unpack an ELITE security number\n   20 REM  This works for either disc or tape copies\n   30 REM  This program "
  },
  {
    "path": "1-source-files/original-sources/A.GENTOK.inf",
    "chars": 31,
    "preview": "$.GENTOKA 000000 000000 000B18\n"
  },
  {
    "path": "1-source-files/original-sources/A.GENTOK.txt",
    "chars": 2799,
    "preview": "   10 REM Generate TOKENS file\n   20 words=OPENOUT\"WORDS9\"\n   30 ONERRORGOTO150\n   40 REPEATREADA$:FORN%=1TOLENA$:CH%=AS"
  },
  {
    "path": "1-source-files/original-sources/O.ELITED.inf",
    "chars": 31,
    "preview": "$.ELITEDO 000000 000000 002E8C\n"
  },
  {
    "path": "1-source-files/original-sources/O.ELITED.txt",
    "chars": 11750,
    "preview": "    1GOTO20\n    2*L.ELITEB\n    3GOTO20\n    4*L.ELITEA\n    6*L.ELITEC\n    7GOTO20\n    8*L.ELITED\n    9GOTO20\n   10*L.ELIT"
  },
  {
    "path": "1-source-files/original-sources/README.md",
    "chars": 233,
    "preview": "# Original source code for the BBC Micro cassette version of Elite\n\nThis folder contains the original source code for th"
  },
  {
    "path": "1-source-files/original-sources/S.BCFS.inf",
    "chars": 31,
    "preview": "S.BCFS    000000 000000 000380\n"
  },
  {
    "path": "1-source-files/original-sources/S.BCFS.txt",
    "chars": 857,
    "preview": "   10REM    Prepare the Big Code File\n   20 \n   25REM          ELTcode\n   30 \n   35REM   (a provisional name, ahem)\n   4"
  },
  {
    "path": "1-source-files/original-sources/S.GENTOK.inf",
    "chars": 31,
    "preview": "$.GENTOKS 000000 000000 000B1F\n"
  },
  {
    "path": "1-source-files/original-sources/S.GENTOK.txt",
    "chars": 2806,
    "preview": "   10 REM Generate TOKENS file\n   20 words=OPENOUT\"WORDS9\"\n   30 ONERRORGOTO150\n   40 REPEATREADA$:FORN%=1TOLENA$:CH%=AS"
  },
  {
    "path": "1-source-files/original-sources/S.STEST.inf",
    "chars": 31,
    "preview": "$.STEST   000000 000000 0012D3\n"
  },
  {
    "path": "1-source-files/original-sources/S.STEST.txt",
    "chars": 4705,
    "preview": "    5REM Source Code for Loader\n   10C%=&F40:S%=C%:L%=&1128:D%=&563A:LC%=&6000-C%:svn=&7FFD\n   20MOS=S%+8:TRTB%=4\n  100D"
  },
  {
    "path": "1-source-files/original-sources/text-sources/ELITEA.txt",
    "chars": 12047,
    "preview": "    1GOTO20\n    2*L.ELITEB\n    3GOTO20\n    4*L.ELITEA\n    5GOTO120\n   20REM ELITE <A>\n   30MODE7:VDU28,0,23,39,19\n   40L"
  },
  {
    "path": "1-source-files/original-sources/text-sources/ELITEB.txt",
    "chars": 11382,
    "preview": "    1GOTO20\n    2*L.ELITEB\n    3GOTO20\n    4*L.ELITEA\n    6*L.ELITEC\n   20REM ELITE <B>\n 1000O%=W%:H%=L%+P%-C%:Q%=FALSE\n"
  },
  {
    "path": "1-source-files/original-sources/text-sources/ELITEC.txt",
    "chars": 11935,
    "preview": "    1GOTO20\n    2*L.ELITEB\n    3GOTO20\n    4*L.ELITEA\n    6*L.ELITEC\n    7GOTO20\n    8*L.ELITED\n   20REM ELITE <C>\n 1000"
  },
  {
    "path": "1-source-files/original-sources/text-sources/ELITED.txt",
    "chars": 11693,
    "preview": "    1GOTO20\n    2*L.ELITEB\n    3GOTO20\n    4*L.ELITEA\n    6*L.ELITEC\n    7GOTO20\n    8*L.ELITED\n    9GOTO20\n   10*L.ELIT"
  },
  {
    "path": "1-source-files/original-sources/text-sources/ELITEE.txt",
    "chars": 11593,
    "preview": "    1GOTO20\n    2*L.ELITEB\n    3GOTO20\n    4*L.ELITEA\n    6*L.ELITEC\n    7GOTO20\n    8*L.ELITED\n    9GOTO20\n   10*L.ELIT"
  },
  {
    "path": "1-source-files/original-sources/text-sources/ELITEF.txt",
    "chars": 11827,
    "preview": "    1GOTO20\n    2*L.ELITEB\n    3GOTO20\n    4*L.ELITEA\n    6*L.ELITEC\n    7GOTO20\n    8*L.ELITED\n    9GOTO20\n   10*L.ELIT"
  },
  {
    "path": "1-source-files/original-sources/text-sources/ELITEG.txt",
    "chars": 11757,
    "preview": "    1GOTO20\n    2*L.ELITEB\n    3GOTO20\n    4*L.ELITEA\n    6*L.ELITEC\n    7GOTO20\n    8*L.ELITED\n    9GOTO20\n   10*L.ELIT"
  },
  {
    "path": "2-build-files/README.md",
    "chars": 867,
    "preview": "# Build files for the BBC Micro cassette version of Elite\n\nThis folder contains support scripts for building the BBC Mic"
  },
  {
    "path": "2-build-files/crc32.py",
    "chars": 4248,
    "preview": "#!/usr/bin/env python\n#\n# ******************************************************************************\n#\n# ELITE VERIF"
  },
  {
    "path": "2-build-files/elite-checksum.py",
    "chars": 6764,
    "preview": "#!/usr/bin/env python\n#\n# ******************************************************************************\n#\n# CASSETTE EL"
  },
  {
    "path": "2-build-files/elite-decrypt.py",
    "chars": 4934,
    "preview": "#!/usr/bin/env python\n#\n# ******************************************************************************\n#\n# CASSETTE EL"
  },
  {
    "path": "2-build-files/mktibet-0.3.php",
    "chars": 15388,
    "preview": "<?php\n\n/*\n *  Quadbike 2\n *  Copyright (C) 2023 'Diminished'\n\n *  This program is free software; you can redistribute it"
  },
  {
    "path": "2-build-files/tibetuef-0.8.php",
    "chars": 61222,
    "preview": "<?php\n\n/*\n *  Quadbike 2\n *  Copyright (C) 2024 'Diminished'\n\n *  This program is free software; you can redistribute it"
  },
  {
    "path": "3-assembled-output/README.md",
    "chars": 367,
    "preview": "# Assembled output for the BBC Micro cassette version of Elite\n\nThis folder contains the output binaries from the build "
  },
  {
    "path": "3-assembled-output/README.txt",
    "chars": 230,
    "preview": "\n\r---------------------------------------\n\rAcornsoft Elite\n\r\n\rVersion: BBC Micro cassette\n\rVariant: Stairway to Hell cas"
  },
  {
    "path": "3-assembled-output/compile.txt",
    "chars": 413354,
    "preview": ".ZP\n     0000\n.RAND\n     0000\n.TRTB%\n     0004\n.T1\n     0006\n.SC\n     0007\n.SCH\n     0008\n.XX16\n     0009\n.P\n     001B\n."
  },
  {
    "path": "4-reference-binaries/README.md",
    "chars": 725,
    "preview": "# Reference binaries for the BBC Micro cassette version of Elite\n\nThis folder contains the binaries from the original so"
  },
  {
    "path": "5-compiled-game-discs/README.md",
    "chars": 559,
    "preview": "# Compiled game discs for the BBC Micro cassette version of Elite\n\nThis folder contains the SSD disc images for the BBC "
  },
  {
    "path": "Makefile",
    "chars": 4731,
    "preview": "BEEBASM?=beebasm\nPYTHON?=python\nPHP?=php\n\n# A make command with no arguments will build the source disc variant with\n# e"
  },
  {
    "path": "README.md",
    "chars": 32664,
    "preview": "# Fully documented source code for the cassette version of Elite on the BBC Micro\n\n<details>\n<summary>Links to my other "
  },
  {
    "path": "make.bat",
    "chars": 155,
    "preview": "@echo off\nSETLOCAL\nSET BEEBASM=C:\\Users\\user\\bin\\beebasm.exe\nSET PYTHON=C:\\Users\\user\\AppData\\Local\\Microsoft\\WindowsApp"
  }
]

// ... and 4 more files (download for full content)

About this extraction

This page contains the full source code of the markmoxon/elite-beebasm GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 91 files (2.3 MB), approximately 600.2k tokens, and a symbol index with 71 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!