Skip to navigation

Elite on the BBC Micro

Elite F encyclopedia source [Elite-A]

ELITE F FILE
CODE_F% = P% LOAD_F% = LOAD% + P% - CODE%
Name: SFX [Show more] Type: Variable Category: Sound Summary: Sound data
Context: See this variable on its own page References: This variable is used as follows: * NOS1 calls SFX

Sound data. To make a sound, the NOS1 routine copies the four relevant sound bytes to XX16, and NO3 then makes the sound. The sound numbers are shown in the table, and are always multiples of 8. Generally, sounds are made by calling the NOISE routine with the sound number in A. These bytes are passed to OSWORD 7, and are the equivalents to the parameters passed to the SOUND keyword in BASIC. The parameters therefore have these meanings: channel/flush, amplitude (or envelope number if 1-4), pitch, duration For the channel/flush parameter, the first byte is the channel while the second is the flush control (where a flush control of 0 queues the sound, while a flush control of 1 makes the sound instantly). When written in hexadecimal, the first figure gives the flush control, while the second is the channel (so &13 indicates flush control = 1 and channel = 3). So when we call NOISE with A = 40 to make a long, low beep, then this is effectively what the NOISE routine does: SOUND &13, &F4, &0C, &08 which makes a sound with flush control 1 on channel 3, and with amplitude &F4 (-12), pitch &0C (2) and duration &08 (8). Meanwhile, to make the hyperspace sound, the NOISE routine does this: SOUND &10, &02, &60, &10 which makes a sound with flush control 1 on channel 0, using envelope 2, and with pitch &60 (96) and duration &10 (16). The four sound envelopes (1-4) are set up by the loading process.
.SFX EQUB &12,&01,&00,&10 \ 0 - Lasers fired by us EQUB &12,&02,&2C,&08 \ 8 - We're being hit by lasers EQUB &11,&03,&F0,&18 \ 16 - We died 1 / We made a hit or kill 2 EQUB &10,&F1,&07,&1A \ 24 - We died 2 / We made a hit or kill 1 EQUB &03,&F1,&BC,&01 \ 32 - Short, high beep EQUB &13,&F4,&0C,&08 \ 40 - Long, low beep EQUB &10,&F1,&06,&0C \ 48 - Missile launched / Ship launched from station EQUB &10,&02,&60,&10 \ 56 - Hyperspace drive engaged EQUB &13,&04,&C2,&FF \ 64 - E.C.M. on EQUB &13,&00,&00,&00 \ 72 - E.C.M. off
Name: RES2 [Show more] Type: Subroutine Category: Start and end Summary: Reset a number of flight variables and workspaces
Context: See this subroutine on its own page References: This subroutine is called as follows: * DEATH2 calls RES2 * DOENTRY calls RES2

This is called after we launch from a space station, arrive in a new system after hyperspace, launch an escape pod, or die a cold, lonely death in the depths of space. Returns: Y Y is set to &FF
.RES2 LDA #NOST \ Reset NOSTM, the number of stardust particles, to the STA NOSTM \ maximum allowed (18) LDX #&FF \ Reset LSX2 and LSY2, the ball line heaps used by the STX LSX2 \ BLINE routine for drawing circles, to &FF, to set the STX LSY2 \ heap to empty STX MSTG \ Reset MSTG, the missile target, to &FF (no target) LDA #128 \ Set the current pitch rate to the mid-point, 128 STA JSTY STA ALP2 \ Reset ALP2 (roll sign) and BET2 (pitch sign) STA BET2 \ to negative, i.e. pitch and roll negative ASL A \ This sets A to 0 STA ALP2+1 \ Reset ALP2+1 (flipped roll sign) and BET2+1 (flipped STA BET2+1 \ pitch sign) to positive, i.e. pitch and roll negative STA MCNT \ Reset MCNT (the main loop counter) to 0 \ --- Mod: Original Acornsoft code removed: -----------> \.modify \ --- End of removed code -----------------------------> LDA #3 \ Reset DELTA (speed) to 3 STA DELTA STA ALPHA \ Reset ALPHA (roll angle alpha) to 3 STA ALP1 \ Reset ALP1 (magnitude of roll angle alpha) to 3 LDA ECMA \ Fetch the E.C.M. status flag, and if E.C.M. is off, BEQ yu \ skip the next instruction JSR ECMOF \ Turn off the E.C.M. sound .yu JSR WPSHPS \ Wipe all ships from the scanner JSR ZERO \ Zero-fill pages &9, &A, &B, &C and &D, which clears \ the ship data blocks, the ship line heap, the ship \ slots for the local bubble of universe, and various \ flight and ship status variables LDA #LO(LS%) \ We have reset the ship line heap, so we now point STA SLSP \ SLSP to LS% (the byte below the ship blueprints at D%) LDA #HI(LS%) \ to indicate that the heap is empty STA SLSP+1 \ --- Mod: Original Acornsoft code removed: -----------> \ JSR DIALS \ Update the dashboard \ --- End of removed code -----------------------------> \ Finally, fall through into ZINF to reset the INWK \ ship workspace
Name: ZINF [Show more] Type: Subroutine Category: Utility routines Summary: Reset the INWK workspace and orientation vectors Deep dive: Orientation vectors
Context: See this subroutine on its own page References: This subroutine is called as follows: * ships_ag calls ZINF

Zero-fill the INWK ship workspace and reset the orientation vectors, with nosev pointing out of the screen, towards us. Returns: Y Y is set to &FF
.ZINF LDY #NI%-1 \ There are NI% bytes in the INWK workspace, so set a \ counter in Y so we can loop through them LDA #0 \ Set A to 0 so we can zero-fill the workspace .ZI1 STA INWK,Y \ Zero the Y-th byte of the INWK workspace DEY \ Decrement the loop counter BPL ZI1 \ Loop back for the next byte, ending when we have \ zero-filled the last byte at INWK, which leaves Y \ with a value of &FF \ Finally, we reset the orientation vectors as follows: \ \ sidev = (1, 0, 0) \ roofv = (0, 1, 0) \ nosev = (0, 0, -1) \ \ 96 * 256 (&6000) represents 1 in the orientation \ vectors, while -96 * 256 (&E000) represents -1. We \ already set the vectors to zero above, so we just \ need to set up the high bytes of the diagonal values \ and we're done. The negative nosev makes the ship \ point towards us, as the z-axis points into the screen LDA #96 \ Set A to represent a 1 (in vector terms) STA INWK+18 \ Set byte #18 = roofv_y_hi = 96 = 1 STA INWK+22 \ Set byte #22 = sidev_x_hi = 96 = 1 ORA #128 \ Flip the sign of A to represent a -1 STA INWK+14 \ Set byte #14 = nosev_z_hi = -96 = -1 RTS \ Return from the subroutine
Name: me2 [Show more] Type: Subroutine Category: Text Summary: Remove an in-flight message from the space view
Context: See this subroutine on its own page References: This subroutine is called as follows: * Main game loop (Part 2 of 6) calls me2
.me2 LDA MCH \ Fetch the token number of the current message into A JSR MESS \ Call MESS to print the token, which will remove it \ from the screen as printing uses EOR logic LDA #0 \ Set the delay in DLY to 0, so any new in-flight STA DLY \ messages will be shown instantly JMP me3 \ Jump back into the main spawning loop at me3
Name: DORND [Show more] Type: Subroutine Category: Utility routines Summary: Generate random numbers Deep dive: Generating random numbers Fixing ship positions
Context: See this subroutine on its own page References: This subroutine is called as follows: * DETOK2 calls DORND * LL9 (Part 1 of 12) calls DORND * MT18 calls DORND * SUN (Part 3 of 4) calls DORND

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. If we want to generate a repeatable sequence of random numbers, when generating explosion clouds, for example, then we call DORND2 to ensure that the value of the C flag on entry doesn't affect the outcome, as otherwise we might not get the same sequence of numbers if the C flag changes.
\ --- Mod: Original Acornsoft code removed: -----------> \.DORND2 \ CLC \ Clear the C flag so the value of the C flag on entry \ \ doesn't affect the outcome \ --- End of removed code -----------------------------> .DORND LDA RAND \ Calculate the next two values f2 and f3 in the feeder ROL A \ sequence: TAX \ ADC RAND+2 \ * f2 = (f1 << 1) mod 256 + C flag on entry STA RAND \ * f3 = f0 + f2 + (1 if bit 7 of f1 is set) STX RAND+2 \ * C flag is set according to the f3 calculation LDA RAND+1 \ Calculate the next value m2 in the main sequence: TAX \ ADC RAND+3 \ * A = m2 = m0 + m1 + C flag from feeder calculation STA RAND+1 \ * X = m1 STX RAND+3 \ * C and V flags set according to the m2 calculation RTS \ Return from the subroutine
Name: Main game loop (Part 2 of 6) [Show more] Type: Subroutine Category: Main loop Summary: Update the main loop counters Deep dive: Program flow of the main game loop Ship data blocks Fixing ship positions
Context: See this subroutine on its own page References: This subroutine is called as follows: * Main game loop (Part 2 of 6) calls entry point me3 * me2 calls entry point me3 * Main game loop (Part 6 of 6) calls entry point TT100

In the encyclopedia code, we start the main game loop at part 2 and then jump straight to part 5, as parts 1, 3 and 4 are not required when we are docked. This section covers the following: * Update the main loop counters Other entry points: TT100 The entry point for the start of the main game loop, which calls the main flight loop and the moves into the spawning routine me3 Used by me2 to jump back into the main game loop after printing an in-flight message
.TT100 DEC DLY \ Decrement the delay counter in DLY, so any in-flight \ messages get removed once the counter reaches zero BEQ me2 \ If DLY is now 0, jump to me2 to remove any in-flight \ message from the space view, and once done, return to \ me3 below, skipping the following two instructions BPL me3 \ If DLY is positive, jump to me3 to skip the next \ instruction INC DLY \ If we get here, DLY is negative, so we have gone too \ and need to increment DLY back to 0 .me3 DEC MCNT \ Decrement the main loop counter in MCNT \ --- Mod: Original Acornsoft code removed: -----------> \ BEQ P%+5 \ If the counter has reached zero, which it will do \ \ every 256 main loops, skip the next JMP instruction \ \ (or to put it another way, if the counter hasn't \ \ reached zero, jump down to MLOOP, skipping all the \ \ following checks) \.ytq \ JMP MLOOP \ Jump down to MLOOP to do some end-of-loop tidying and \ \ restart the main loop \ \ We only get here once every 256 iterations of the \ \ main loop. If we aren't in witchspace and don't \ \ already have 3 or more asteroids in our local bubble, \ \ then this section has a 13% chance of spawning \ \ something benign (the other 87% of the time we jump \ \ down to consider spawning cops, pirates and bounty \ \ hunters) \ \ \ \ If we are in that 13%, then 50% of the time this will \ \ be a Cobra Mk III trader, and the other 50% of the \ \ time it will either be an asteroid (98.5% chance) or, \ \ very rarely, a cargo canister (1.5% chance) \ LDA MJ \ If we are in witchspace following a mis-jump, skip the \ BNE ytq \ following by jumping down to MLOOP (via ytq above) \ JSR DORND \ Set A and X to random numbers \ CMP #35 \ If A >= 35 (87% chance), jump down to MLOOP to skip \ BCS MLOOP \ the following \ LDA MANY+AST \ If we already have 3 or more asteroids in the local \ CMP #3 \ bubble, jump down to MLOOP to skip the following \ BCS MLOOP \ JSR ZINF \ Call ZINF to reset the INWK ship workspace \ LDA #38 \ Set z_hi = 38 (far away) \ STA INWK+7 \ JSR DORND \ Set A, X and C flag to random numbers \ STA INWK \ Set x_lo = random \ STX INWK+3 \ Set y_lo = random \ \ \ \ Note that because we use the value of X returned by \ \ DORND, and X contains the value of A returned by the \ \ previous call to DORND, this does not set the new ship \ \ to a totally random location. See the deep dive on \ \ "Fixing ship positions" for details \ AND #%10000000 \ Set x_sign = bit 7 of x_lo \ STA INWK+2 \ TXA \ Set y_sign = bit 7 of y_lo \ AND #%10000000 \ STA INWK+5 \ ROL INWK+1 \ Set bit 1 of x_hi to the C flag, which is random, so \ ROL INWK+1 \ this randomly moves us off-centre by 512 (as if x_hi \ \ is %00000010, then (x_hi x_lo) is 512 + x_lo) \ --- End of removed code -----------------------------> \ Fall through into part 5 (parts 3 and 4 are not \ required when we are docked)
Name: Main game loop (Part 5 of 6) [Show more] Type: Subroutine Category: Main loop Summary: Cool down lasers, make calls to update the dashboard Deep dive: Program flow of the main game loop The dashboard indicators
Context: See this subroutine on its own page References: This subroutine is called as follows: * Main game loop (Part 6 of 6) calls entry point MLOOP

This is the first half of the minimal game loop, which we iterate when we are docked. This section covers the following: * Cool down lasers * Make calls to update the dashboard Other entry points: MLOOP The entry point for the main game loop. This entry point comes after the call to the main flight loop and spawning routines, so it marks the start of the main game loop for when we are docked (as we don't need to call the main flight loop or spawning routines if we aren't in space)
.MLOOP 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 \ --- Mod: Original Acornsoft code removed: -----------> \ LDX GNTMP \ If the laser temperature in GNTMP is non-zero, \ BEQ EE20 \ decrement it (i.e. cool it down a bit) \ DEC GNTMP \.EE20 \ JSR DIALS \ Call DIALS to update the dashboard \ LDA QQ11 \ If this is a space view, skip the following two \ BEQ P%+7 \ instructions (i.e. jump to JSR TT17 below) \ --- End of removed code -----------------------------> LDY #2 \ Wait for 2/50 of a second (0.04 seconds), to slow the JSR DELAY \ main loop down a bit JSR TT17 \ Scan the keyboard for the cursor keys or joystick, \ returning the cursor's delta values in X and Y and \ the key pressed in A
Name: Main game loop (Part 6 of 6) [Show more] Type: Subroutine Category: Main loop Summary: Process non-flight key presses (red function keys, docked keys) Deep dive: Program flow of the main game loop
Context: See this subroutine on its own page References: This subroutine is called as follows: * BAY calls entry point FRCE * buy_invnt calls entry point FRCE

This is the second half of the minimal game loop, which we iterate when we are docked. This section covers the following: * Process more key presses (red function keys, docked keys etc.) It also support joining the main loop with a key already "pressed", so we can jump into the main game loop to perform a specific action. In practice, this is used when we enter the docking bay in BAY to display Status Mode (red key f8), and when we finish buying or selling cargo in BAY2 to jump to the Inventory (red key f9). Other entry points: FRCE The entry point for the main game loop if we want to jump straight to a specific screen, by pretending to "press" a key, in which case A contains the internal key number of the key we want to "press"
.FRCE JSR TT102 \ Call TT102 to process the key pressed in A LDA QQ12 \ Fetch the docked flag from QQ12 into A BNE MLOOP \ If we are docked, loop back up to MLOOP just above \ to restart the main loop, but skipping all the flight \ and spawning code in the top part of the main loop JMP TT100 \ Otherwise jump to TT100 to restart the main loop from \ the start
Name: TT102 [Show more] Type: Subroutine Category: Keyboard Summary: Process function key, save key, hyperspace and chart key presses
Context: See this subroutine on its own page References: This subroutine is called as follows: * Main game loop (Part 6 of 6) calls TT102 * HME2 calls entry point T95

Process function key presses, plus "@" (save commander), "H" (hyperspace), "D" (show distance to system) and "O" (move chart cursor back to current system). We can also pass cursor position deltas in X and Y to indicate that the cursor keys or joystick have been used (i.e. the values that are returned by routine TT17). Arguments: A The internal key number of the key pressed (see p.142 of the Advanced User Guide for a list of internal key numbers) X The amount to move the crosshairs in the x-axis Y The amount to move the crosshairs in the y-axis Other entry points: T95 Print the distance to the selected system
.TT102 \ --- Mod: Original Acornsoft code removed: -----------> \ CMP #f8 \ If red key f8 was pressed, jump to STATUS to show the \ BNE P%+5 \ Status Mode screen, returning from the subroutine \ JMP STATUS \ using a tail call \ CMP #f4 \ If red key f4 was pressed, jump to TT22 to show the \ BNE P%+5 \ Long-range Chart, returning from the subroutine using \ JMP TT22 \ a tail call \ CMP #f5 \ If red key f5 was pressed, jump to TT23 to show the \ BNE P%+5 \ Short-range Chart, returning from the subroutine using \ JMP TT23 \ a tail call \ CMP #f6 \ If red key f6 was pressed, call TT111 to select the \ BNE TT92 \ system nearest to galactic coordinates (QQ9, QQ10) \ JSR TT111 \ (the location of the chart crosshairs) and set ZZ to \ JMP TT25 \ the system number, and then jump to TT25 to show the \ \ Data on System screen (along with an extended system \ \ description for the system in ZZ if we're docked), \ \ returning from the subroutine using a tail call \ --- And replaced by: --------------------------------> CMP #f8 \ If red key f8 was pressed, jump to info_menu to show BNE P%+5 \ the Encyclopedia screen, returning from the subroutine JMP info_menu \ using a tail call CMP #f4 \ If red key f4 was pressed, jump to TT22 to show the BNE P%+5 \ Long-range Chart, returning from the subroutine using JMP TT22 \ a tail call CMP #f5 \ If red key f5 was pressed, jump to TT23 to show the BNE P%+5 \ Short-range Chart, returning from the subroutine using JMP TT23 \ a tail call CMP #f6 \ If red key f6 was not pressed, jump to TT92 to check BNE TT92 \ for the next key JSR CTRL \ Red key f6 was pressed, so check whether CTRL was BPL jump_data \ also pressed, and if it wasn't pressed, jump to \ jump_data to skip the following instruction JMP launch \ CTRL-f6 was pressed, so jump to launch to load and run \ the main docked code (i.e. to exit the encyclopedia) .jump_data JSR TT111 \ Red key f6 was pressed on its own, so call TT111 to \ select the system nearest to galactic coordinates \ (QQ9, QQ10) (the location of the chart crosshairs) and \ set ZZ to the system number JMP TT25 \ Jump to TT25 to show the Data on System screen, along \ with an extended system description for the system in \ ZZ, returning from the subroutine using a tail call \ --- End of replacement ------------------------------> .TT92 \ --- Mod: Original Acornsoft code removed: -----------> \ CMP #f9 \ If red key f9 was pressed, jump to TT213 to show the \ BNE P%+5 \ Inventory screen, returning from the subroutine \ JMP TT213 \ using a tail call \ CMP #f7 \ If red key f7 was pressed, jump to TT167 to show the \ BNE P%+5 \ Market Price screen, returning from the subroutine \ JMP TT167 \ using a tail call \ CMP #f0 \ If red key f0 was pressed, jump to TT110 to launch our \ BNE fvw \ ship (if docked), returning from the subroutine using \ JMP TT110 \ a tail call \ --- And replaced by: --------------------------------> CMP #f9 \ If red key f9 was pressed, jump to info_menu to show BNE not_invnt \ the Encyclopedia screen, returning from the subroutine JMP info_menu \ using a tail call .not_invnt CMP #f7 \ If red key f7 was pressed, jump to info_menu to show BNE not_price \ the Encyclopedia screen, returning from the subroutine JMP info_menu \ using a tail call .not_price \ --- End of replacement ------------------------------> .fvw \ --- Mod: Original Acornsoft code removed: -----------> \ CMP #f3 \ If red key f3 was pressed, jump to EQSHP to show the \ BNE P%+5 \ Equip Ship screen, returning from the subroutine using \ JMP EQSHP \ a tail call \ CMP #f1 \ If red key f1 was pressed, jump to TT219 to show the \ BNE P%+5 \ Buy Cargo screen, returning from the subroutine using \ JMP TT219 \ a tail call \ CMP #&47 \ If "@" was not pressed, skip to nosave \ BNE nosave \ JSR SVE \ "@" was pressed, so call SVE to show the disc access \ \ menu \ BCC P%+5 \ If the C flag was set by SVE, then we loaded a new \ JMP QU5 \ commander file, so jump to QU5 to restart the game \ \ with the newly loaded commander \ JMP BAY \ Otherwise the C flag was clear, so jump to BAY to go \ \ to the docking bay (i.e. show the Status Mode screen) \.nosave \ CMP #f2 \ If red key f2 was pressed, jump to TT208 to show the \ BNE LABEL_3 \ Sell Cargo screen, returning from the subroutine using \ JMP TT208 \ a tail call \.INSP \ --- And replaced by: --------------------------------> CMP #f0 \ If red key f0 was pressed, jump to jump_menu to show BEQ jump_menu \ the Encyclopedia screen CMP #f1 \ If red key f1 was pressed, jump to jump_menu to show BEQ jump_menu \ the Encyclopedia screen CMP #f2 \ If red key f2 was pressed, jump to jump_menu to show BEQ jump_menu \ the Encyclopedia screen CMP #f3 \ If red key f3 was not pressed, jump to LABEL_3 to BNE LABEL_3 \ skip the following and keep checking for other keys .jump_menu JMP info_menu \ Jump to info_menu to show the Encyclopedia screen \ --- End of replacement ------------------------------> .LABEL_3 CMP #&54 \ If "H" was not pressed, jump to NWDAV5 to skip the BNE NWDAV5 \ following JSR CLYNS \ "H" was pressed, so clear the bottom three text rows \ of the upper screen, and move the text cursor to \ column 1 on row 21, i.e. the start of the top row of \ the three bottom rows LDA #15 \ Move the text cursor to column 15 (the middle of the STA XC \ screen) LDA #205 \ Print extended token 205 ("DOCKED") and return from JMP DETOK \ the subroutine using a tail call .NWDAV5 CMP #&32 \ If "D" was pressed, jump to T95 to print the distance BEQ T95 \ to a system (if we are in one of the chart screens) CMP #&43 \ If "F" was not pressed, jump down to HME1, otherwise BNE HME1 \ keep going to process searching for systems LDA QQ11 \ If the current view is a chart (QQ11 = 64 or 128), AND #%11000000 \ keep going, otherwise return from the subroutine (as BEQ t95 \ t95 contains an RTS) JMP HME2 \ Jump to HME2 to let us search for a system, returning \ from the subroutine using a tail call .HME1 STA T1 \ Store A (the key that's been pressed) in T1 LDA QQ11 \ If the current view is a chart (QQ11 = 64 or 128), AND #%11000000 \ keep going, otherwise jump down to t95 to return from BEQ t95 \ the subroutine LDA QQ22+1 \ If the on-screen hyperspace counter is non-zero, BNE t95 \ then we are already counting down, so jump down to t95 \ to return from the subroutine LDA T1 \ Restore the original value of A (the key that's been \ pressed) from T1 \ --- Mod: Original Acornsoft code removed: -----------> \ CMP #&36 \ If "O" was pressed, do the following three jumps, \ BNE ee2 \ otherwise skip to ee2 to continue \ --- And replaced by: --------------------------------> CMP #&36 \ If "O" was pressed, do the following three jumps, BNE not_home \ otherwise skip to not_home to continue checking key \ presses \ --- End of replacement ------------------------------> JSR TT103 \ Draw small crosshairs at coordinates (QQ9, QQ10), \ which will erase the crosshairs currently there JSR ping \ Set the target system to the current system (which \ will move the location in (QQ9, QQ10) to the current \ home system JSR TT103 \ Draw small crosshairs at coordinates (QQ9, QQ10), \ which will draw the crosshairs at our current home \ system .ee2 JSR TT16 \ Call TT16 to move the crosshairs by the amount in X \ and Y, which were passed to this subroutine as \ arguments .t95 RTS \ Return from the subroutine \ --- Mod: Code added for Elite-A: --------------------> .not_home CMP #&21 \ If "W" was pressed, continue on to move the crosshairs BNE ee2 \ to the special cargo destination, otherwise skip to \ ee2 to continue LDA cmdr_cour \ If there is no special cargo delivery mission in ORA cmdr_cour+1 \ progress, then the mission timer in cmdr_cour(1 0) BEQ ee2 \ will be zero, so skip to ee2 to continue JSR TT103 \ Draw small crosshairs at coordinates (QQ9, QQ10), \ which will erase the crosshairs currently there LDA cmdr_courx \ Set the galactic coordinates in (QQ9, QQ10) to the STA QQ9 \ current special cargo delivery destination in LDA cmdr_coury \ (cmdr_courx, cmdr_coury) STA QQ10 JSR TT103 \ Draw small crosshairs at coordinates (QQ9, QQ10), \ which will draw the crosshairs at our current home \ system \ --- End of added code -------------------------------> .T95 \ If we get here, "D" was pressed, so we need to show \ the distance to the selected system (if we are in a \ chart view) LDA QQ11 \ If the current view is a chart (QQ11 = 64 or 128), AND #%11000000 \ keep going, otherwise return from the subroutine (as BEQ t95 \ t95 contains an RTS) JSR hm \ Call hm to move the crosshairs to the target system \ in (QQ9, QQ10), returning with A = 0 STA QQ17 \ Set QQ17 = 0 to switch to ALL CAPS JSR cpl \ Print control code 3 (the selected system name) LDA #%10000000 \ Set bit 7 of QQ17 to switch to Sentence Case, with the STA QQ17 \ next letter in capitals LDA #1 \ Move the text cursor to column 1 and down one line STA XC \ (in other words, to the start of the next line) INC YC JMP TT146 \ Print the distance to the selected system and return \ from the subroutine using a tail call
Name: brkd [Show more] Type: Variable Category: Utility routines Summary: The brkd counter for error handling
Context: See this variable on its own page References: This variable is used as follows: * BRBR calls brkd

This counter starts at zero, and is decremented whenever the BRKV handler at BRBR prints an error message. It is incremented every time an error message is printed out as part of the TITLE routine.
.brkd EQUB 0
Name: BR1 [Show more] Type: Subroutine Category: Start and end Summary: Start or restart the game
Context: See this subroutine on its own page References: This subroutine is called as follows: * BRBR calls BR1

.BR1 \ --- Mod: Original Acornsoft code removed: -----------> \ LDX #3 \ Set XC = 3 (set text cursor to column 3) \ STX XC \ JSR FX200 \ Disable the ESCAPE key and clear memory if the BREAK \ \ key is pressed (*FX 200,3) \ LDX #CYL \ Call TITLE to show a rotating Cobra Mk III (#CYL) and \ LDA #6 \ token 6 ("LOAD NEW {single cap}COMMANDER {all caps} \ JSR TITLE \ (Y/N)?{sentence case}{cr}{cr}"), returning with the \ \ internal number of the key pressed in A \ CMP #&44 \ Did we press "Y"? If not, jump to QU5, otherwise \ BNE QU5 \ continue on to load a new commander \ JSR DFAULT \ Call DFAULT to reset the current commander data block \ \ to the last saved commander \ JSR SVE \ Call SVE to load a new commander into the last saved \ \ commander data block \.QU5 \ JSR DFAULT \ Call DFAULT to reset the current commander data block \ \ to the last saved commander \ --- And replaced by: --------------------------------> JMP escape \ Jump to escape to load the main docked code so that it \ shows the docking tunnel and ship hanger \ --- End of replacement ------------------------------>
Name: BRBR [Show more] Type: Subroutine Category: Utility routines Summary: The standard BRKV handler for the game
Context: See this subroutine on its own page References: This subroutine is called as follows: * BRKBK calls BRBR * S% calls BRBR

This routine is used to display error messages, before restarting the game. When called, it makes a beep and prints the system error message in the block pointed to by (&FD &FE), which is where the MOS will put any system errors. It then waits for a key press and restarts the game. BRKV is set to this routine in the loader, when the docked code is loaded, and at the end of the SVE routine after the disc access menu has been processed. In other words, this is the standard BRKV handler for the game, and it's swapped out to MEBRK for disc access operations only. When it is the BRKV handler, the routine can be triggered using a BRK instruction. The main differences between this routine and the MEBRK handler that is used during disc access operations are that this routine restarts the game rather than returning to the disc access menu, and this handler decrements the brkd counter.
.BRBR DEC brkd \ Decrement the brkd counter BNE BR1 \ If the brkd counter is non-zero, jump to BR1 to \ restart the game
Name: DEATH2 [Show more] Type: Subroutine Category: Start and end Summary: Reset most of the game and restart from the title screen
Context: See this subroutine on its own page References: No direct references to this subroutine in this source file

This routine is called following death, and when the game is quit by pressing ESCAPE when paused.
.DEATH2 JSR RES2 \ Reset a number of flight variables and workspaces \ and fall through into the entry code for the game \ to restart from the title screen
Name: BAY [Show more] Type: Subroutine Category: Status Summary: Go to the docking bay (i.e. show the Encyclopedia screen)
Context: See this subroutine on its own page References: This subroutine is called as follows: * DOENTRY calls BAY * info_menu calls BAY * menu calls BAY * ships_ag calls BAY * trading calls BAY

We end up here after the start-up process (load commander etc.), as well as after a successful save, an escape pod launch, a successful docking, the end of a cargo sell, and various errors (such as not having enough cash, entering too many items when buying, trying to fit an item to your ship when you already have it, running out of cargo space, and so on).
.BAY LDA #&FF \ Set QQ12 = &FF (the docked flag) to indicate that we STA QQ12 \ are docked \ --- Mod: Original Acornsoft code removed: -----------> \ LDA #f8 \ Jump into the main loop at FRCE, setting the key \ JMP FRCE \ that's "pressed" to red key f8 (so we show the Status \ \ Mode screen) \ --- And replaced by: --------------------------------> LDA #f3 \ Jump into the main loop at FRCE, setting the key JMP FRCE \ that's "pressed" to red key f3 (so we show the \ Encyclopedia screen) \ --- End of replacement ------------------------------>
Name: MT26 [Show more] Type: Subroutine Category: Text Summary: Fetch a line of text from the keyboard Deep dive: Extended text tokens
Context: See this subroutine on its own page References: This subroutine is called as follows: * JMTB calls MT26

If ESCAPE is pressed or a blank name is entered, then an empty string is returned. Returns: Y The size of the entered text, or 0 if none was entered or if ESCAPE was pressed INWK+5 The entered text, terminated by a carriage return C flag Set if ESCAPE was pressed
.MT26 LDA #%10000001 \ Clear 6522 System VIA interrupt enable register IER STA VIA+&4E \ (SHEILA &4E) bit 1 (i.e. enable the CA2 interrupt, \ which comes from the keyboard) JSR FLKB \ Call FLKB to flush the keyboard buffer LDX #LO(RLINE) \ Set (Y X) to point to the RLINE parameter block LDY #HI(RLINE) LDA #0 \ Call OSWORD with A = 0 to read a line from the current JSR OSWORD \ input stream (i.e. the keyboard) BCC P%+4 \ The C flag will be set if we pressed ESCAPE when \ entering the name, otherwise it will be clear, so \ skip the next instruction if ESCAPE is not pressed LDY #0 \ ESCAPE was pressed, so set Y = 0 (as the OSWORD call \ returns the length of the entered string in Y) LDA #%00000001 \ Set 6522 System VIA interrupt enable register IER STA VIA+&4E \ (SHEILA &4E) bit 1 (i.e. disable the CA2 interrupt, \ which comes from the keyboard) JMP FEED \ Jump to FEED to print a newline, returning from the \ subroutine using a tail call
Name: RLINE [Show more] Type: Variable Category: Text Summary: The OSWORD configuration block used to fetch a line of text from the keyboard
Context: See this variable on its own page References: This variable is used as follows: * MT26 calls RLINE
.RLINE EQUW INWK+5 \ The address to store the input, so the text entered \ will be stored in INWK+5 as it is typed EQUB 9 \ Maximum line length = 9, as that's the maximum size \ for a commander's name including a directory name EQUB '!' \ Allow ASCII characters from "!" through to "{" in {' \ the input
Name: ZERO [Show more] Type: Subroutine Category: Utility routines Summary: Zero-fill pages &9, &A, &B, &C and &D
Context: See this subroutine on its own page References: This subroutine is called as follows: * RES2 calls ZERO

This resets the following workspaces to zero: * The ship data blocks ascending from K% at &0900 * The ship line heap descending from WP at &0D40 * WP workspace variables from FRIN to de, which include the ship slots for the local bubble of universe, and various flight and ship status variables (only a portion of the LSX/LSO sun line heap is cleared)
.ZERO LDX #(de-FRIN) \ We're going to zero the UP workspace variables from \ FRIN to de, so set a counter in X for the correct \ number of bytes LDA #0 \ Set A = 0 so we can zero the variables .ZEL2 STA FRIN,X \ Zero the X-th byte of FRIN to de DEX \ Decrement the loop counter BPL ZEL2 \ Loop back to zero the next variable until we have done \ them all RTS \ Return from the subroutine
Name: ZES1 [Show more] Type: Subroutine Category: Utility routines Summary: Zero-fill the page whose number is in X
Context: See this subroutine on its own page References: This subroutine is called as follows: * TTX66 calls ZES1

Arguments: X The page we want to zero-fill
.ZES1 LDY #0 \ If we set Y = SC = 0 and fall through into ZES2 STY SC \ below, then we will zero-fill 255 bytes starting from \ SC - in other words, we will zero-fill the whole of \ page X
Name: ZES2 [Show more] Type: Subroutine Category: Utility routines Summary: Zero-fill a specific page
Context: See this subroutine on its own page References: This subroutine is called as follows: * CHPR calls ZES2

Zero-fill from address (X SC) + Y to (X SC) + &FF. Arguments: Y The offset from (X SC) where we start zeroing, counting up to to &FF SC The low byte (i.e. the offset into the page) of the starting point of the zero-fill Returns: Z flag Z flag is set
.ZES2 LDA #0 \ Load A with the byte we want to fill the memory block \ with - i.e. zero STX SC+1 \ We want to zero-fill page X, so store this in the \ high byte of SC, so the 16-bit address in SC and \ SC+1 is now pointing to the SC-th byte of page X .ZEL1 STA (SC),Y \ Zero the Y-th byte of the block pointed to by SC, \ so that's effectively the Y-th byte before SC INY \ Increment the loop counter BNE ZEL1 \ Loop back to zero the next byte RTS \ Return from the subroutine
Name: NORM [Show more] Type: Subroutine Category: Maths (Geometry) Summary: Normalise the three-coordinate vector in XX15 Deep dive: Tidying orthonormal vectors Orientation vectors
Context: See this subroutine on its own page References: This subroutine is called as follows: * TIDY calls NORM * NO3 calls entry point NO1

We do this by dividing each of the three coordinates by the length of the vector, which we can calculate using Pythagoras. Once normalised, 96 (&E0) is used to represent a value of 1, and 96 with bit 7 set (&E0) is used to represent -1. This enables us to represent fractional values of less than 1 using integers. Arguments: XX15 The vector to normalise, with: * The x-coordinate in XX15 * The y-coordinate in XX15+1 * The z-coordinate in XX15+2 Returns: XX15 The normalised vector Q The length of the original XX15 vector Other entry points: NO1 Contains an RTS
.NORM LDA XX15 \ Fetch the x-coordinate into A JSR SQUA \ Set (A P) = A * A = x^2 STA R \ Set (R Q) = (A P) = x^2 LDA P STA Q LDA XX15+1 \ Fetch the y-coordinate into A JSR SQUA \ Set (A P) = A * A = y^2 STA T \ Set (T P) = (A P) = y^2 LDA P \ Set (R Q) = (R Q) + (T P) = x^2 + y^2 ADC Q \ STA Q \ First, doing the low bytes, Q = Q + P LDA T \ And then the high bytes, R = R + T ADC R STA R LDA XX15+2 \ Fetch the z-coordinate into A JSR SQUA \ Set (A P) = A * A = z^2 STA T \ Set (T P) = (A P) = z^2 LDA P \ Set (R Q) = (R Q) + (T P) = x^2 + y^2 + z^2 ADC Q \ STA Q \ First, doing the low bytes, Q = Q + P LDA T \ And then the high bytes, R = R + T ADC R STA R JSR LL5 \ We now have the following: \ \ (R Q) = x^2 + y^2 + z^2 \ \ so we can call LL5 to use Pythagoras to get: \ \ Q = SQRT(R Q) \ = SQRT(x^2 + y^2 + z^2) \ \ So Q now contains the length of the vector (x, y, z), \ and we can normalise the vector by dividing each of \ the coordinates by this value, which we do by calling \ routine TIS2. TIS2 returns the divided figure, using \ 96 to represent 1 and 96 with bit 7 set for -1 LDA XX15 \ Call TIS2 to divide the x-coordinate in XX15 by Q, JSR TIS2 \ with 1 being represented by 96 STA XX15 LDA XX15+1 \ Call TIS2 to divide the y-coordinate in XX15+1 by Q, JSR TIS2 \ with 1 being represented by 96 STA XX15+1 LDA XX15+2 \ Call TIS2 to divide the z-coordinate in XX15+2 by Q, JSR TIS2 \ with 1 being represented by 96 STA XX15+2 .NO1 RTS \ Return from the subroutine
Name: RDKEY [Show more] Type: Subroutine Category: Keyboard Summary: Scan the keyboard for key presses
Context: See this subroutine on its own page References: This subroutine is called as follows: * DK4 calls RDKEY * PAUSE2 calls RDKEY * TT217 calls RDKEY * ships_ag calls RDKEY

Scan the keyboard, starting with internal key number 16 ("Q") and working through the set of internal key numbers (see p.142 of the Advanced User Guide for a list of internal key numbers). This routine is effectively the same as OSBYTE 122, though the OSBYTE call preserves A, unlike this routine. Returns: X If a key is being pressed, X contains the internal key number, otherwise it contains 0 A Contains the same as X
.RDKEY LDX #16 \ Start the scan with internal key number 16 ("Q") .Rd1 JSR DKS4 \ Scan the keyboard to see if the key in X is currently \ being pressed, returning the result in A and X BMI Rd2 \ Jump to Rd2 if this key is being pressed (in which \ case DKS4 will have returned the key number with bit \ 7 set, which is negative) INX \ Increment the key number, which was unchanged by the \ above call to DKS4 BPL Rd1 \ Loop back to test the next key, ending the loop when \ X is negative (i.e. 128) TXA \ If we get here, nothing is being pressed, so copy X \ into A so that X = A = 128 = %10000000 .Rd2 EOR #%10000000 \ EOR A with #%10000000 to flip bit 7, so A now contains \ 0 if no key has been pressed, or the internal key \ number if a key has been pressed TAX \ Copy A into X RTS \ Return from the subroutine
Name: ECMOF [Show more] Type: Subroutine Category: Sound Summary: Switch off the E.C.M.
Context: See this subroutine on its own page References: This subroutine is called as follows: * RES2 calls ECMOF

Switch the E.C.M. off, turn off the dashboard bulb and make the sound of the E.C.M. switching off).
.ECMOF LDA #0 \ Set ECMA and ECMB to 0 to indicate that no E.C.M. is STA ECMA \ currently running STA ECMP LDA #72 \ Call the NOISE routine with A = 72 to make the sound BNE NOISE \ of the E.C.M. being turned off and return from the \ subroutine using a tail call (this BNE is effectively \ a JMP as A will never be zero)
Name: BEEP [Show more] Type: Subroutine Category: Sound Summary: Make a short, high beep
Context: See this subroutine on its own page References: This subroutine is called as follows: * CHPR calls BEEP * dn2 calls BEEP
.BEEP \ --- Mod: Original Acornsoft code removed: -----------> \ LDA #32 \ Call the NOISE routine with A = 32 to make a short, \ BNE NOISE \ high beep, returning from the subroutine using a tail \ \ call (this BNE is effectively a JMP as A will never be \ \ zero) \ --- And replaced by: --------------------------------> LDA #32 \ Set A = 32 to denote a short, high beep, and fall \ through into the NOISE routine to make the sound \ --- End of replacement ------------------------------>
Name: NOISE [Show more] Type: Subroutine Category: Sound Summary: Make the sound whose number is in A
Context: See this subroutine on its own page References: This subroutine is called as follows: * ECMOF calls NOISE * HME2 calls NOISE

Arguments: A The number of the sound to be made. See the documentation for variable SFX for a list of sound numbers
.NOISE JSR NOS1 \ Set up the sound block in XX16 for the sound in A and \ fall through into NO3 to make the sound
Name: NO3 [Show more] Type: Subroutine Category: Sound Summary: Make a sound from a prepared sound block
Context: See this subroutine on its own page References: No direct references to this subroutine in this source file

Make a sound from a prepared sound block in XX16 (if sound is enabled). See routine NOS1 for details of preparing the XX16 sound block.
.NO3 LDX DNOIZ \ Set X to the DNOIZ configuration setting BNE NO1 \ If DNOIZ is non-zero, then sound is disabled, so \ return from the subroutine (as NO1 contains an RTS) LDX #LO(XX16) \ Otherwise set (Y X) to point to the sound block in LDY #HI(XX16) \ XX16 LDA #7 \ Call OSWORD 7 to makes the sound, as described in the JMP OSWORD \ documentation for variable SFX, and return from the \ subroutine using a tail call
Name: NOS1 [Show more] Type: Subroutine Category: Sound Summary: Prepare a sound block
Context: See this subroutine on its own page References: This subroutine is called as follows: * NOISE calls NOS1

Copy four sound bytes from SFX into XX16, interspersing them with null bytes, with Y indicating the sound number to copy (from the values in the sound table at SFX). So, for example, if we call this routine with A = 40 (long, low beep), the following bytes will be set in XX16 to XX16+7: &13 &00 &F4 &00 &0C &00 &08 &00 This block will be passed to OSWORD 7 to make the sound, which expects the four sound attributes as 16-bit big-endian values - in other words, with the low byte first. So the above block would pass the values &0013, &00F4, &000C and &0008 to the SOUND statement when used with OSWORD 7, or: SOUND &13, &F4, &0C, &08 as the high bytes are always zero. Arguments: A The sound number to copy from SFX to XX16, which is always a multiple of 8
.NOS1 LSR A \ Divide A by 2, and also clear the C flag, as bit 0 of \ A is always zero (as A is a multiple of 8) ADC #3 \ Set Y = A + 3, so Y now points to the last byte of TAY \ four within the block of four-byte values LDX #7 \ We want to copy four bytes, spread out into an 8-byte \ block, so set a counter in Y to cover 8 bytes .NOL1 LDA #0 \ Set the X-th byte of XX16 to 0 STA XX16,X DEX \ Decrement the destination byte pointer LDA SFX,Y \ Set the X-th byte of XX16 to the value from SFX+Y STA XX16,X DEY \ Decrement the source byte pointer again DEX \ Decrement the destination byte pointer again BPL NOL1 \ Loop back for the next source byte \ Fall through into KYTB to return from the subroutine, \ as the first byte of KYTB is an RTS
Name: CTRL [Show more] Type: Subroutine Category: Keyboard Summary: Scan the keyboard to see if CTRL is currently pressed
Context: See this subroutine on its own page References: This subroutine is called as follows: * TT102 calls CTRL

Returns: X X = %10000001 (i.e. 129 or -127) if CTRL is being pressed X = 1 if CTRL is not being pressed A Contains the same as X
.CTRL LDX #1 \ Set X to the internal key number for CTRL and fall \ through to DKS4 to scan the keyboard
Name: DKS4 [Show more] Type: Subroutine Category: Keyboard Summary: Scan the keyboard to see if a specific key is being pressed Deep dive: The key logger
Context: See this subroutine on its own page References: This subroutine is called as follows: * RDKEY calls DKS4 * TT17 calls DKS4

Arguments: X The internal number of the key to check (see p.142 of the Advanced User Guide for a list of internal key numbers) Returns: A If the key in A is being pressed, A contains the original argument A, but with bit 7 set (i.e. A + 128). If the key in A is not being pressed, the value in A is unchanged X Contains the same as A
.DKS4 LDA #%00000011 \ Set A to %00000011, so it's ready to send to SHEILA \ once interrupts have been disabled SEI \ Disable interrupts so we can scan the keyboard \ without being hijacked STA VIA+&40 \ Set 6522 System VIA output register ORB (SHEILA &40) \ to %00000011 to stop auto scan of keyboard LDA #%01111111 \ Set 6522 System VIA data direction register DDRA STA VIA+&43 \ (SHEILA &43) to %01111111. This sets the A registers \ (IRA and ORA) so that: \ \ * Bits 0-6 of ORA will be sent to the keyboard \ \ * Bit 7 of IRA will be read from the keyboard STX VIA+&4F \ Set 6522 System VIA output register ORA (SHEILA &4F) \ to X, the key we want to scan for; bits 0-6 will be \ sent to the keyboard, of which bits 0-3 determine the \ keyboard column, and bits 4-6 the keyboard row LDX VIA+&4F \ Read 6522 System VIA output register IRA (SHEILA &4F) \ into X; bit 7 is the only bit that will have changed. \ If the key is pressed, then bit 7 will be set, \ otherwise it will be clear LDA #%00001011 \ Set 6522 System VIA output register ORB (SHEILA &40) STA VIA+&40 \ to %00001011 to restart auto scan of keyboard CLI \ Allow interrupts again TXA \ Transfer X into A RTS \ Return from the subroutine
Name: DKS2 [Show more] Type: Subroutine Category: Keyboard Summary: Read the joystick position
Context: See this subroutine on its own page References: This subroutine is called as follows: * DOKEY calls DKS2

Return the value of ADC channel in X (used to read the joystick). The value will be inverted if the game has been configured to reverse both joystick channels (which can be done by pausing the game and pressing J). Arguments: X The ADC channel to read: * 1 = joystick X * 2 = joystick Y Returns: (A X) The 16-bit value read from channel X, with the value inverted if the game has been configured to reverse the joystick Other entry points: DKS2-1 Contains an RTS
.DKS2 LDA #128 \ Call OSBYTE with A = 128 to fetch the 16-bit value JSR OSBYTE \ from ADC channel X, returning (Y X), i.e. the high \ byte in Y and the low byte in X TYA \ Copy Y to A, so the result is now in (A X) EOR JSTE \ The high byte A is now EOR'd with the value in \ location JSTE, which contains &FF if both joystick \ channels are reversed and 0 otherwise (so A now \ contains the high byte but inverted, if that's what \ the current settings say) RTS \ Return from the subroutine
Name: DKS3 [Show more] Type: Subroutine Category: Keyboard Summary: Toggle a configuration setting and emit a beep
Context: See this subroutine on its own page References: This subroutine is called as follows: * DK4 calls DKS3

This is called when the game is paused and a key is pressed that changes the game's configuration. Specifically, this routine toggles the configuration settings for the following keys: * CAPS LOCK toggles keyboard flight damping (&40) * A toggles keyboard auto-recentre (&41) * X toggles author names on start-up screen (&42) * F toggles flashing console bars (&43) * Y toggles reverse joystick Y channel (&44) * J toggles reverse both joystick channels (&45) * K toggles keyboard and joystick (&46) * @ toggles keyboard and Delta 14b joystick (&47) The numbers in brackets are the internal key numbers (see p.142 of the Advanced User Guide for a list of internal key numbers). We pass the key that has been pressed in X, and the configuration option to check it against in Y, so this routine is typically called in a loop that loops through the various configuration options. Arguments: X The internal number of the key that's been pressed Y The internal number of the configuration key to check against, from the list above (i.e. Y must be from &40 to &46)
.DKS3 STY T \ Store the configuration key argument in T CPX T \ If X <> Y, jump to Dk3 to return from the subroutine BNE Dk3 \ We have a match between X and Y, so now to toggle \ the relevant configuration byte. CAPS LOCK has a key \ value of &40 and has its configuration byte at \ location DAMP, A has a value of &41 and has its byte \ at location DJD, which is DAMP+1, and so on. So we \ can toggle the configuration byte by changing the \ byte at DAMP + (X - &40), or to put it in indexing \ terms, DAMP-&40,X. It's no coincidence that the \ game's configuration bytes are set up in this order \ and with these keys (and this is also why the sound \ on/off keys are dealt with elsewhere, as the internal \ key for S and Q are &51 and &10, which don't fit \ nicely into this approach) LDA DAMP-&40,X \ Fetch the byte from DAMP + (X - &40), invert it and EOR #&FF \ put it back (0 means no and &FF means yes in the STA DAMP-&40,X \ configuration bytes, so this toggles the setting) JSR BELL \ Make a beep sound so we know something has happened JSR DELAY \ Wait for Y vertical syncs (Y is between 64 and 70, so \ this is always a bit longer than a second) LDY T \ Restore the configuration key argument into Y .Dk3 RTS \ Return from the subroutine
Name: DOKEY [Show more] Type: Subroutine Category: Keyboard Summary: Scan for the seven primary flight controls Deep dive: The key logger The docking computer
Context: See this subroutine on its own page References: This subroutine is called as follows: * TT17 calls DOKEY
.DOKEY \ --- Mod: Original Acornsoft code removed: -----------> \ LDA JSTK \ If JSTK is zero, then we are configured to use the \ BEQ DK9 \ keyboard rather than the joystick, so jump to DK9 to \ \ make sure the Bitstik is disabled as well (DK9 then \ \ jumps to DK4 to scan for pause, configuration and \ \ secondary flight keys) \ --- And replaced by: --------------------------------> LDA JSTK \ If JSTK is zero, then we are configured to use the BEQ DK4 \ keyboard rather than the joystick, so jump to DK4 to \ scan for pause, configuration and secondary flight \ keys \ --- End of replacement ------------------------------> LDX #1 \ Call DKS2 to fetch the value of ADC channel 1 (the JSR DKS2 \ joystick X value) into (A X), and OR A with 1. This ORA #1 \ ensures that the high byte is at least 1, and then we STA JSTX \ store the result in JSTX LDX #2 \ Call DKS2 to fetch the value of ADC channel 2 (the JSR DKS2 \ joystick Y value) into (A X), and EOR A with JSTGY. EOR JSTGY \ JSTGY will be &FF if the game is configured to STA JSTY \ reverse the joystick Y channel, so this EOR does \ exactly that, and then we store the result in JSTY \ Fall through into DK4 to scan for other keys
Name: DK4 [Show more] Type: Subroutine Category: Keyboard Summary: Scan for pause, configuration and secondary flight keys Deep dive: The key logger
Context: See this subroutine on its own page References: This subroutine is called as follows: * DOKEY calls DK4

Scan for pause and configuration keys, and if this is a space view, also scan for secondary flight controls. Specifically: * Scan for the pause button (COPY) and if it's pressed, pause the game and process any configuration key presses until the game is unpaused (DELETE) * If this is a space view, scan for secondary flight keys and update the relevant bytes in the key logger
.DK4 JSR RDKEY \ Scan the keyboard for a key press and return the \ internal key number in X (or 0 for no key press) STX KL \ Store X in KL, byte #0 of the key logger CPX #&69 \ If COPY is not being pressed, jump to DK2 below, BNE DK2 \ otherwise let's process the configuration keys .FREEZE \ COPY is being pressed, so we enter a loop that \ listens for configuration keys, and we keep looping \ until we detect a DELETE key press. This effectively \ pauses the game when COPY is pressed, and unpauses \ it when DELETE is pressed JSR WSCAN \ Call WSCAN to wait for the vertical sync, so the whole \ screen gets drawn JSR RDKEY \ Scan the keyboard for a key press and return the \ internal key number in X (or 0 for no key press) CPX #&51 \ If "S" is not being pressed, skip to DK6 BNE DK6 LDA #0 \ "S" is being pressed, so set DNOIZ to 0 to turn the STA DNOIZ \ sound on .DK6 LDY #&40 \ We now want to loop through the keys that toggle \ various settings. These have internal key numbers \ between &40 (CAPS LOCK) and &46 ("K"), so we set up \ the first key number in Y to act as a loop counter. \ See subroutine DKS3 for more details on this .DKL4 JSR DKS3 \ Call DKS3 to scan for the key given in Y, and toggle \ the relevant setting if it is pressed INY \ Increment Y to point to the next toggle key \ --- Mod: Original Acornsoft code removed: -----------> \ CPY #&47 \ The last toggle key is &46 (K), so check whether we \ \ have just done that one \ --- And replaced by: --------------------------------> CPY #&48 \ The last toggle key is &47 (@), so check whether we \ have just done that one \ --- End of replacement ------------------------------> BNE DKL4 \ If not, loop back to check for the next toggle key .DK55 CPX #&10 \ If "Q" is not being pressed, skip to DK7 BNE DK7 STX DNOIZ \ "Q" is being pressed, so set DNOIZ to X, which is \ non-zero (&10), so this will turn the sound off .DK7 CPX #&70 \ If ESCAPE is not being pressed, skip over the next BNE P%+5 \ instruction \ --- Mod: Original Acornsoft code removed: -----------> \ JMP BR1 \ ESCAPE is being pressed, so jump to BR1 to end the \ \ game \ CPX #&64 \ If "B" is not being pressed, skip to DK7 \ BNE nobit \ LDA BSTK \ Toggle the value of BSTK between 0 and &FF \ EOR #&FF \ STA BSTK \ STA JSTK \ Configure JSTK to the same value, so when the Bitstik \ \ is enabled, so is the joystick \ STA JSTE \ Configure JSTE to the same value, so when the Bitstik \ \ is enabled, the joystick is configured with reversed \ \ channels \.nobit \ --- And replaced by: --------------------------------> JMP escape \ ESCAPE is being pressed, so jump to escape to end \ the game \ --- End of replacement ------------------------------> CPX #&59 \ If DELETE is not being pressed, we are still paused, BNE FREEZE \ so loop back up to keep listening for configuration \ keys, otherwise fall through into the rest of the \ key detection code, which unpauses the game .DK2 LDA QQ11 \ If the current view is non-zero (i.e. not a space BNE out \ view), return from the subroutine (as out contains \ an RTS) LDY #16 \ This is a space view, so now we want to check for all \ the secondary flight keys. The internal key numbers \ are in the keyboard table KYTB from KYTB+8 to \ KYTB+16, and their key logger locations are from KL+8 \ to KL+16. So set a decreasing counter in Y for the \ index, starting at 16, so we can loop through them LDA #&FF \ Set A to &FF so we can store this in the keyboard \ logger for keys that are being pressed \ --- Mod: Original Acornsoft code removed: -----------> \.DK5 \ --- End of removed code -----------------------------> RTS \ Return from the subroutine \ --- Mod: Original Acornsoft code removed: -----------> \.DK9 \ STA BSTK \ DK9 is called from DOKEY using a BEQ, so we know A is \ \ 0, so this disables the Bitstik and switched to \ \ keyboard or joystick \ BEQ DK4 \ Jump back to DK4 in DOKEY (this BEQ is effectively a \ \ JMP as A is always zero) \ --- End of removed code ----------------------------->
Name: TT217 [Show more] Type: Subroutine Category: Keyboard Summary: Scan the keyboard until a key is pressed
Context: See this subroutine on its own page References: This subroutine is called as follows: * gnum calls TT217 * DK4 calls entry point out * mes9 calls entry point out

Scan the keyboard until a key is pressed, and return the key's ASCII code. If, on entry, a key is already being held down, then wait until that key is released first (so this routine detects the first key down event following the subroutine call). Returns: X The ASCII code of the key that was pressed A Contains the same as X Y Y is preserved Other entry points: out Contains an RTS
.TT217 STY YSAV \ Store Y in temporary storage, so we can restore it \ later .t LDY #2 \ Delay for 2 vertical syncs (2/50 = 0.04 seconds) so we JSR DELAY \ don't take up too much CPU time while looping round JSR RDKEY \ Scan the keyboard for a key press and return the \ internal key number in X (or 0 for no key press) BNE t \ If a key was already being held down when we entered \ this routine, keep looping back up to t, until the \ key is released .t2 JSR RDKEY \ Any pre-existing key press is now gone, so we can \ start scanning the keyboard again, returning the \ internal key number in X (or 0 for no key press) BEQ t2 \ Keep looping up to t2 until a key is pressed TAY \ Copy A to Y, so Y contains the internal key number \ of the key pressed LDA (TRTB%),Y \ The address in TRTB% points to the MOS key \ translation table, which is used to translate \ internal key numbers to ASCII, so this fetches the \ key's ASCII code into A LDY YSAV \ Restore the original value of Y we stored above TAX \ Copy A into X .out RTS \ Return from the subroutine
Name: me1 [Show more] Type: Subroutine Category: Text Summary: Erase an old in-flight message and display a new one
Context: See this subroutine on its own page References: This subroutine is called as follows: * MESS calls me1

Arguments: A The text token to be printed X Must be set to 0
.me1 STX DLY \ Set the message delay in DLY to 0, so any new \ in-flight messages will be shown instantly PHA \ Store the new message token we want to print LDA MCH \ Set A to the token number of the message that is JSR mes9 \ currently on-screen, and call mes9 to print it (which \ will remove it from the screen, as printing is done \ using EOR logic) PLA \ Restore the new message token
Name: MESS [Show more] Type: Subroutine Category: Text Summary: Display an in-flight message
Context: See this subroutine on its own page References: This subroutine is called as follows: * me2 calls MESS

Display an in-flight message in capitals at the bottom of the space view, erasing any existing in-flight message first. Arguments: A The text token to be printed
.MESS LDX #0 \ Set QQ17 = 0 to switch to ALL CAPS STX QQ17 LDY #9 \ Move the text cursor to column 9, row 22, at the STY XC \ bottom middle of the screen, and set Y = 22 LDY #22 STY YC CPX DLY \ If the message delay in DLY is not zero, jump up to BNE me1 \ me1 to erase the current message first (whose token \ number will be in MCH) STY DLY \ Set the message delay in DLY to 22 STA MCH \ Set MCH to the token we are about to display \ Fall through into mes9 to print the token in A
Name: mes9 [Show more] Type: Subroutine Category: Text Summary: Print a text token, possibly followed by " DESTROYED"
Context: See this subroutine on its own page References: This subroutine is called as follows: * me1 calls mes9

Print a text token, followed by " DESTROYED" if the destruction flag is set (for when a piece of equipment is destroyed).
.mes9 JSR TT27 \ Call TT27 to print the text token in A LSR de \ If bits 1-7 of variable de are clear, return from the BEQ out \ subroutine (as out contains an RTS). This means that \ " DESTROYED" is never shown, even if bit 0 of de is \ set, which makes sense as we are docked LDA #253 \ Print recursive token 93 (" DESTROYED") and return JMP TT27 \ from the subroutine using a tail call
Name: TIDY [Show more] Type: Subroutine Category: Maths (Geometry) Summary: Orthonormalise the orientation vectors for a ship Deep dive: Tidying orthonormal vectors Orientation vectors
Context: See this subroutine on its own page References: This subroutine is called as follows: * MVEIT (Part 1 of 9) calls TIDY

This routine orthonormalises the orientation vectors for a ship. This means making the three orientation vectors orthogonal (perpendicular to each other), and normal (so each of the vectors has length 1). We do this because we use the small angle approximation to rotate these vectors in space. It is not completely accurate, so the three vectors tend to get stretched over time, so periodically we tidy the vectors with this routine to ensure they remain as orthonormal as possible.
.TI2 \ Called from below with A = 0, X = 0, Y = 4 when \ nosev_x and nosev_y are small, so we assume that \ nosev_z is big TYA \ A = Y = 4 LDY #2 JSR TIS3 \ Call TIS3 with X = 0, Y = 2, A = 4, to set roofv_z = STA INWK+20 \ -(nosev_x * roofv_x + nosev_y * roofv_y) / nosev_z JMP TI3 \ Jump to TI3 to keep tidying .TI1 \ Called from below with A = 0, Y = 4 when nosev_x is \ small TAX \ Set X = A = 0 LDA XX15+1 \ Set A = nosev_y, and if the top two magnitude bits AND #%01100000 \ are both clear, jump to TI2 with A = 0, X = 0, Y = 4 BEQ TI2 LDA #2 \ Otherwise nosev_y is big, so set up the index values \ to pass to TIS3 JSR TIS3 \ Call TIS3 with X = 0, Y = 4, A = 2, to set roofv_y = STA INWK+18 \ -(nosev_x * roofv_x + nosev_z * roofv_z) / nosev_y JMP TI3 \ Jump to TI3 to keep tidying .TIDY LDA INWK+10 \ Set (XX15, XX15+1, XX15+2) = nosev STA XX15 LDA INWK+12 STA XX15+1 LDA INWK+14 STA XX15+2 JSR NORM \ Call NORM to normalise the vector in XX15, i.e. nosev LDA XX15 \ Set nosev = (XX15, XX15+1, XX15+2) STA INWK+10 LDA XX15+1 STA INWK+12 LDA XX15+2 STA INWK+14 LDY #4 \ Set Y = 4 LDA XX15 \ Set A = nosev_x, and if the top two magnitude bits AND #%01100000 \ are both clear, jump to TI1 with A = 0, Y = 4 BEQ TI1 LDX #2 \ Otherwise nosev_x is big, so set up the index values LDA #0 \ to pass to TIS3 JSR TIS3 \ Call TIS3 with X = 2, Y = 4, A = 0, to set roofv_x = STA INWK+16 \ -(nosev_y * roofv_y + nosev_z * roofv_z) / nosev_x .TI3 LDA INWK+16 \ Set (XX15, XX15+1, XX15+2) = roofv STA XX15 LDA INWK+18 STA XX15+1 LDA INWK+20 STA XX15+2 JSR NORM \ Call NORM to normalise the vector in XX15, i.e. roofv LDA XX15 \ Set roofv = (XX15, XX15+1, XX15+2) STA INWK+16 LDA XX15+1 STA INWK+18 LDA XX15+2 STA INWK+20 LDA INWK+12 \ Set Q = nosev_y STA Q LDA INWK+20 \ Set A = roofv_z JSR MULT12 \ Set (S R) = Q * A = nosev_y * roofv_z LDX INWK+14 \ Set X = nosev_z LDA INWK+18 \ Set A = roofv_y JSR TIS1 \ Set (A ?) = (-X * A + (S R)) / 96 \ = (-nosev_z * roofv_y + nosev_y * roofv_z) / 96 \ \ This also sets Q = nosev_z EOR #%10000000 \ Set sidev_x = -A STA INWK+22 \ = (nosev_z * roofv_y - nosev_y * roofv_z) / 96 LDA INWK+16 \ Set A = roofv_x JSR MULT12 \ Set (S R) = Q * A = nosev_z * roofv_x LDX INWK+10 \ Set X = nosev_x LDA INWK+20 \ Set A = roofv_z JSR TIS1 \ Set (A ?) = (-X * A + (S R)) / 96 \ = (-nosev_x * roofv_z + nosev_z * roofv_x) / 96 \ \ This also sets Q = nosev_x EOR #%10000000 \ Set sidev_y = -A STA INWK+24 \ = (nosev_x * roofv_z - nosev_z * roofv_x) / 96 LDA INWK+18 \ Set A = roofv_y JSR MULT12 \ Set (S R) = Q * A = nosev_x * roofv_y LDX INWK+12 \ Set X = nosev_y LDA INWK+16 \ Set A = roofv_x JSR TIS1 \ Set (A ?) = (-X * A + (S R)) / 96 \ = (-nosev_y * roofv_x + nosev_x * roofv_y) / 96 EOR #%10000000 \ Set sidev_z = -A STA INWK+26 \ = (nosev_y * roofv_x - nosev_x * roofv_y) / 96 LDA #0 \ Set A = 0 so we can clear the low bytes of the \ orientation vectors LDX #14 \ We want to clear the low bytes, so start from sidev_y \ at byte #9+14 (we clear all except sidev_z_lo, though \ I suspect this is in error and that X should be 16) .TIL1 STA INWK+9,X \ Set the low byte in byte #9+X to zero DEX \ Set X = X - 2 to jump down to the next low byte DEX BPL TIL1 \ Loop back until we have zeroed all the low bytes RTS \ Return from the subroutine
Name: TIS2 [Show more] Type: Subroutine Category: Maths (Arithmetic) Summary: Calculate A = A / Q Deep dive: Shift-and-subtract division
Context: See this subroutine on its own page References: This subroutine is called as follows: * NORM calls TIS2

Calculate the following division, where A is a sign-magnitude number and Q is a positive integer: A = A / Q The value of A is returned as a sign-magnitude number with 96 representing 1, and the maximum value returned is 1 (i.e. 96). This routine is used when normalising vectors, where we represent fractions using integers, so this gives us an approximation to two decimal places.
.TIS2 TAY \ Store the argument A in Y AND #%01111111 \ Strip the sign bit from the argument, so A = |A| CMP Q \ If A >= Q then jump to TI4 to return a 1 with the BCS TI4 \ correct sign LDX #%11111110 \ Set T to have bits 1-7 set, so we can rotate through 7 STX T \ loop iterations, getting a 1 each time, and then \ getting a 0 on the 8th iteration... and we can also \ use T to catch our result bits into bit 0 each time .TIL2 ASL A \ Shift A to the left CMP Q \ If A < Q skip the following subtraction BCC P%+4 SBC Q \ A >= Q, so set A = A - Q \ \ Going into this subtraction we know the C flag is \ set as we passed through the BCC above, and we also \ know that A >= Q, so the C flag will still be set once \ we are done ROL T \ Rotate the counter in T to the left, and catch the \ result bit into bit 0 (which will be a 0 if we didn't \ do the subtraction, or 1 if we did) BCS TIL2 \ If we still have set bits in T, loop back to TIL2 to \ do the next iteration of 7 \ We've done the division and now have a result in the \ range 0-255 here, which we need to reduce to the range \ 0-96. We can do that by multiplying the result by 3/8, \ as 256 * 3/8 = 96 LDA T \ Set T = T / 4 LSR A LSR A STA T LSR A \ Set T = T / 8 + T / 4 ADC T \ = 3T / 8 STA T TYA \ Fetch the sign bit of the original argument A AND #%10000000 ORA T \ Apply the sign bit to T RTS \ Return from the subroutine .TI4 TYA \ Fetch the sign bit of the original argument A AND #%10000000 ORA #96 \ Apply the sign bit to 96 (which represents 1) RTS \ Return from the subroutine
Name: TIS3 [Show more] Type: Subroutine Category: Maths (Arithmetic) Summary: Calculate -(nosev_1 * roofv_1 + nosev_2 * roofv_2) / nosev_3
Context: See this subroutine on its own page References: This subroutine is called as follows: * TIDY calls TIS3

Calculate the following expression: A = -(nosev_1 * roofv_1 + nosev_2 * roofv_2) / nosev_3 where 1, 2 and 3 are x, y, or z, depending on the values of X, Y and A. This routine is called with the following values: X = 0, Y = 2, A = 4 -> A = -(nosev_x * roofv_x + nosev_y * roofv_y) / nosev_z X = 0, Y = 4, A = 2 -> A = -(nosev_x * roofv_x + nosev_z * roofv_z) / nosev_y X = 2, Y = 4, A = 0 -> A = -(nosev_y * roofv_y + nosev_z * roofv_z) / nosev_x Arguments: X Index 1 (0 = x, 2 = y, 4 = z) Y Index 2 (0 = x, 2 = y, 4 = z) A Index 3 (0 = x, 2 = y, 4 = z)
.TIS3 STA P+2 \ Store P+2 in A for later LDA INWK+10,X \ Set Q = nosev_x_hi (plus X) STA Q LDA INWK+16,X \ Set A = roofv_x_hi (plus X) JSR MULT12 \ Set (S R) = Q * A \ = nosev_x_hi * roofv_x_hi LDX INWK+10,Y \ Set Q = nosev_x_hi (plus Y) STX Q LDA INWK+16,Y \ Set A = roofv_x_hi (plus Y) JSR MAD \ Set (A X) = Q * A + (S R) \ = (nosev_x,X * roofv_x,X) + \ (nosev_x,Y * roofv_x,Y) STX P \ Store low byte of result in P, so result is now in \ (A P) LDY P+2 \ Set Q = roofv_x_hi (plus argument A) LDX INWK+10,Y STX Q EOR #%10000000 \ Flip the sign of A \ Fall through into DIVDT to do: \ \ (P+1 A) = (A P) / Q \ \ = -((nosev_x,X * roofv_x,X) + \ (nosev_x,Y * roofv_x,Y)) \ / nosev_x,A
Name: DVIDT [Show more] Type: Subroutine Category: Maths (Arithmetic) Summary: Calculate (P+1 A) = (A P) / Q
Context: See this subroutine on its own page References: No direct references to this subroutine in this source file

Calculate the following integer division between sign-magnitude numbers: (P+1 A) = (A P) / Q This uses the same shift-and-subtract algorithm as TIS2.
.DVIDT STA P+1 \ Set P+1 = A, so P(1 0) = (A P) EOR Q \ Set T = the sign bit of A EOR Q, so it's 1 if A and Q AND #%10000000 \ have different signs, i.e. it's the sign of the result STA T \ of A / Q LDA #0 \ Set A = 0 for us to build a result LDX #16 \ Set a counter in X to count the 16 bits in P(1 0) ASL P \ Shift P(1 0) left ROL P+1 ASL Q \ Clear the sign bit of Q the C flag at the same time LSR Q .DVL2 ROL A \ Shift A to the left CMP Q \ If A < Q skip the following subtraction BCC P%+4 SBC Q \ Set A = A - Q \ \ Going into this subtraction we know the C flag is \ set as we passed through the BCC above, and we also \ know that A >= Q, so the C flag will still be set once \ we are done ROL P \ Rotate P(1 0) to the left, and catch the result bit ROL P+1 \ into the C flag (which will be a 0 if we didn't \ do the subtraction, or 1 if we did) DEX \ Decrement the loop counter BNE DVL2 \ Loop back for the next bit until we have done all 16 \ bits of P(1 0) LDA P \ Set A = P so the low byte is in the result in A ORA T \ Set A to the correct sign bit that we set in T above RTS \ Return from the subroutine
Save ELTF.bin
PRINT "ELITE F" PRINT "Assembled at ", ~CODE_F% PRINT "Ends at ", ~P% PRINT "Code size is ", ~(P% - CODE_F%) PRINT "Execute at ", ~LOAD% PRINT "Reload at ", ~LOAD_F% PRINT "S.F.ELTF ", ~CODE_F%, " ", ~P%, " ", ~LOAD%, " ", ~LOAD_F% SAVE "3-assembled-output/F.ELTF.bin", CODE_F%, P%, LOAD%