Skip to navigation


Elite F flight 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 uses 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 high nibble of the low byte is the flush control (where a flush control of 0 queues the sound, and a flush control of 1 makes the sound instantly), while the low nibble of the low byte is the channel number. 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: rand_posn [Show more] Type: Subroutine Category: Universe Summary: Set up the INWK workspace for a ship in a random ship position
Context: See this subroutine on its own page References: This subroutine is called as follows: * Main game loop (Part 2 of 6) calls rand_posn * Ze calls rand_posn

This routine sets up a new ship, with the following coordinates: * (x_sign x_hi x_lo) is a random number in the range -8191 to +8191: * x_sign is randomly positive or negative * x_hi is a random number in the range 0 to 31 * x_lo is a random number in the range 0 to 255 * (y_sign y_hi y_lo) is a random number in the range -8191 to +8191: * y_sign is randomly positive or negative * y_hi is a random number in the range 0 to 31 * y_lo is a random number in the range 0 to 255 * z_sign is a random number in the range 4352 to 20224: * z_sign is 0 (positive) * z_hi is a random number in the range 17 to 79 * z_lo is 0 In other words, the ship is randomly up, down, left or right, but is always in front of us.
Returns: A A is set to a random number X X is set to a random number T1 T1 is set to a random number
\ --- Mod: Code added for Elite-A: --------------------> .rand_posn JSR ZINF \ Call ZINF to reset the INWK ship workspace JSR DORND \ Set A and X to random numbers STA INWK \ Set x_lo to the random number in A STX INWK+3 \ Set y_lo to the random number in X STA T1 \ Store x_lo in T1 LSR A \ Set bit 7 of x_sign randomly (to bit 0 of the random ROR INWK+2 \ number in A), so the x-coordinate it is randomly \ positive or negative LSR A \ Set bit 7 of y_sign randomly (to bit 1 of the random ROR INWK+5 \ number in A), so the y-coordinate it is randomly \ positive or negative LSR A \ Set bits 0-4 of y_hi randomly (to bits 3-7 of the STA INWK+4 \ random number in A), so the high byte of the \ y-coordinate is in the range 0 to 31 TXA \ Set x_hi to the random number X, reduced to the range AND #31 \ 0 to 31 STA INWK+1 LDA #80 \ Set z_hi = 80 - x_hi - y_hi - 1 SBC INWK+1 \ SBC INWK+4 \ The C flag is clear as INWK+4 was 0 before the ROR STA INWK+7 \ above, so this sets z_hi in the range 17 to 79 \ (as x_hi and y_hi are both in the range 0 to 31) JMP DORND \ Set A and X to random numbers and return from the \ subroutine using a tail call \ --- End of added code ------------------------------->
Name: THERE [Show more] Type: Subroutine Category: Missions Summary: Check whether we are in the Constrictor's system in mission 1
Context: See this subroutine on its own page References: This subroutine is called as follows: * LOMOD calls THERE * Main game loop (Part 4 of 6) calls THERE

The stolen Constrictor is the target of mission 1. We finally track it down to the Orarra system in the second galaxy, which is at galactic coordinates (144, 33). This routine checks whether we are in this system and sets the C flag accordingly.
Returns: C flag Set if we are in the Constrictor system, otherwise clear
.THERE LDX GCNT \ Set X = GCNT - 1 DEX BNE THEX \ If X is non-zero (i.e. GCNT is not 1, so we are not in \ the second galaxy), then jump to THEX LDA QQ0 \ Set A = the current system's galactic x-coordinate CMP #144 \ If A <> 144 then jump to THEX BNE THEX LDA QQ1 \ Set A = the current system's galactic y-coordinate CMP #33 \ If A = 33 then set the C flag BEQ THEX+1 \ If A = 33 then jump to THEX+1, so we return from the \ subroutine with the C flag set (otherwise we clear the \ C flag with the next instruction) .THEX CLC \ Clear the C flag RTS \ Return from the subroutine
Name: RESET [Show more] Type: Subroutine Category: Start and end Summary: Reset most variables
Context: See this subroutine on its own page References: This subroutine is called as follows: * RSHIPS calls RESET

Reset our ship and various controls, recharge shields and energy, and then fall through into RES2 to reset the stardust and the ship workspace at INWK. In this subroutine, this means zero-filling the following locations: * Pages &9, &A, &B, &C and &D * BETA to BETA+8, which covers the following: * BETA, BET1 - Set pitch to 0 * XC, YC - Set text cursor to (0, 0) * QQ22 - Set hyperspace counters to 0 * ECMA - Turn E.C.M. off * ALP1, ALP2 - Set roll signs to 0 It also sets QQ12 to &FF, to indicate we are docked, recharges the shields and energy banks, and then falls through into RES2.
.RESET 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 LDX #8 \ Set up a counter for zeroing BETA through BETA+8 .SAL3 STA BETA,X \ Zero the X-th byte after BETA DEX \ Decrement the loop counter BPL SAL3 \ Loop back for the next byte to zero TXA \ X is now negative - i.e. &FF - so this sets A to &FF LDX #2 \ We're now going to recharge both shields and the \ energy bank, which live in the three bytes at FSH, \ ASH (FSH+1) and ENERGY (FSH+2), so set a loop counter \ in X for 3 bytes .REL5 STA FSH,X \ Set the X-th byte of FSH to &FF to charge up that \ shield/bank DEX \ Decrement the loop counter BPL REL5 \ Loop back to REL5 until we have recharged both shields \ and the energy bank \ Fall through into RES2 to reset the stardust and ship \ workspace at INWK
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: * DEATH calls RES2 * DEATH2 calls RES2 * ESCAPE calls RES2 * Main flight loop (Part 9 of 16) calls RES2 * MJP calls RES2 * TT110 calls RES2 * TT18 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 and roll rates to the mid-point, STA JSTX \ 128 STA JSTY ASL A \ This sets A to 0 STA MCNT \ Reset MCNT (the main loop counter) to 0 STA QQ22+1 \ Set the on-screen hyperspace counter to 0 LDA #3 \ Reset DELTA (speed) to 3 STA DELTA LDA SSPR \ Fetch the "space station present" flag, and if we are BEQ P%+5 \ not inside the safe zone, skip the next instruction JSR SPBLB \ Light up the space station bulb on the dashboard 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 JSR DIALS \ Update the dashboard JSR U% \ Call U% to clear the key logger \ Finally, fall through into ZINF to reset the INWK \ ship workspace
Name: ZINF [Show more] Type: Subroutine Category: Universe 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: * DOKEY calls ZINF * FRS1 calls ZINF * KS4 calls ZINF * rand_posn calls ZINF * SOLAR 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 #%10000000 \ 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: msblob [Show more] Type: Subroutine Category: Dashboard Summary: Display the dashboard's missile indicators in green
Context: See this subroutine on its own page References: This subroutine is called as follows: * FRMIS calls msblob * SOS1 calls msblob

Display the dashboard's missile indicators, with all the missiles reset to green/cyan (i.e. not armed or locked).
Returns: X X is set to &FF Y Y is set to 0
.msblob \ --- Mod: Code removed for Elite-A: ------------------> \LDX #4 \ Set up a loop counter in X to count through all four \ \ missile indicators \ --- And replaced by: --------------------------------> LDX #3 \ Set up a loop counter in X to count through all four \ missile indicators (in Elite-A the missile indicators \ are numbered 0-3 rather than 1-4) \ --- End of replacement ------------------------------> .ss \ --- Mod: Code removed for Elite-A: ------------------> \CPX NOMSL \ If the counter is equal to the number of missiles, \BEQ SAL8 \ jump down to SAL8 to draw the remaining missiles, as \ \ the rest of them are present and should be drawn in \ \ green/cyan \ \LDY #0 \ Draw the missile indicator at position X in black \JSR MSBAR \ \DEX \ Decrement the counter to point to the next missile \ \BNE ss \ Loop back to ss if we still have missiles to draw \ \RTS \ Return from the subroutine \ \.SAL8 \ \LDY #&EE \ Draw the missile indicator at position X in green/cyan \JSR MSBAR \ \DEX \ Decrement the counter to point to the next missile \ \BNE SAL8 \ Loop back to SAL8 if we still have missiles to draw \ --- And replaced by: --------------------------------> LDY #0 \ If X >= NOMSL, then jump down to miss_miss with Y = 0 CPX NOMSL \ to draw the missile indicator at position X in black BCS miss_miss LDY #&EE \ Set the colour of the missile indicator to green/cyan .miss_miss JSR MSBAR \ Draw the missile indicator at position X in colour Y, \ and return with Y = 0 DEX \ Decrement the counter to point to the next missile BPL ss \ Loop back to ss if we still have missiles to draw, \ ending when X = &FF \ --- End of replacement ------------------------------> RTS \ Return from the subroutine
Name: me2 [Show more] Type: Subroutine Category: Flight 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: Ze [Show more] Type: Subroutine Category: Universe Summary: Initialise the INWK workspace to a hostile ship Deep dive: Fixing ship positions
Context: See this subroutine on its own page References: This subroutine is called as follows: * DEATH calls Ze * GTHG calls Ze * Main game loop (Part 3 of 6) calls Ze

Specifically, this routine does the following: * Reset the INWK ship workspace * Set the ship to a fair distance away in all axes, in front of us but randomly up or down, left or right * Give the ship a 4% chance of having E.C.M. * Set the ship to hostile, with AI enabled This routine also sets A, X, T1 and the C flag to random values. Note that because this routine uses the value of X returned by DORND, and X contains the value of A returned by the previous call to DORND, this routine does not necessarily set the new ship to a totally random location.
.Ze \ --- Mod: Code removed for Elite-A: ------------------> \JSR ZINF \ Call ZINF to reset the INWK ship workspace \ \JSR DORND \ Set A and X to random numbers \ \STA T1 \ Store A in T1 \ \AND #%10000000 \ Extract the sign of A and store in x_sign \STA INWK+2 \ \TXA \ Extract the sign of X and store in y_sign \AND #%10000000 \STA INWK+5 \ \LDA #25 \ Set x_hi = y_hi = z_hi = 25, a fair distance away \STA INWK+1 \STA INWK+4 \STA INWK+7 \ \JSR DORND \ Set A and X to random numbers \ --- And replaced by: --------------------------------> JSR rand_posn \ Call rand_posn to set up the INWK workspace for a ship \ in a random ship position, and set T1 to a random \ number \ --- End of replacement ------------------------------> CMP #245 \ Set the C flag if A >= 245 (4% chance) ROL A \ Set bit 0 of A to the C flag (i.e. there's a 4% \ chance of this ship having E.C.M.) ORA #%11000000 \ Set bits 6 and 7 of A, so the ship is hostile (bit 6 \ and has AI (bit 7) STA INWK+32 \ Store A in the AI flag of this ship \ Fall through into DORND2 to set A, X and the C flag \ randomly
Name: DORND [Show more] 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. 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.
Other entry points: DORND2 Make sure the C flag doesn't affect the outcome
.DORND2 CLC \ Clear the C flag so the value of the C flag on entry \ doesn't affect the outcome .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 1 of 6) [Show more] Type: Subroutine Category: Main loop Summary: Spawn a trader (a Cobra Mk III, Python, Boa or Anaconda) Deep dive: Program flow of the main game loop Ship data blocks
Context: See this subroutine on its own page References: No direct references to this subroutine in this source file

This is part of the main game loop. This is where the core loop of the game lives, and it's in two parts. The shorter loop (just parts 5 and 6) is iterated when we are docked, while the entire loop from part 1 to 6 iterates if we are in space. This section covers the following: * Spawn a trader, i.e. a Cobra Mk III, Python, Boa or Anaconda, with a 50% chance of it having a missile, a 50% chance of it having an E.C.M., a 50% chance of it docking and being aggressive if attacked, a speed between 16 and 31, and a gentle clockwise roll We call this from within the main loop.
.MTT4 JSR DORND \ Set A and X to random numbers LSR A \ Clear bit 7 of our random number in A and set the C \ flag to bit 0 of A, which is random STA INWK+32 \ Store this in the ship's AI flag, so this ship does \ not have AI STA INWK+29 \ Store A in the ship's roll counter, giving it a \ clockwise roll (as bit 7 is clear), and a 1 in 127 \ chance of it having no damping ROL INWK+31 \ Set bit 0 of the ship's missile count randomly (as the \ C flag was set), giving the ship either no missiles or \ one missile \ --- Mod: Code removed for Elite-A: ------------------> \AND #15 \ Set the ship speed to our random number, set to a \ORA #16 \ minimum of 16 and a maximum of 31 \STA INWK+27 \ --- And replaced by: --------------------------------> AND #15 \ Set the ship speed to our random number, set to a STA INWK+27 \ minimum of 0 and a maximum of 15 \ --- End of replacement ------------------------------> JSR DORND \ Set A and X to random numbers, plus the C flag BMI nodo \ If A is negative (50% chance), jump to nodo to skip \ the following \ If we get here then we are going to spawn a ship that \ is minding its own business and trying to dock LDA INWK+32 \ Set bits 6 and 7 of the ship's AI flag, to make it ORA #%11000000 \ aggressive if attacked, and enable its AI STA INWK+32 LDX #%00010000 \ Set bit 4 of the ship's NEWB flags, to indicate that STX NEWB \ this ship is docking .nodo \ --- Mod: Code removed for Elite-A: ------------------> \AND #2 \ If we jumped here with a random value of A from the \ \ BMI above, then this reduces A to a random value of \ \ either 0 or 2; if we didn't take the BMI and made the \ \ ship hostile, then A will be 0 \ \ADC #CYL \ Set A = A + C + #CYL \ \ \ \ where A is 0 or 2 and C is 0 or 1, so this gives us a \ \ ship type from the following: Cobra Mk III, Python, \ \ Boa or Anaconda \ \JSR NWSHP \ Add a new ship of type A to the local bubble and fall \ \ through into the main game loop again \ --- And replaced by: --------------------------------> LDA #11 \ Call hordes to spawn a pack of ships from ship slots LDX #3 \ 11 to 14, which is where the trader ships live in the JMP hordes \ ship files \ --- End of replacement ------------------------------>
Name: Main game loop (Part 2 of 6) [Show more] Type: Subroutine Category: Main loop Summary: Call the main flight loop, and potentially spawn a trader, an asteroid, or a cargo canister 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 6 of 6) calls via TT100 * me2 calls via me3

This section covers the following: * Call M% to do the main flight loop * Potentially spawn a trader, asteroid or cargo canister
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 JSR M% \ Call M% to iterate through the main flight loop 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 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 \ --- Mod: Code removed for Elite-A: ------------------> \CMP #35 \ If A >= 35 (87% chance), jump down to MTT1 to skip \BCS MTT1 \ the spawning of an asteroid or cargo canister and \ \ potentially spawn something else \ --- And replaced by: --------------------------------> CMP #51 \ If A >= 51 (80% chance), jump down to MTT1 to skip BCS MTT1 \ the spawning of an asteroid or cargo canister and \ potentially spawn something else \ --- End of replacement ------------------------------> LDA JUNK \ If we already have 3 or more bits of junk in the local CMP #3 \ bubble, jump down to MTT1 to skip the following and BCS MTT1 \ potentially spawn something else \ --- Mod: Code removed for Elite-A: ------------------> \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 \ \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) \ \JSR DORND \ Set A, X and V flag to random numbers \ \BVS MTT4 \ If V flag is set (50% chance), jump up to MTT4 to \ \ spawn a trader \ \IF _STH_DISC OR _SRAM_DISC \ \NOP \ In the first version of disc Elite, asteroids never \NOP \ appeared. It turned out that the authors had put in a \NOP \ jump to force traders to spawn, so they could test \ \ that part of the code, but had forgotten to remove it, \ \ so this was fixed in later versions by replacing the \ \ JMP instruction with NOPs... and this is where that \ \ was done \ \ELIF _IB_DISC \ \JMP MTT4 \ In the first version of disc Elite, asteroids never \ \ appeared. It turned out that the authors had put in a \ \ jump to force traders to spawn, so they could test \ \ that part of the code, but had forgotten to remove it, \ \ so this was fixed in later versions by replacing the \ \ JMP instruction with NOPs. The version on Ian Bell's \ \ site still contains the test jump, so asteroids never \ \ appear in this version \ \ENDIF \ \ORA #%01101111 \ Take the random number in A and set bits 0-3 and 5-6, \STA INWK+29 \ so the result has a 50% chance of being positive or \ \ negative, and a 50% chance of bits 0-6 being 127. \ \ Storing this number in the roll counter therefore \ \ gives our new ship a fast roll speed with a 50% \ \ chance of having no damping, plus a 50% chance of \ \ rolling clockwise or anti-clockwise \ \LDA SSPR \ If we are inside the space station safe zone, jump \BNE MTT1 \ down to MTT1 to skip the following and potentially \ \ spawn something else \ \TXA \ Set A to the random X we set above, which we haven't \BCS MTT2 \ used yet, and if the C flag is set (50% chance) jump \ \ down to MTT2 to skip the following \ \AND #31 \ Set the ship speed to our random number, set to a \ORA #16 \ minimum of 16 and a maximum of 31 \STA INWK+27 \ --- And replaced by: --------------------------------> JSR rand_posn \ Call rand_posn to set up the INWK workspace for a ship \ in a random ship position BVS MTT4 \ If V flag is set (50% chance), jump up to MTT4 to \ spawn a trader ORA #%01101111 \ Take the random number in A and set bits 0-3 and 5-6, STA INWK+29 \ so the result has a 50% chance of being positive or \ negative, and a 50% chance of bits 0-6 being 127. \ Storing this number in the roll counter therefore \ gives our new ship a fast roll speed with a 50% \ chance of having no damping, plus a 50% chance of \ rolling clockwise or anti-clockwise LDA SSPR \ If we are inside the space station safe zone, jump BNE MLOOPS \ down to MLOOPS to stop spawning TXA \ Set A to the random X we set above, which we haven't BCS MTT2 \ used yet, and if the C flag is set (50% chance) jump \ down to MTT2 to skip the following AND #15 \ Set the ship speed to our random number, reduced to STA INWK+27 \ the range 0 to 15 \ --- End of replacement ------------------------------> BCC MTT3 \ Jump down to MTT3, skipping the following (this BCC \ is effectively a JMP as we know the C flag is clear, \ having passed through the BCS above) .MTT2 ORA #%01111111 \ Set bits 0-6 of A to 127, leaving bit 7 as random, so STA INWK+30 \ storing this number in the pitch counter means we have \ full pitch with no damping, with a 50% chance of \ pitching up or down .MTT3 JSR DORND \ Set A and X to random numbers CMP #10 \ If random A >= 10 (96% of the time), set the C flag AND #1 \ Reduce A to a random number that's 0 or 1 ADC #OIL \ Set A = #OIL + A + C, so there's a tiny chance of us \ spawning a cargo canister (#OIL) and an even chance of \ us spawning either a boulder (#OIL + 1) or an asteroid \ (#OIL + 2) \ --- Mod: Code removed for Elite-A: ------------------> \JSR NWSHP \ Add our new asteroid or canister to the universe \ --- And replaced by: --------------------------------> BNE horde_plain \ Jump to horde_plain to spawn a whole pack of cargo \ canisters, boulders or asteroids, according to the \ value of A (the BNE is effectively a JMP, as A will \ never be zero) \ --- End of replacement ------------------------------>
Name: Main game loop (Part 3 of 6) [Show more] Type: Subroutine Category: Main loop Summary: Potentially spawn a cop, particularly if we've been bad Deep dive: Program flow of the main game loop Ship data blocks Fixing ship positions
Context: See this subroutine on its own page References: No direct references to this subroutine in this source file

This section covers the following: * Potentially spawn a cop (in a Viper), very rarely if we have been good, more often if have been naughty, and very often if we have been properly bad
.MTT1 LDA SSPR \ If we are outside the space station's safe zone, skip BEQ P%+5 \ the following instruction .MLOOPS JMP MLOOP \ Jump to MLOOP to skip the following JSR BAD \ Call BAD to work out how much illegal contraband we \ are carrying in our hold (A is up to 40 for a \ standard hold crammed with contraband, up to 70 for \ an extended cargo hold full of narcotics and slaves) ASL A \ Double A to a maximum of 80 or 140 LDX MANY+COPS \ If there are no cops in the local bubble, skip the BEQ P%+5 \ next instruction ORA FIST \ There are cops in the vicinity and we've got a hold \ full of jail time, so OR the value in A with FIST to \ get a new value that is at least as high as both \ values, to reflect the fact that they have almost \ certainly scanned our ship STA T \ Store our badness level in T JSR Ze \ Call Ze to initialise INWK to a potentially hostile \ ship, and set A and X to random values \ \ Note that because Ze uses 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 \ --- Mod: Code removed for Elite-A: ------------------> \CMP T \ If the random value in A >= our badness level, which \BCS P%+7 \ will be the case unless we have been really, really \ \ bad, then skip the following two instructions (so \ \ if we are really bad, there's a higher chance of \ \ spawning a cop, otherwise we got away with it, for \ \ now) \ \LDA #COPS \ Add a new police ship to the local bubble \JSR NWSHP \ --- And replaced by: --------------------------------> CMP T \ If the random value in A >= our badness level, which BCS P%+8 \ will be the case unless we have been really, really \ bad, then skip the following three instructions (so \ if we are really bad, there's a higher chance of \ spawning a cop, otherwise we got away with it, for \ now) LDA #COPS \ Set A to the ship type for a cop, so the following \ call to hordes will spawn a pack of cops .horde_plain LDX #0 \ Jump to hordes to spawn a pack of ships of type A, BEQ hordes \ returning from the subroutine using a tail call (the \ BEQ is effectively a JMP as X is always zero) \ --- End of replacement ------------------------------> LDA MANY+COPS \ If we now have at least one cop in the local bubble, BNE MLOOPS \ jump down to MLOOPS to stop spawning, otherwise fall \ through into the next part to look at spawning \ something else
Name: Main game loop (Part 4 of 6) [Show more] Type: Subroutine Category: Main loop Summary: Potentially spawn a lone bounty hunter or up to four pirates 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 1 of 6) calls via hordes * Main game loop (Part 3 of 6) calls via hordes

This section covers the following: * Potentially spawn (47% chance) either a pack of up to 8 bounty hunters, or a pack of up to 8 pirates * Also potentially spawn a Constrictor if this is the mission 1 endgame, or Thargoids if mission 2 is in progress
Other entry points: hordes Spawn a pack of ships, made up of ships from type A to type A + X, with the pack size normally being one to four ships, but rarely being up to eight ships
DEC EV \ Decrement EV, the extra vessels spawning delay, and if BPL MLOOPS \ it is still positive, jump to MLOOPS to stop spawning, \ so we only do the following when the EV counter runs \ down INC EV \ EV is negative, so bump it up again, setting it back \ to 0 LDA TP \ Fetch bits 2 and 3 of TP, which contain the status of AND #%00001100 \ mission 2 CMP #%00001000 \ If bit 3 is set and bit 2 is clear, keep going to BNE nopl \ spawn a Thargoid as we are transporting the plans in \ mission 2 and the Thargoids are trying to stop us, \ otherwise jump to nopl to skip spawning a Thargoid JSR DORND \ Set A and X to random numbers CMP #200 \ If the random number in A < 200 (78% chance), jump to BCC nopl \ nopl to skip spawning a Thargoid .fothg2 JSR GTHG \ Call GTHG to spawn a Thargoid ship and a Thargon \ companion .nopl JSR DORND \ Set A and X to random numbers LDY gov \ If the government of this system is 0 (anarchy), jump BEQ LABEL_2 \ straight to LABEL_2 to start spawning pirates or \ bounty hunters CMP #120 \ If the random number in A >= 120 (53% chance), jump to BCS MLOOPS \ MLOOPS to stop spawning (so there's a 47% chance of \ spawning pirates or bounty hunters) AND #7 \ Reduce the random number in A to the range 0-7, and CMP gov \ if A is less than government of this system, jump BCC MLOOPS \ to MLOOPS to stop spawning (so safer governments with \ larger gov numbers have a greater chance of jumping \ out, which is another way of saying that more \ dangerous systems spawn pirates and bounty hunters \ more often) .LABEL_2 \ --- Mod: Code removed for Elite-A: ------------------> \ \ Now to spawn a lone bounty hunter or a group of \ \ pirates \ \JSR Ze \ Call Ze to initialise INWK to a potentially hostile \ \ ship, and set A and X to random values \ \ \ \ Note that because Ze uses 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 \ \CMP #100 \ If the random number in A >= 100 (61% chance), jump \BCS mt1 \ to mt1 to spawn pirates, otherwise keep going to \ \ spawn a lone bounty hunter \ --- And replaced by: --------------------------------> \ Now to spawn a group of bounty hunters, a Thargoid or \ a pack of pirates CPX #100 \ If the random number in X >= 100 (61% chance), jump BCS mt1 \ to mt1 to spawn pirates, otherwise keep going to \ spawn bounty hunters or a Thargoid \ --- End of replacement ------------------------------> INC EV \ Increase the extra vessels spawning counter, to \ prevent the next attempt to spawn extra vessels AND #3 \ Set A = random number in the range 0-3, which we \ will now use to determine the type of ship \ --- Mod: Code removed for Elite-A: ------------------> \ADC #CYL2 \ Add A to #CYL2 (we know the C flag is clear as we \ \ passed through the BCS above), so A is now one of the \ \ lone bounty hunter ships, i.e. Cobra Mk III (pirate), \ \ Asp Mk II, Python (pirate) or Fer-de-lance \ \ \ \ Interestingly, this logic means that the Moray, which \ \ is the ship after the Fer-de-lance in the XX21 table, \ \ never spawns, as the above logic chooses a blueprint \ \ number in the range CYL2 to CYL2+3 (i.e. 24 to 27), \ \ and the Moray is blueprint 28 \ \ \ \ No other code spawns the ship with blueprint 28, so \ \ this means the Moray is never seen in Elite \ \ \ \ This is presumably a bug, which could be very easily \ \ fixed by inserting one of the following instructions \ \ before the ADC #CYL2 instruction above: \ \ \ \ * SEC would change the range to 25 to 28, which \ \ would cover the Asp Mk II, Python (pirate), \ \ Fer-de-lance and Moray \ \ \ \ * LSR A would set the C flag to a random number to \ \ give a range of 24 to 28, which would cover the \ \ Cobra Mk III (pirate), Asp Mk II, Python (pirate), \ \ Fer-de-lance and Moray \ \ \ \ It's hard to know what the authors' original intent \ \ was, but the second approach makes the Moray and Cobra \ \ Mk III the rarest choices, with the Asp Mk II, Python \ \ and Fer-de-Lance being more likely, and as the Moray \ \ is described in the literature as a rare ship, and the \ \ Cobra can already be spawned as part of a group of \ \ pirates (see mt1 below), I tend to favour the LSR A \ \ solution over the SEC approach \ --- And replaced by: --------------------------------> ADC #25 \ Add A to 25 (we know the C flag is clear as we passed \ through the BCS above), so A is now a ship blueprint \ position in the range 25-28, which is where the bounty \ hunter ships live in the ship files \ --- End of replacement ------------------------------> TAY \ Copy the new ship type to Y JSR THERE \ Call THERE to see if we are in the Constrictor's \ system in mission 1 BCC NOCON \ If the C flag is clear then we are not in the \ Constrictor's system, so skip to NOCON LDA #%11111001 \ Set the AI flag of this ship so that it has E.C.M., STA INWK+32 \ has a very high aggression level of 28 out of 31, is \ hostile, and has AI enabled - nasty stuff! LDA TP \ Fetch bits 0 and 1 of TP, which contain the status of AND #%00000011 \ mission 1 LSR A \ Shift bit 0 into the C flag BCC NOCON \ If bit 0 is clear, skip to NOCON as mission 1 is not \ in progress ORA MANY+CON \ Bit 0 of A now contains bit 1 of TP, so this will be \ set if we have already completed mission 1, so this OR \ will be non-zero if we have either completed mission \ 1, or there is already a Constrictor in our local \ bubble of universe (in which case MANY+CON will be \ non-zero) BEQ YESCON \ If A = 0 then mission 1 is in progress, we haven't \ completed it yet, and there is no Constrictor in the \ vicinity, so jump to YESCON to spawn the Constrictor .NOCON TYA \ Set A to the new ship type in Y EQUB &2C \ Skip the next instruction by turning it into \ &2C &A9 &1F, or BIT &1FA9, which does nothing apart \ from affect the flags .YESCON LDA #CON \ If we jump straight here, we are in the mission 1 \ endgame and it's time to spawn the Constrictor, so \ set A to the Constrictor's type .focoug JSR NWSHP \ Spawn the new ship, whether it's a pirate or \ Constrictor .mj1 JMP MLOOP \ Jump down to MLOOP, as we are done spawning ships .mt1 \ --- Mod: Code removed for Elite-A: ------------------> \AND #3 \ It's time to spawn a group of pirates, so set A to a \ \ random number in the range 0-3, which will be the \ \ loop counter for spawning pirates below (so we will \ \ spawn 1-4 pirates) \ \STA EV \ Delay further spawnings by this number \ \STA XX13 \ Store the number in XX13, the pirate counter \ \.mt3 \ \JSR DORND \ Set A and X to random numbers \ \STA T \ Set T to a random number \ \JSR DORND \ Set A and X to random numbers \ \AND T \ Set A to the AND of two random numbers, so each bit \ \ has 25% chance of being set which makes the chances \ \ of a smaller number higher \ \AND #7 \ Reduce A to a random number in the range 0-7, though \ \ with a bigger chance of a smaller number in this range \ \STA CPIR \ Set CPIR to this random number in the range 0-7 \ \.more \ \LDA CPIR \ Set A to the ship type in CPIR \ \ADC #PACK \ #PACK is set to #SH3, the ship type for a Sidewinder, \ \ so this sets our new ship type to one of the pack \ \ hunters, namely a Sidewinder, Mamba, Krait, Adder, \ \ Gecko, Cobra Mk I, Worm or Cobra Mk III (pirate) \ --- And replaced by: --------------------------------> LDA #17 \ Fall through into hordes to spawn a pack of ships from LDX #7 \ ship blueprint positions 17 to 24, which is where the \ pirate ships live in the ship blueprint files .hordes \ This routine spawns a pack of ships, made up of ships \ from type A to type A + X, with the pack size normally \ being one to four ships, but rarely being up to eight \ ships \ \ Let's call A the "base ship type", and X the "ship \ type range" STA horde_base+1 \ Modify the ADC instruction at horde_base so that it \ adds the base ship type given in A STX horde_mask+1 \ Modify the ADC instruction at horde_mask so that it \ ANDs the ship type range given in X JSR DORND \ Set A and X to random numbers CMP #248 \ If A >= 248 (3.1% chance), jump to horde_large so we BCS horde_large \ potentially spawn a larger pack (i.e. up to 8 ships) STA XX13 \ We are going to spawn a smaller pack (i.e. up to 4 TXA \ ships), so set: AND XX13 \ AND #3 \ A = A AND X AND 3 \ \ to give a random pack size of 0-3, with a greater \ chance of the smaller numbers than the larger ones \ (due to the AND). This will be our pack size, which \ won't be affected further by the following AND \ instruction .horde_large AND #7 \ If we are going to spawn a larger pack, reduce the \ random number in A to the range 0-7, with an equal \ chance of each of the numbers. This will be our pack \ size \ By this point our pack size is in A, and is either \ 0-3 or 0-7 STA EV \ Delay further spawnings by this number STA XX13 \ Store the number in XX13, the pack size counter .mt3 JSR DORND \ Set A and X to random numbers STA T \ Set A = A AND X TXA \ AND T \ which is in the range 0-255, but with a greater chance \ of being a smaller number (due to the AND) .horde_mask AND #&FF \ This instruction gets modified so that it ANDs the \ ship type range given in the argument X to the \ hordes routine, i.e. it turns into AND #type_range, \ which reduces our random number to be between 0 and \ the ship type range (so if we add this number to the \ base ship type, it will pick a random ship type from \ within the range A to A + X, where A and X are the \ arguments to the original call to hordes STA CPIR \ Set CPIR to our random number in the range 0 to \ the ship type .more LDA CPIR \ Set A to the ship type in CPIR CLC \ Clear the C flag for the addition below .horde_base ADC #0 \ This instruction gets modified so that it adds the \ ship type given in the argument A to the hordes \ routine, i.e. it turns into ADC #ship_type, so this \ sets A to a ship type in the range we want INC INWK+27 \ Increment the speed of the ship we are about to spawn, \ so later ships in the pack go faster INC INWK+1 \ Increment the x_hi coordinate of the ship we are about \ to spawn, so later ships in the pack are spread out to \ the sides INC INWK+4 \ Increment the y_hi coordinate of the ship we are about \ to spawn, so later ships in the pack are spread out \ to the top and bottom \ --- End of replacement ------------------------------> JSR NWSHP \ Try adding a new ship of type A to the local bubble \ --- Mod: Code removed for Elite-A: ------------------> \BCS P%+7 \ If the ship was successfully added, skip the following \ \ two instructions \ \DEC CPIR \ The ship wasn't added, which might be because the ship \ \ blueprint for this ship type isn't in the currently \ \ loaded ship blueprints file, so decrement CPIR to \ \ point to the previous ship type, so we can try \ \ spawning that type of pirate instead \ \BPL more \ Loop back to more to have another go at spawning this \ \ pirate, until we have tried spawning a Sidewinder when \ \ CPIR is 0, in which case give up and move on to the \ \ next pirate to spawn \ \DEC XX13 \ Decrement the pirate counter \ \BPL mt3 \ If we need more pirates, loop back up to mt3, \ \ otherwise we are done spawning, so fall through into \ \ the end of the main loop at MLOOP \ --- And replaced by: --------------------------------> CMP #24 \ This compares the value of A (which is set to the \ x_sign value of the spawned ship by NWSHP), but the \ result isn't used anywhere, as CMP affects the Z and N \ flags (not the C flag), and these same flags will be \ overwritten by the two DEC instructions below... so \ this instruction has no effect BCS P%+7 \ If the ship was successfully added, skip the following \ two instructions DEC CPIR \ The ship wasn't added, which might be because the ship \ blueprint for this ship type isn't in the currently \ loaded ship blueprints file, so decrement CPIR to \ point to the previous ship type, so we can try \ spawning that type of ship instead BPL more \ Loop back to more to have another go at spawning this \ ship, until CPIR is 0, in which case we have tried \ spawning all the ship types in the range, so give up \ and move on to the next pirate to spawn DEC XX13 \ Decrement the pack size counter BPL mt3 \ If we need more ships, loop back up to mt3, \ otherwise we are done spawning, so fall through into \ the end of the main loop at MLOOP \ --- End of replacement ------------------------------>
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 2 of 6) calls via MLOOP * Main game loop (Part 3 of 6) calls via MLOOP * Main game loop (Part 4 of 6) calls via 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 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 \ --- Mod: Code removed for Elite-A: ------------------> \LDA QQ11 \ If this is a space view, skip the following five \BEQ P%+13 \ instructions (i.e. jump to JSR TT17 below) \ \AND PATG \ If PATG = &FF (author names are shown on start-up) \LSR A \ and bit 0 of QQ11 is 1 (the current view is type 1), \BCS P%+7 \ then skip the following two instructions \ --- And replaced by: --------------------------------> 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 replacement ------------------------------> 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: * RSHIPS calls via 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 supports 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 \ --- Mod: Code added for Elite-A: --------------------> PHA \ Store the key to "press" in A on the stack LDA QQ22+1 \ Fetch QQ22+1, which contains the number that's shown \ on-screen during hyperspace countdown BNE l_locked \ If the hyperspace countdown is non-zero, jump to \ l_locked so the key does not get "pressed" PLA \ Retrieve the key to "press" from the stack into A so \ we can now process it \ --- End of added code -------------------------------> JSR TT102 \ Call TT102 to process the key pressed in A JMP TT100 \ Otherwise jump to TT100 to restart the main loop from \ the start \ --- Mod: Code added for Elite-A: --------------------> .l_locked PLA \ Retrieve the key to "press" from the stack into A JSR TT107 \ Call TT107 to progress the countdown of the hyperspace \ counter JMP TT100 \ Jump to TT100 to restart the main loop from the start \ --- End of added code ------------------------------->
Name: TT102 [Show more] Type: Subroutine Category: Keyboard Summary: Process function key, save key, hyperspace and chart key presses and update the hyperspace counter
Context: See this subroutine on its own page References: This subroutine is called as follows: * Main game loop (Part 6 of 6) calls TT102 * Main game loop (Part 3 of 6) calls via BAD * TT110 calls via BAD * Main game loop (Part 6 of 6) calls via TT107

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: BAD Work out how bad we are from the amount of contraband in our hold T95 Print the distance to the selected system TT107 Progress the countdown of the hyperspace counter
.TT102 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 .TT92 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 .fvw CMP #f1 \ If the key pressed is < red key f1 or > red key f3, BCC LABEL_3 \ jump to LABEL_3 (so only do the following if the key CMP #f3+1 \ pressed is f1, f2 or f3) BCS LABEL_3 AND #3 \ If we get here then we are either in space, or we are TAX \ docked and none of f1-f3 were pressed, so we can now JMP LOOK1 \ process f1-f3 with their in-flight functions, i.e. \ switching space views \ \ A will contain &71, &72 or &73 (for f1, f2 or f3), so \ set X to the last digit (1, 2 or 3) and jump to LOOK1 \ to switch to view X (rear, left or right), returning \ from the subroutine using a tail call .LABEL_3 CMP #&54 \ If "H" was pressed, jump to hyp to do a hyperspace BNE P%+5 \ jump (if we are in space), returning from the JMP hyp \ subroutine using a tail call 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) \ --- Mod: Code added for Elite-A: --------------------> CMP #&43 \ If "F" was not pressed, jump down to HME1, otherwise BNE HME1 \ keep going to toggle the compass display LDA finder \ Set the value of A to finder, which determines whether \ the compass is configured to show the sun or the \ planet EOR #NI% \ The value of finder is 0 (show the planet) or NI% \ (show the sun), so this toggles the value between the \ two STA finder \ Store the toggled value in finder JMP WSCAN \ Jump to WSCAN to wait for the vertical sync and return \ from the subroutine using a tail call .HME1 \ --- End of added code -------------------------------> STA T1 \ Store A (the key that's been pressed) in T1 \ --- Mod: Code removed for Elite-A: ------------------> \LDA QQ11 \ If the current view is a chart (QQ11 = 64 or 128), \AND #%11000000 \ keep going, otherwise jump down to TT107 to skip the \BEQ TT107 \ following \ \LDA QQ22+1 \ If the on-screen hyperspace counter is non-zero, \BNE TT107 \ then we are already counting down, so jump to TT107 \ \ to skip the following \ --- And replaced by: --------------------------------> LDA QQ11 \ If the current view is a chart (QQ11 = 64 or 128), AND #%11000000 \ keep going, otherwise jump down to TT107 to skip the BEQ TT107 \ following and move on to updating the hyperspace \ counter \ --- End of replacement ------------------------------> LDA T1 \ Restore the original value of A (the key that's been \ pressed) from T1 \ --- Mod: Code removed for Elite-A: ------------------> \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 \ --- Mod: Code removed for Elite-A: ------------------> \JSR TT103 \ Draw small crosshairs at coordinates (QQ9, QQ10), \ \ which will draw the crosshairs at our current home \ \ system \ --- And replaced by: --------------------------------> JMP TT103 \ Draw small crosshairs at coordinates (QQ9, QQ10), \ which will draw the crosshairs at our current home \ system, and return from the subroutine using a tail \ call \ --- End of replacement ------------------------------> .ee2 JSR TT16 \ Call TT16 to move the crosshairs by the amount in X \ and Y, which were passed to this subroutine as \ arguments .TT107 LDA QQ22+1 \ If the on-screen hyperspace counter is zero, return BEQ t95 \ from the subroutine (as t95 contains an RTS), as we \ are not currently counting down to a hyperspace jump DEC QQ22 \ Decrement the internal hyperspace counter BNE t95 \ If the internal hyperspace counter is still non-zero, \ then we are still counting down, so return from the \ subroutine (as t95 contains an RTS) \ If we get here then the internal hyperspace counter \ has just reached zero and it wasn't zero before, so \ we need to reduce the on-screen counter and update \ the screen. We do this by first printing the next \ number in the countdown sequence, and then printing \ the old number, which will erase the old number \ and display the new one because printing uses EOR \ logic LDX QQ22+1 \ Set X = the on-screen hyperspace counter - 1 DEX \ (i.e. the next number in the sequence) JSR ee3 \ Print the 8-bit number in X at text location (0, 1) LDA #5 \ Reset the internal hyperspace counter to 5 STA QQ22 LDX QQ22+1 \ Set X = the on-screen hyperspace counter (i.e. the \ current number in the sequence, which is already \ shown on-screen) JSR ee3 \ Print the 8-bit number in X at text location (0, 1), \ i.e. print the hyperspace countdown in the top-left \ corner DEC QQ22+1 \ Decrement the on-screen hyperspace countdown BNE t95 \ If the countdown is not yet at zero, return from the \ subroutine (as t95 contains an RTS) JMP TT18 \ Otherwise the countdown has finished, so jump to TT18 \ to do a hyperspace jump, returning from the subroutine \ using a tail call \ --- Mod: Code added for Elite-A: --------------------> .BAD LDA QQ20+3 \ Set A to the number of tonnes of slaves in the hold CLC \ Clear the C flag so we can do addition without the \ C flag affecting the result ADC QQ20+6 \ Add the number of tonnes of narcotics in the hold ASL A \ Double the result and add the number of tonnes of ADC QQ20+10 \ firearms in the hold \ --- End of added code -------------------------------> .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) \ --- Mod: Code removed for Elite-A: ------------------> \LDA #%10000000 \ Set bit 7 of QQ17 to switch to Sentence Case, with the \STA QQ17 \ next letter in capitals \ --- And replaced by: --------------------------------> JSR vdu_80 \ Call vdu_80 to switch to Sentence Case, with the next \ letter in capitals \ --- End of replacement ------------------------------> 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: BAD, Removed [Show more] Type: Subroutine Category: Status Summary: Calculate how bad we have been
Context: See this subroutine on its own page References: No direct references to this subroutine in this source file

Work out how bad we are from the amount of contraband in our hold. The formula is: (slaves + narcotics) * 2 + firearms so slaves and narcotics are twice as illegal as firearms. The value in FIST (our legal status) is set to at least this value whenever we launch from a space station, and a FIST of 50 or more gives us fugitive status, so leaving a station carrying 25 tonnes of slaves/narcotics, or 50 tonnes of firearms across multiple trips, is enough to make us a fugitive.
Returns: A A value that determines how bad we are from the amount of contraband in our hold
\ --- Mod: Code removed for Elite-A: ------------------> \.BAD \ \LDA QQ20+3 \ Set A to the number of tonnes of slaves in the hold \ \CLC \ Clear the C flag so we can do addition without the \ \ C flag affecting the result \ \ADC QQ20+6 \ Add the number of tonnes of narcotics in the hold \ \ASL A \ Double the result and add the number of tonnes of \ADC QQ20+10 \ firearms in the hold \ \RTS \ Return from the subroutine \ --- End of removed code ----------------------------->
Name: FAROF [Show more] Type: Subroutine Category: Maths (Geometry) Summary: Compare x_hi, y_hi and z_hi with 224
Context: See this subroutine on its own page References: This subroutine is called as follows: * Main flight loop (Part 12 of 16) calls FAROF

Compare x_hi, y_hi and z_hi with 224, and set the C flag if all three <= 224, otherwise clear the C flag.
Returns: C flag Set if x_hi <= 224 and y_hi <= 224 and z_hi <= 224 Clear otherwise (i.e. if any one of them are bigger than 224)
.FAROF LDA #224 \ Set A = 224 and fall through into FAROF2 to do the \ comparison
Name: FAROF2 [Show more] Type: Subroutine Category: Maths (Geometry) Summary: Compare x_hi, y_hi and z_hi with A
Context: See this subroutine on its own page References: This subroutine is called as follows: * Main flight loop (Part 14 of 16) calls FAROF2

Compare x_hi, y_hi and z_hi with A, and set the C flag if all three <= A, otherwise clear the C flag.
Returns: C flag Set if x_hi <= A and y_hi <= A and z_hi <= A Clear otherwise (i.e. if any one of them are bigger than A)
.FAROF2 CMP INWK+1 \ If A < x_hi, C will be clear so jump to FA1 to BCC FA1 \ return from the subroutine with C clear, otherwise \ C will be set so move on to the next one CMP INWK+4 \ If A < y_hi, C will be clear so jump to FA1 to BCC FA1 \ return from the subroutine with C clear, otherwise \ C will be set so move on to the next one CMP INWK+7 \ If A < z_hi, C will be clear, otherwise C will be set .FA1 RTS \ Return from the subroutine
Name: MAS4 [Show more] Type: Subroutine Category: Maths (Geometry) Summary: Calculate a cap on the maximum distance to a ship
Context: See this subroutine on its own page References: This subroutine is called as follows: * Main flight loop (Part 7 of 16) calls MAS4 * TACTICS (Part 1 of 7) calls MAS4 * TACTICS (Part 6 of 7) calls MAS4

Logical OR the value in A with the high bytes of the ship's position (x_hi, y_hi and z_hi).
Returns: A A OR x_hi OR y_hi OR z_hi
.MAS4 ORA INWK+1 \ OR A with x_hi, y_hi and z_hi ORA INWK+4 ORA INWK+7 RTS \ Return from the subroutine
Name: DEATH [Show more] Type: Subroutine Category: Start and end Summary: Display the death screen
Context: See this subroutine on its own page References: This subroutine is called as follows: * Main flight loop (Part 15 of 16) calls DEATH * OOPS calls DEATH

We have been killed, so display the chaos of our destruction above a "GAME OVER" sign, and clean up the mess ready for the next attempt.
.DEATH JSR EXNO3 \ Make the sound of us dying JSR RES2 \ Reset a number of flight variables and workspaces ASL DELTA \ Divide our speed in DELTA by 4 ASL DELTA LDX #24 \ Set the screen to only show 24 text rows, which hides JSR DET1 \ the dashboard, setting A to 6 in the process JSR TT66 \ Clear the top part of the screen, draw a border box, \ and set the current view type in QQ11 to 6 (death \ screen) JSR BOX \ Call BOX to redraw the same border box (BOX is part \ of TT66), which removes the border as it is drawn \ using EOR logic JSR nWq \ Create a cloud of stardust containing the correct \ number of dust particles (i.e. NOSTM of them) LDA #12 \ Move the text cursor to column 12 on row 12 STA YC STA XC LDA #146 \ Print recursive token 146 ("{all caps}GAME OVER") JSR ex .D1 JSR Ze \ Call Ze to initialise INWK to a potentially hostile \ ship, and set A and X to random values LSR A \ Set A = A / 4, so A is now between 0 and 63, and LSR A \ store in byte #0 (x_lo) STA INWK LDY #0 \ Set the following to 0: the current view in QQ11 STY QQ11 \ (space view), x_hi, y_hi, z_hi and the AI flag (no AI STY INWK+1 \ or E.C.M. and not hostile) STY INWK+4 STY INWK+7 STY INWK+32 DEY \ Set Y = 255 STY MCNT \ Reset the main loop counter to 255, so all timer-based \ calls will be stopped STY LASCT \ Set the laser count to 255 to act as a counter in the \ D2 loop below, so this setting determines how long the \ death animation lasts (it's 5.1 seconds, as LASCT is \ decremented every vertical sync, or 50 times a second, \ and 255 / 50 = 5.1) EOR #%00101010 \ Flip bits 1, 3 and 5 in A (x_lo) to get another number STA INWK+3 \ between 48 and 63, and store in byte #3 (y_lo) ORA #%01010000 \ Set bits 4 and 6 of A to bump it up to between 112 and STA INWK+6 \ 127, and store in byte #6 (z_lo) TXA \ Set A to the random number in X and keep bits 0-3 and AND #%10001111 \ the sign in bit 7 to get a number between -15 and +15, STA INWK+29 \ and store in byte #29 (roll counter) to give our ship \ a gentle roll with damping ROR A \ The C flag is randomly set from the above call to Ze, AND #%10000111 \ so this sets A to a number between -7 and +7, which STA INWK+30 \ we store in byte #30 (the pitch counter) to give our \ ship a very gentle pitch with damping LDX #OIL \ Set X to #OIL, the ship type for a cargo canister LDA XX21-1+2*PLT \ Fetch the byte from location XX21 - 1 + 2 * PLT, which \ equates to XX21 + 7 (the high byte of the address of \ SHIP_PLATE), which seems a bit odd. It might make more \ sense to do LDA (XX21-2+2*PLT) as this would fetch the \ first byte of the alloy plate's blueprint (which \ determines what happens when alloys are destroyed), \ but there aren't any brackets, so instead this always \ returns &D0, which is never zero, so the following \ BEQ is never true. (If the brackets were there, then \ we could stop plates from spawning on death by setting \ byte #0 of the blueprint to 0... but then scooping \ plates wouldn't give us alloys, so who knows what this \ is all about?) BEQ D3 \ If A = 0, jump to D3 to skip the following instruction BCC D3 \ If the C flag is clear, which will be random following \ the above call to Ze, jump to D3 to skip the following \ instruction DEX \ Decrement X, which sets it to #PLT, the ship type for \ an alloy plate .D3 JSR fq1 \ Call fq1 with X set to #OIL or #PLT, which adds a new \ cargo canister or alloy plate to our local bubble of \ universe and points it away from us with double DELTA \ speed (i.e. 6, as DELTA was set to 3 by the call to \ RES2 above). INF is set to point to the new arrival's \ ship data block in K% JSR DORND \ Set A and X to random numbers and extract bit 7 from A AND #%10000000 LDY #31 \ Store this in byte #31 of the ship's data block, so it STA (INF),Y \ has a 50% chance of marking our new arrival as being \ killed (so it will explode) LDA FRIN+4 \ The call we made to RES2 before we entered the loop at BEQ D1 \ D1 will have reset all the ship slots at FRIN, so this \ checks to see if the fifth slot is empty, and if it \ is we loop back to D1 to add another canister, until \ we have added five of them JSR U% \ Clear the key logger, which also sets A = 0 STA DELTA \ Set our speed in DELTA to 0, as we aren't going \ anywhere any more .D2 JSR M% \ Call the M% routine to do the main flight loop once, \ which will display our exploding canister scene and \ move everything about LDA LASCT \ Loop back to D2 to run the main flight loop until BNE D2 \ LASCT reaches zero (which will take 5.1 seconds, as \ explained above) LDX #31 \ Set the screen to show all 31 text rows, which shows JSR DET1 \ the dashboard JMP DEATH2 \ Jump to DEATH2 to reset and restart the game
Name: RSHIPS [Show more] Type: Subroutine Category: Loader Summary: Launch from the station, load a new set of ship blueprints and jump into the main game loop
Context: See this subroutine on its own page References: This subroutine is called as follows: * S% calls RSHIPS
.RSHIPS JSR LOMOD \ Call LOMOD to load a new ship blueprints file JSR RESET \ Call RESET to reset most variables LDA #&FF \ Set QQ1 to &FF to indicate we are docked, so when STA QQ12 \ we reach TT110 after calling FRCE below, it shows the \ launch tunnel STA QQ11 \ Set the view type to a non-zero value, so when we \ reach LOOK1 after calling FRCE below, it sets up a \ new space view LDA #f0 \ Jump into the main game loop at FRCE, setting the key JMP FRCE \ "pressed" to red key f0 (so we launch from the \ station)
Name: LOMOD [Show more] Type: Subroutine Category: Loader Summary: Load a new ship blueprints file Deep dive: Ship blueprints in the BBC Micro disc version Ship blueprints in Elite-A
Context: See this subroutine on its own page References: This subroutine is called as follows: * RSHIPS calls LOMOD * TT18 calls LOMOD * MJP calls via SHIPinA

Other entry points: SHIPinA Load the ship blueprints file specified in A
.LOMOD \ --- Mod: Code added for Elite-A: --------------------> LDA #0 \ Set finder = 0 so the compass shows the planet rather STA finder \ than the sun \ --- End of added code -------------------------------> JSR THERE \ Call THERE to see if we are in the Constrictor's \ system in mission 1 LDA #6 \ Set A to the number of the ship blueprints file \ containing the Constrictor (ship blueprints file G) BCS SHIPinA \ If the C flag is set then we are in the Constrictor's \ system, so skip to SHIPinA JSR DORND \ Set A and X to random numbers and reduce A to a AND #3 \ random number in the range 0-3 (i.e. just bits 0-1) LDX gov \ If the system's government type is 0-2 (anarchy, CPX #3 \ feudal or multi-government), shift a 0 into bit 0 of ROL A \ A, otherwise shift a 1 LDX tek \ If the system's tech level is 0-9, shift a 0 into bit CPX #10 \ 0 of A, otherwise shift a 1 ROL A \ --- Mod: Code removed for Elite-A: ------------------> \ \ By this point, A is: \ \ \ \ * Bit 0 = 0 for low tech level (Coriolis station) \ \ 1 for high tech level (Dodo station) \ \ * Bit 1 = 0 for more dangerous systems \ \ 1 for safer systems \ \ * Bit 2 = random \ \ * Bit 3 = random \ \ * Bits 4-7 = 0 \ \ \ \ So A is in the range 0-15, which corresponds to the \ \ appropriate ship blueprints file (where 0 is file \ \ D.MOA and 15 is file D.MOP) \ --- And replaced by: --------------------------------> \ By this point, A is: \ \ * Bit 0 = 0 for low tech level (Coriolis station) \ 1 for high tech level (Dodo station) \ * Bit 1 = 0 for more dangerous systems \ 1 for safer systems \ * Bit 2 = random \ * Bit 3 = random \ * Bits 4-7 = 0 \ \ and we know the C flag is clear, as we cleared the top \ bits of A before doing the left rotations above \ \ So A is in the range 0-15. This corresponds to the \ range of ship blueprint files in the original disc \ version, which are D.MOA to D.MOP, but we're not done \ yet, as Elite-A has 23 ship blueprint files ADC GCNT \ Add the galaxy number in GCNT to A, which moves A into \ the range 0-22, to correspond with the appropriate \ Elite-A ship file (where 0 is file S.A and 22 is file \ S.W) \ --- End of replacement ------------------------------> TAX \ Store A in X so we can retrieve it after the mission 2 \ progress check LDA TP \ If mission 2 has started and we have picked up the AND #%00001100 \ plans, then bits 2-3 of TP will be %10, so this jumps CMP #%00001000 \ to TPnot8 if this is not the case BNE TPnot8 TXA \ Retrieve the value of A we calculated above AND #%00000001 \ We have picked up the plans in mission 2 so we need to ORA #%00000010 \ load a ship blueprints file containing Thargoids, so \ set A to either %10 or %11 for file D.MOC or D.MOD, as \ they are the only files that contain Thargoid ship \ blueprints TAX \ Store the amended A in X again .TPnot8 TXA \ Retrieve the value of A we calculated above .SHIPinA \ --- Mod: Code removed for Elite-A: ------------------> \CLC \ Convert A from 0-15 to 'A' to 'P' \ADC #'A' \ \STA SHIPI+6 \ Store the letter of the ship blueprints file we want \ \ in the seventh byte of the command string at SHIPI, so \ \ it overwrites the "0" in "D.MO0" with the file letter \ \ to load, from D.MOA to D.MOP \ \JSR CATD \ Call CATD to reload the disc catalogue \ --- And replaced by: --------------------------------> CLC \ Convert A from 0-22 to 'A' to 'W' ADC #'A' STA SHIPI+4 \ Store the letter of the ship blueprints file we want \ in the fifth byte of the command string at SHIPI, so \ it overwrites the "0" in "S.0" with the file letter \ to load, from S.A to S.W \ --- End of replacement ------------------------------> LDX #LO(SHIPI) \ Set (Y X) to point to the OS command at SHIPI, which LDY #HI(SHIPI) \ loads the relevant ship blueprints file JMP OSCLI \ Call OSCLI to execute the OS command at (Y X), which \ loads the relevant ship blueprints file, and return \ from the subroutine using a tail call
Name: SHIPI [Show more] Type: Variable Category: Loader Summary: The OS command string for loading a ship blueprints file
Context: See this variable on its own page References: This variable is used as follows: * LOMOD uses SHIPI
.SHIPI \ --- Mod: Code removed for Elite-A: ------------------> \EQUS "L.D.MO0" \ This is short for "*LOAD D.MO0" \EQUB 13 \ --- And replaced by: --------------------------------> EQUS "L.S.0" \ This is short for "*LOAD S.0" EQUB 13 \ --- End of replacement ------------------------------>
Name: ZERO [Show more] Type: Subroutine Category: Utility routines Summary: Reset the local bubble of universe and ship status
Context: See this subroutine on its own page References: This subroutine is called as follows: * RES2 calls ZERO * RESET calls ZERO

This resets the following workspaces to zero: * 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 STX SC+1 \ We want to zero-fill page X, so store this in the \ high byte of SC, so SC(1 0) is now pointing to page X LDA #0 \ If we set Y = SC = 0 and fall through into ZES2 STA SC \ below, then we will zero-fill 255 bytes starting from TAY \ SC, then SC + 255, and then the rest of the page - 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: No direct references to this subroutine in this source file

Zero-fill from address (X SC) to (X SC) + Y.
Arguments: Y The offset from (X SC) where we start zeroing, counting down to 0 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 .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 DEY \ Decrement the loop counter BNE ZEL1 \ Loop back to zero the next byte RTS \ Return from the subroutine
Name: SPS1 [Show more] Type: Subroutine Category: Maths (Geometry) Summary: Calculate the vector to the planet, sun or station and store it in XX15
Context: See this subroutine on its own page References: This subroutine is called as follows: * COMPAS calls SPS1 * Main flight loop (Part 9 of 16) calls SPS1 * TACTICS (Part 3 of 7) calls SPS1

Arguments: Y Determines the object whose vector we are calculating: * 0 = calculate the vector to the planet * NI% = calculate the vector to the sun/space station Other entry points: SPS1+1 A BRK instruction
.SPS1 \ --- Mod: Code removed for Elite-A: ------------------> \LDX #0 \ Copy the two high bytes of the planet's x-coordinate \JSR SPS3 \ into K3(2 1 0), separating out the sign bit into K3+2 \ \LDX #3 \ Copy the two high bytes of the planet's y-coordinate \JSR SPS3 \ into K3(5 4 3), separating out the sign bit into K3+5 \ \LDX #6 \ Copy the two high bytes of the planet's z-coordinate \JSR SPS3 \ into K3(8 7 6), separating out the sign bit into K3+8 \ --- And replaced by: --------------------------------> LDX #0 \ Copy the two high bytes of the planet/sun/station's JSR SPS3 \ x-coordinate into K3(2 1 0), separating out the sign \ bit into K3+2 JSR SPS3 \ Copy the two high bytes of the planet/sun/station's \ y-coordinate into K3(5 4 3), separating out the sign \ bit into K3+5 JSR SPS3 \ Copy the two high bytes of the planet/sun/station's \ z-coordinate into K3(8 7 6), separating out the sign \ bit into K3+8 \ --- End of replacement ------------------------------> \ Fall through into TAS2 to build XX15 from K3
Name: TAS2 [Show more] Type: Subroutine Category: Maths (Geometry) Summary: Normalise the three-coordinate vector in K3
Context: See this subroutine on its own page References: This subroutine is called as follows: * DOCKIT calls TAS2 * TACTICS (Part 3 of 7) calls TAS2 * DOCKIT calls via TA2

Normalise the vector in K3, which has 16-bit values and separate sign bits, and store the normalised version in XX15 as a signed 8-bit vector. A normalised vector (also known as a unit vector) has length 1, so this routine takes an existing vector in K3 and scales it so the length of the new vector is 1. This is used in two places: when drawing the compass, and when applying AI tactics to ships. We do this in two stages. This stage shifts the 16-bit vector coordinates in K3 to the left as far as they will go without losing any bits off the end, so we can then take the high bytes and use them as the most accurate 8-bit vector to normalise. Then the next stage (in routine NORM) does the normalisation.
Arguments: K3(2 1 0) The 16-bit x-coordinate as (x_sign x_hi x_lo), where x_sign is just bit 7 K3(5 4 3) The 16-bit y-coordinate as (y_sign y_hi y_lo), where y_sign is just bit 7 K3(8 7 6) The 16-bit z-coordinate as (z_sign z_hi z_lo), where z_sign is just bit 7
Returns: XX15 The normalised vector, with: * The x-coordinate in XX15 * The y-coordinate in XX15+1 * The z-coordinate in XX15+2
Other entry points: TA2 Calculate the length of the vector in XX15 (ignoring the low coordinates), returning it in Q
.TAS2 LDA K3 \ OR the three low bytes and 1 to get a byte that has ORA K3+3 \ a 1 wherever any of the three low bytes has a 1 ORA K3+6 \ (as well as always having bit 0 set), and store in ORA #1 \ K3+9 STA K3+9 LDA K3+1 \ OR the three high bytes to get a byte in A that has a ORA K3+4 \ 1 wherever any of the three high bytes has a 1 ORA K3+7 \ (A K3+9) now has a 1 wherever any of the 16-bit \ values in K3 has a 1 .TAL2 ASL K3+9 \ Shift (A K3+9) to the left, so bit 7 of the high byte ROL A \ goes into the C flag BCS TA2 \ If the left shift pushed a 1 out of the end, then we \ know that at least one of the coordinates has a 1 in \ this position, so jump to TA2 as we can't shift the \ values in K3 any further to the left ASL K3 \ Shift K3(1 0), the x-coordinate, to the left ROL K3+1 ASL K3+3 \ Shift K3(4 3), the y-coordinate, to the left ROL K3+4 ASL K3+6 \ Shift K3(6 7), the z-coordinate, to the left ROL K3+7 BCC TAL2 \ Jump back to TAL2 to do another shift left (this BCC \ is effectively a JMP as we know bit 7 of K3+7 is not a \ 1, as otherwise bit 7 of A would have been a 1 and we \ would have taken the BCS above) .TA2 LDA K3+1 \ Fetch the high byte of the x-coordinate from our left- LSR A \ shifted K3, shift it right to clear bit 7, stick the ORA K3+2 \ sign bit in there from the x_sign part of K3, and STA XX15 \ store the resulting signed 8-bit x-coordinate in XX15 LDA K3+4 \ Fetch the high byte of the y-coordinate from our left- LSR A \ shifted K3, shift it right to clear bit 7, stick the ORA K3+5 \ sign bit in there from the y_sign part of K3, and STA XX15+1 \ store the resulting signed 8-bit y-coordinate in \ XX15+1 LDA K3+7 \ Fetch the high byte of the z-coordinate from our left- LSR A \ shifted K3, shift it right to clear bit 7, stick the ORA K3+8 \ sign bit in there from the z_sign part of K3, and STA XX15+2 \ store the resulting signed 8-bit z-coordinate in \ XX15+2 \ Now we have a signed 8-bit version of the vector K3 in \ XX15, so fall through into NORM to normalise it
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

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 (&60) 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 \ --- Mod: Code removed for Elite-A: ------------------> \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 \ --- And replaced by: --------------------------------> TAY \ Set (Y P) = (A P) = y^2 LDA P \ Set (R Q) = (R Q) + (Y P) = x^2 + y^2 ADC Q \ STA Q \ First, doing the low bytes, Q = Q + P TYA \ And then the high bytes, R = R + Y ADC R STA R \ --- End of replacement ------------------------------> LDA XX15+2 \ Fetch the z-coordinate into A JSR SQUA \ Set (A P) = A * A = z^2 \ --- Mod: Code removed for Elite-A: ------------------> \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 \ --- And replaced by: --------------------------------> TAY \ Set (Y P) = (A P) = z^2 LDA P \ Set (R Q) = (R Q) + (Y P) = x^2 + y^2 + z^2 ADC Q \ STA Q \ First, doing the low bytes, Q = Q + P TYA \ And then the high bytes, R = R + Y ADC R STA R \ --- End of replacement ------------------------------> 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

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: WARP [Show more] Type: Subroutine Category: Flight Summary: Perform an in-system jump
Context: See this subroutine on its own page References: This subroutine is called as follows: * Main flight loop (Part 3 of 16) calls WARP * Main flight loop (Part 3 of 16) calls via WA1

This is called when we press "J" during flight. The following checks are performed: * Make sure we don't have any ships or space stations in the vicinity * Make sure we are not in witchspace * If we are facing the planet, make sure we aren't too close * If we are facing the sun, make sure we aren't too close If the above checks are passed, then we perform an in-system jump by moving the sun and planet in the opposite direction to travel, so we appear to jump in space. This means that any asteroids, cargo canisters or escape pods get dragged along for the ride.
Other entry points: WA1 Make a long, low beep
.WARP LDX JUNK \ Set X to the total number of junk items in the \ vicinity (e.g. asteroids, escape pods, cargo \ canisters, Shuttles, Transporters and so on) LDA FRIN+2,X \ If the slot at FRIN+2+X is non-zero, then we have \ something else in the vicinity besides asteroids, \ escape pods and cargo canisters, so to check whether \ we can jump, we first grab the slot contents into A \ --- Mod: Code added for Elite-A: --------------------> ORA JUNK \ If there is any junk in the vicinity, then JUNK will \ be non-zero, so OR'ing with JUNK will produce a \ non-zero result if either A or JUNK are non-zero \ (so this prevents in-system jumps if there is any \ junk nearby, which is different to the other versions \ which allow you to jump, dragging any junk along with \ the ship) \ --- End of added code -------------------------------> ORA SSPR \ If there is a space station nearby, then SSPR will \ be non-zero, so OR'ing with SSPR will produce a \ non-zero result if either A or SSPR are non-zero ORA MJ \ If we are in witchspace, then MJ will be non-zero, so \ OR'ing with MJ will produce a non-zero result if \ either A or SSPR or MJ are non-zero BNE WA1 \ A is non-zero if we have either a ship, or a space \ station, or junk in the vicinity, or we are in \ witchspace, in which case jump to WA1 to make a low \ beep to show that we can't do an in-system jump LDY K%+8 \ Otherwise we can do an in-system jump, so now we fetch \ the byte at K%+8, which contains the z_sign for the \ first ship slot, i.e. the distance of the planet BMI WA3 \ If the planet's z_sign is negative, then the planet \ is behind us, so jump to WA3 to skip the following TAY \ Set A = Y = 0 (as we didn't BNE above) so the call \ to MAS2 measures the distance to the planet JSR MAS2 \ Call MAS2 to set A to the largest distance to the \ planet in any of the three axes (we could also call \ routine m to do the same thing, as A = 0) LSR A \ If A < 2 then jump to WA1 to abort the in-system jump BEQ WA1 \ with a low beep, as we are facing the planet and are \ too close to jump in that direction .WA3 LDY K%+NI%+8 \ Fetch the z_sign (byte #8) of the second ship in the \ ship data workspace at K%, which is reserved for the \ sun or the space station (in this case it's the \ former, as we already confirmed there isn't a space \ station in the vicinity) BMI WA2 \ If the sun's z_sign is negative, then the sun is \ behind us, so jump to WA2 to skip the following LDY #NI% \ Set Y to point to the offset of the ship data block \ for the sun, which is NI% (as each block is NI% bytes \ long, and the sun is the second block) JSR m \ Call m to set A to the largest distance to the sun \ in any of the three axes LSR A \ If A < 2 then jump to WA1 to abort the in-system jump BEQ WA1 \ with a low beep, as we are facing the sun and are too \ close to jump in that direction .WA2 \ If we get here, then we can do an in-system jump, as \ we don't have any ships or space stations in the \ vicinity, we are not in witchspace, and if we are \ facing the planet or the sun, we aren't too close to \ jump towards it \ \ We do an in-system jump by moving the sun and planet, \ rather than moving our own local bubble (this is why \ in-system jumps drag asteroids, cargo canisters and \ escape pods along for the ride). Specifically, we move \ them in the z-axis by a fixed amount in the opposite \ direction to travel, thus performing a jump towards \ our destination LDA #&81 \ Set R = R = P = &81 STA S STA R STA P LDA K%+8 \ Set A = z_sign for the planet JSR ADD \ Set (A X) = (A P) + (S R) \ = (z_sign &81) + &8181 \ = (z_sign &81) - &0181 \ \ This moves the planet against the direction of travel \ by reducing z_sign by 1, as the above maths is: \ \ z_sign 00000000 \ + 00000000 10000001 \ - 00000001 10000001 \ \ or: \ \ z_sign 00000000 \ + 00000000 00000000 \ - 00000001 00000000 \ \ i.e. the high byte is z_sign - 1, making sure the sign \ is preserved STA K%+8 \ Set the planet's z_sign to the high byte of the result LDA K%+NI%+8 \ Set A = z_sign for the sun JSR ADD \ Set (A X) = (A P) + (S R) \ = (z_sign &81) + &8181 \ = (z_sign &81) - &0181 \ \ which moves the sun against the direction of travel \ by reducing z_sign by 1 STA K%+NI%+8 \ Set the planet's z_sign to the high byte of the result LDA #1 \ Temporarily set the view type to a non-zero value, so STA QQ11 \ the call to LOOK1 below clears the screen before \ switching to the space view STA MCNT \ Set the main loop counter to 1, so the next iteration \ through the main loop will potentially spawn ships \ (see part 2 of the main game loop at me3) LSR A \ Set EV, the extra vessels spawning counter, to 0 STA EV \ (the LSR produces a 0 as A was previously 1) LDX VIEW \ Set X to the current view (front, rear, left or right) JMP LOOK1 \ and jump to LOOK1 to initialise that view, returning \ from the subroutine using a tail call .WA1 LDA #40 \ If we get here then we can't do an in-system jump, so BNE NOISE \ call the NOISE routine with A = 40 to make a long, low \ beep and return from the subroutine using a tail call \ (the BNE is effectively a JMP as A is never zero)
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: * Main flight loop (Part 16 of 16) calls ECMOF * 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 ECMP to 0 to indicate that no E.C.M. is STA ECMA \ currently running STA ECMP JSR ECBLB \ Update the E.C.M. indicator bulb on the dashboard 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: EXNO3 [Show more] Type: Subroutine Category: Sound Summary: Make an explosion sound
Context: See this subroutine on its own page References: This subroutine is called as follows: * DEATH calls EXNO3 * Main flight loop (Part 10 of 16) calls EXNO3 * OOPS calls EXNO3 * TACTICS (Part 1 of 7) calls EXNO3

Make the sound of death in the cold, hard vacuum of space. Apparently, in Elite space, everyone can hear you scream. This routine also makes the sound of a destroyed cargo canister if we don't get scooping right, the sound of us colliding with another ship, and the sound of us being hit with depleted shields. It is not a good sound to hear.
.EXNO3 \ --- Mod: Code removed for Elite-A: ------------------> \LDA #16 \ Call the NOISE routine with A = 16 to make the first \JSR NOISE \ death sound \ --- And replaced by: --------------------------------> JSR n_sound10 \ Call n_sound10 make the first death sound \ --- End of replacement ------------------------------> LDA #24 \ Call the NOISE routine with A = 24 to make the second BNE NOISE \ death sound 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: * Main flight loop (Part 11 of 16) calls BEEP * TT26 calls BEEP
.BEEP 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)
Name: SFRMIS [Show more] Type: Subroutine Category: Tactics Summary: Add an enemy missile to our local bubble of universe
Context: See this subroutine on its own page References: This subroutine is called as follows: * TACTICS (Part 5 of 7) calls SFRMIS * FRMIS calls via n_sound30 * LAUN calls via n_sound30

An enemy has fired a missile, so add the missile to our universe if there is room, and if there is, make the appropriate warnings and noises.
Other entry points: n_sound30 Make the sound of a missile being launched
.SFRMIS LDX #MSL \ Set X to the ship type of a missile, and call SFS1-2 JSR SFS1-2 \ to add the missile to our universe with an AI flag \ of %11111110 (AI enabled, hostile, no E.C.M.) BCC KYTB \ The C flag will be set if the call to SFS1-2 was a \ success, so if it's clear, jump to KYTB to return from \ the subroutine (as KYTB contains an RTS) LDA #120 \ Print recursive token 120 ("INCOMING MISSILE") as an JSR MESS \ in-flight message \ --- Mod: Code added for Elite-A: --------------------> .n_sound30 \ --- End of added code -------------------------------> LDA #48 \ Call the NOISE routine with A = 48 to make the sound BNE NOISE \ of the missile being launched and return from the \ subroutine using a tail call (this BNE is effectively \ a JMP as A will never be zero)
Name: EXNO2 [Show more] Type: Subroutine Category: Status Summary: Process us making a kill Deep dive: Combat rank
Context: See this subroutine on its own page References: This subroutine is called as follows: * Main flight loop (Part 11 of 16) calls EXNO2 * TACTICS (Part 1 of 7) calls EXNO2

We have killed a ship, so increase the kill tally, displaying an iconic message of encouragement if the kill total is a multiple of 256, and then make a nearby explosion sound.
.EXNO2 INC TALLY \ Increment the low byte of the kill count in TALLY BNE EXNO-2 \ If there is no carry, jump to the LDX #7 below (at \ EXNO-2) INC TALLY+1 \ Increment the high byte of the kill count in TALLY LDA #101 \ The kill total is a multiple of 256, so it's time JSR MESS \ for a pat on the back, so print recursive token 101 \ ("RIGHT ON COMMANDER!") as an in-flight message LDX #7 \ Set X = 7 and fall through into EXNO to make the \ sound of a ship exploding
Name: EXNO [Show more] Type: Subroutine Category: Sound Summary: Make the sound of a laser strike or ship explosion
Context: See this subroutine on its own page References: This subroutine is called as follows: * Main flight loop (Part 11 of 16) calls EXNO * EXNO2 calls via EXNO-2 * EXNO3 calls via n_sound10

Make the two-part explosion sound of us making a laser strike, or of another ship exploding. The volume of the first explosion is affected by the distance of the ship being hit, with more distant ships being quieter. The value in X also affects the volume of the first explosion, with a higher X giving a quieter sound (so X can be used to differentiate a laser strike from an explosion).
Arguments: X The larger the value of X, the fainter the explosion. Allowed values are: * 7 = explosion is louder (i.e. the ship has just exploded) * 15 = explosion is quieter (i.e. this is just a laser strike)
Other entry points: EXNO-2 Set X = 7 and fall through into EXNO to make the sound of a ship exploding n_sound10 Make the first part of the death sound, or the second part of the explosion sound
.EXNO STX T \ Store the distance in T LDA #24 \ Set A = 24 to denote the sound of us making a hit or JSR NOS1 \ kill (part 1 of the explosion), and call NOS1 to set \ up the sound block in XX16 LDA INWK+7 \ Fetch z_hi, the distance of the ship being hit in LSR A \ terms of the z-axis (in and out of the screen), and LSR A \ divide by 4. If z_hi has either bit 6 or 7 set then \ that ship is too far away to be shown on the scanner \ (as per the SCAN routine), so we know the maximum \ z_hi at this point is %00111111, and shifting z_hi \ to the right twice gives us a maximum value of \ %00001111 AND T \ This reduces A to a maximum of X; X can be either \ 7 = %0111 or 15 = %1111, so AND'ing with 15 will \ not affect A, while AND'ing with 7 will clear bit \ 3, reducing the maximum value in A to 7 ORA #%11110001 \ The SOUND statement's amplitude ranges from 0 (for no \ sound) to -15 (full volume), so we can set bits 0 and \ 4-7 in A, and keep bits 1-3 from the above to get \ a value between -15 (%11110001) and -1 (%11111111), \ with lower values of z_hi and argument X leading \ to a more negative, or quieter number (so the closer \ the ship, i.e. the smaller the value of X, the louder \ the sound) STA XX16+2 \ The amplitude byte of the sound block in XX16 is in \ byte #3 (where it's the low byte of the amplitude), so \ this sets the amplitude to the value in A JSR NO3 \ Make the sound from our updated sound block in XX16 \ --- Mod: Code added for Elite-A: --------------------> .n_sound10 \ --- End of added code -------------------------------> LDA #16 \ Set A = 16 to denote we have made a hit or kill \ (part 2 of the explosion), and fall through into NOISE \ to make the sound
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: * BEEP calls NOISE * ECBLB2 calls NOISE * ECMOF calls NOISE * EXNO3 calls NOISE * LL164 calls NOISE * Main flight loop (Part 3 of 16) calls NOISE * SFRMIS calls NOISE * TACTICS (Part 6 of 7) calls NOISE * WARP 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: This subroutine is called as follows: * EXNO calls NO3

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 \ --- Mod: Code removed for Elite-A: ------------------> \LDX DNOIZ \ Set X to the DNOIZ configuration setting \ --- And replaced by: --------------------------------> LDY DNOIZ \ Set Y to the DNOIZ configuration setting \ --- End of replacement ------------------------------> BNE KYTB \ If DNOIZ is non-zero, then sound is disabled, so \ return from the subroutine (as KYTB contains an RTS) \ --- Mod: Code removed for Elite-A: ------------------> \LDX #LO(XX16) \ Otherwise set (Y X) to point to the sound block in \LDY #HI(XX16) \ XX16 \ --- And replaced by: --------------------------------> LDX #LO(XX16) \ Otherwise set (Y X) to point to the sound block in \ XX16 (Y is 0 as we didn't take the BNE above, and the \ XX16 block is in zero page, so we don't need to \ explicitly set Y to #HI(XX16) as it's already correct) \ --- End of replacement ------------------------------> 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: * EXNO calls NOS1 * 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: KYTB [Show more] Type: Variable Category: Keyboard Summary: Lookup table for in-flight keyboard controls Deep dive: The key logger
Context: See this variable on its own page References: This variable is used as follows: * DKS1 uses KYTB * NO3 uses KYTB * SFRMIS uses KYTB

Keyboard table for in-flight controls. This table contains the internal key codes for the flight keys (see p.142 of the Advanced User Guide for a list of internal key numbers). The pitch, roll, speed and laser keys (i.e. the seven primary flight control keys) have bit 7 set, so they have 128 added to their internal values. This doesn't appear to be used anywhere. Note that KYTB actually points to the byte before the start of the table, so the offset of the first key value is 1 (i.e. KYTB+1), not 0.
Other entry points: KYTB Contains an RTS
.KYTB RTS \ Return from the subroutine (used as an entry point and \ a fall-through from above) \ These are the primary flight controls (pitch, roll, \ speed and lasers): EQUB &68 + 128 \ ? KYTB+1 Slow down EQUB &62 + 128 \ Space KYTB+2 Speed up EQUB &66 + 128 \ < KYTB+3 Roll left EQUB &67 + 128 \ > KYTB+4 Roll right EQUB &42 + 128 \ X KYTB+5 Pull up EQUB &51 + 128 \ S KYTB+6 Pitch down EQUB &41 + 128 \ A KYTB+7 Fire lasers \ These are the secondary flight controls: \ --- Mod: Code removed for Elite-A: ------------------> \EQUB &60 \ TAB KYTB+8 Energy bomb \EQUB &70 \ ESCAPE KYTB+9 Launch escape pod \EQUB &23 \ T KYTB+10 Arm missile \EQUB &35 \ U KYTB+11 Unarm missile \EQUB &65 \ M KYTB+12 Fire missile \EQUB &22 \ E KYTB+13 E.C.M. \EQUB &45 \ J KYTB+14 In-system jump \EQUB &52 \ C KYTB+15 Docking computer \ --- And replaced by: --------------------------------> EQUB &60 \ TAB KYTB+8 Activate hyperspace unit EQUB &70 \ ESCAPE KYTB+9 Launch escape pod EQUB &23 \ T KYTB+10 Arm missile EQUB &35 \ U KYTB+11 Unarm missile EQUB &65 \ M KYTB+12 Fire missile EQUB &22 \ E KYTB+13 E.C.M. EQUB &45 \ J KYTB+14 In-system jump EQUB &63 \ V KYTB+15 Docking computer \ --- End of replacement ------------------------------> EQUB &37 \ P KYTB+16 Cancel docking computer
Name: b_table [Show more] Type: Variable Category: Keyboard Summary: Lookup table for Delta 14B joystick buttons Deep dive: Delta 14B joystick support
Context: See this variable on its own page References: This variable is used as follows: * b_14 uses b_table

In the following table, which maps buttons on the Delta 14B to the flight controls, the high nibble of the value gives the column: &6 = %110 = left column &5 = %101 = middle column &3 = %011 = right column while the low nibble gives the row: &1 = %0001 = top row &2 = %0010 = second row &4 = %0100 = third row &8 = %1000 = bottom row This results in the following mapping (as the top two fire buttons are treated the same as the top button in the middle row): Fire laser Fire laser Slow down Fire laser Speed up Unarm missile Fire missile Target missile Hyperspace Unit E.C.M. Escape pod Docking computer off In-system jump Docking computer on Note that this is different to the layout in Angus Duggan's documentation, as he has the docking computer buttons the wrong way around in his instructions.
\ --- Mod: Code added for Elite-A: --------------------> .b_table EQUB &61 \ Left column Top row KYTB+1 Slow down EQUB &31 \ Right column Top row KYTB+2 Speed up EQUB &80 \ - KYTB+3 Roll left EQUB &80 \ - KYTB+4 Roll right EQUB &80 \ - KYTB+5 Pull up EQUB &80 \ - KYTB+6 Pitch down EQUB &51 \ Middle column Top row KYTB+7 Fire lasers EQUB &64 \ Left column Third row KYTB+8 Hyperspace unit EQUB &34 \ Right column Third row KYTB+9 Escape pod EQUB &32 \ Right column Second row KYTB+10 Arm missile EQUB &62 \ Left column Second row KYTB+11 Unarm missile EQUB &52 \ Middle column Second row KYTB+12 Fire missile EQUB &54 \ Middle column Third row KYTB+13 E.C.M. EQUB &58 \ Middle column Bottom row KYTB+14 In-system jump EQUB &38 \ Right column Bottom row KYTB+15 Docking computer EQUB &68 \ Left column Bottom row KYTB+16 Cancel docking \ --- End of added code ------------------------------->
Name: b_14 [Show more] Type: Subroutine Category: Keyboard Summary: Scan the Delta 14B joystick buttons Deep dive: Delta 14B joystick support
Context: See this subroutine on its own page References: This subroutine is called as follows: * DKS1 calls b_14

Scan the Delta 14B for the flight key given in register Y, where Y is the offset into the KYTB table above (so this is the same approach as in DKS1). The keys on the Delta 14B are laid out as follows (the top two fire buttons are treated the same as the top button in the middle row): Fire laser Fire laser Slow down Fire laser Speed up Unarm missile Fire missile Target missile Hyperspace Unit E.C.M. Escape pod Docking computer off In-system jump Docking computer on Note that this is different to the layout in Angus Duggan's documentation, as he has the docking computer buttons the wrong way around in his instructions.
Arguments: Y The offset into the KYTB table of the key that we want to scan on the Delta 14B
\ --- Mod: Code added for Elite-A: --------------------> .b_13 LDA #0 \ Set A = 0 for the second pass through the following, \ so we can check the joystick plugged into the rear \ socket of the Delta 14B adaptor .b_14 \ This is the entry point for the routine, which is \ called with A = 128 (the value of BSTK when the Delta \ 14b is enabled), and if the key we are checking has a \ corresponding button on the Delta 14B, it is run a \ second time with A = 0 TAX \ Store A in X so we can restore it below EOR b_table-1,Y \ We now EOR the value in A with the Y-th entry in BEQ b_quit \ b_table, and jump to b_quit to return from the \ subroutine if the table entry is 128 (&80) - in other \ words, we quit if Y is the offset for the roll and \ pitch controls \ If we get here, then the offset in Y points to a \ control with a corresponding button on the Delta 14B, \ and we pass through the following twice, once with a \ starting value of A = 128, and again with a starting \ value of A = 0 \ \ On the first pass, the EOR will set A to the value \ from b_table but with bit 7 set, which means we scan \ the joystick plugged into the side socket of the \ Delta 14B adaptor \ \ On the second pass, the EOR will set A to the value \ from b_table (i.e. with bit 7 clear), which means we \ scan the joystick plugged into the rear socket of the \ Delta 14B adaptor STA VIA+&60 \ Set 6522 User VIA output register ORB (SHEILA &60) to \ the value in A, which tells the Delta 14B adaptor box \ that we want to read the buttons specified in PB4 to \ PB7 (i.e. bits 4-7), as follows: \ \ On the side socket joystick (bit 7 set): \ \ %1110 = read buttons in left column (bit 4 clear) \ %1101 = read buttons in middle column (bit 5 clear) \ %1011 = read buttons in right column (bit 6 clear) \ \ On the rear socket joystick (bit 7 clear): \ \ %0110 = read buttons in left column (bit 4 clear) \ %0101 = read buttons in middle column (bit 5 clear) \ %0011 = read buttons in right column (bit 6 clear) AND #%00001111 \ We now read the 6522 User VIA to fetch PB0 to PB3 from AND VIA+&60 \ the user port (PB0 = bit 0 to PB3 = bit 3), which \ tells us whether any buttons in the specified column \ are being pressed, and if they are, in which row. The \ values read are as follows: \ \ %1111 = no button is being pressed in this column \ %1110 = button pressed in top row (bit 0 clear) \ %1101 = button pressed in second row (bit 1 clear) \ %1011 = button pressed in third row (bit 2 clear) \ %0111 = button pressed in bottom row (bit 3 clear) \ \ In other words, if a button is being pressed in the \ top row in the previously specified column, then PB0 \ (bit 0) will go low in the value we read from the user \ port BEQ b_pressed \ In the above we AND'd the result from the user port \ with the bottom four bits of the table value (the \ low nibble). The low nibble in b_table contains \ a 1 in the relevant position for that row that \ corresponds with the clear bit in the response from \ the user port, so if we AND the two together and get \ a zero, that means that button is being pressed, in \ which case we jump to b_pressed to update the key \ logger for that button \ \ For example, take the b_table entry for the escape pod \ button, in the right column and third row. The value \ in b_table is &34. The high nibble denotes the column, \ which is &3 = %011, which means in the STA VIA+&60 \ above, we write %1011 in the first pass (when A = 128) \ to set the right column for the side socket joystick, \ and we write %0011 in the first pass (when A = 0) to \ set the right column for the rear socket joystick \ \ Now for the row. The low nibble of the &34 value \ from b_table contains the row, so that's &4 = %0100. \ When we read the user port, then we will fetch %1011 \ from VIA+&60 if the button in the third row is being \ pressed, so when we AND the two together, we get: \ \ %0100 AND %1011 = 0 \ \ which will indicate the button is being pressed. If \ any other button is being pressed, or no buttons at \ all, then the result will be non-zero and we move on \ to the next button TXA \ Restore the original value of A that we stored in X BMI b_13 \ If we just did the above with A = 128, then loop back \ to b_13 to do it again with A = 0 RTS \ Return from the subroutine \ --- End of added code ------------------------------->
Name: DKS1 [Show more] Type: Subroutine Category: Keyboard Summary: Scan the keyboard for a flight key Deep dive: The key logger
Context: See this subroutine on its own page References: This subroutine is called as follows: * DK4 calls DKS1 * DKJ1 calls DKS1 * DOKEY calls DKS1 * b_14 calls via b_pressed * b_14 calls via b_quit

Scan the keyboard for the flight key given in register Y, where Y is the offset into the KYTB table above (so we can scan for Space by setting Y to 2, for example). If the key is pressed, set the corresponding byte in the key logger at KL to &FF.
Arguments: Y The offset into the KYTB table above of the key that we want to scan on the keyboard
Other entry points: b_pressed Store &FF in the Y-th byte of the key logger at KL, to indicate that key is being pressed b_quit Contains an RTS
.DKS1 \ --- Mod: Code added for Elite-A: --------------------> LDA BSTK \ If BSTK is negative, then the Delta 14B joystick is BMI b_14 \ configured, so jump to b_14 to check the Delta 14B \ joystick buttons \ --- End of added code -------------------------------> LDX KYTB,Y \ Get the internal key number from the Y-th byte of the \ KYTB table above JSR DKS4 \ Call DKS4, which will set A and X to a negative value \ if the key is being pressed \ --- Mod: Code removed for Elite-A: ------------------> \BPL DKS2-1 \ The key is not being pressed, so return from the \ \ subroutine (as DKS2-1 contains an RTS) \ --- And replaced by: --------------------------------> BPL b_quit \ The key is not being pressed, so return from the \ subroutine (as b_quit contains an RTS) .b_pressed \ --- End of replacement ------------------------------> LDA #&FF \ Store &FF in the Y-th byte of the key logger at KL STA KL,Y \ --- Mod: Code added for Elite-A: --------------------> .b_quit \ --- End of added code -------------------------------> RTS \ Return from the subroutine
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: * hyp 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 into 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: * DKS1 calls DKS4 * RDKEY 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: * DKJ1 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 \ \ * Channel 1 is the x-axis: 0 = right, 65520 = left \ \ * Channel 2 is the y-axis: 0 = down, 65520 = up 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/50 seconds (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: DKJ1 [Show more] Type: Subroutine Category: Keyboard Summary: Read joystick and flight controls
Context: See this subroutine on its own page References: This subroutine is called as follows: * DOKEY calls DKJ1

Specifically, scan the keyboard for the speed up and slow down keys, and read the joystick's fire button and X and Y axes, storing the results in the key logger and the joystick position variables. This routine is only called if joysticks are enabled (JSTK = non-zero).
.DKJ1 LDA auto \ If auto is non-zero, then the docking computer is BNE auton \ currently activated, so jump to auton in DOKEY so the \ docking computer can "press" the flight keys for us LDY #1 \ Update the key logger for key 1 in the KYTB table, so JSR DKS1 \ KY1 will be &FF if "?" (slow down) is being pressed INY \ Update the key logger for key 2 in the KYTB table, so JSR DKS1 \ KY2 will be &FF if Space (speed up) is being pressed \ --- Mod: Code added for Elite-A: --------------------> LDA #&51 \ Set 6522 User VIA output register ORB (SHEILA &60) to STA VIA+&60 \ the Delta 14B joystick button in the middle column \ (high nibble &5) and top row (low nibble &1), which \ corresponds to the fire button \ --- End of added code -------------------------------> LDA VIA+&40 \ Read 6522 System VIA input register IRB (SHEILA &40) TAX \ This instruction doesn't seem to have any effect, as \ X is overwritten in a few instructions AND #%00010000 \ Bit 4 of IRB (PB4) is clear if joystick 1's fire \ button is pressed, otherwise it is set, so AND'ing \ the value of IRB with %10000 extracts this bit EOR #%00010000 \ Flip bit 4 so that it's set if the fire button has STA KY7 \ been pressed, and store the result in the keyboard \ logger at location KY7, which is also where the A key \ (fire lasers) key is logged 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 JMP DK4 \ We are done scanning the joystick flight controls, \ so jump to DK4 to scan for other keys, using a tail \ call so we can return from the subroutine there
Name: U% [Show more] Type: Subroutine Category: Keyboard Summary: Clear the key logger
Context: See this subroutine on its own page References: This subroutine is called as follows: * DEATH calls U% * DOKEY calls U% * RES2 calls U%

Returns: A A is set to 0 Y Y is set to 0
.U% LDA #0 \ Set A to 0, as this means "key not pressed" in the \ key logger at KL LDY #16 \ We want to clear the 16 key logger locations from \ KY1 to KY20, so set a counter in Y .DKL3 STA KL,Y \ Store 0 in the Y-th byte of the key logger DEY \ Decrement the counter BNE DKL3 \ And loop back for the next key, until we have just \ KL+1. We don't want to clear the first key logger \ location at KL, as the keyboard table at KYTB starts \ with offset 1, not 0, so KL is not technically part of \ the key logger (it's actually used for logging keys \ that don't appear in the keyboard table, and which \ therefore don't use the key logger) RTS \ Return from the subroutine
Name: DOKEY [Show more] Type: Subroutine Category: Keyboard Summary: Scan for the seven primary flight controls and apply the docking computer manoeuvring code 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 * DKJ1 calls via auton

Scan for the seven primary flight controls (or the equivalent on joystick), pause and configuration keys, and secondary flight controls, and update the key logger accordingly. Specifically: * If we are on keyboard configuration, clear the key logger and update it for the seven primary flight controls, and update the pitch and roll rates accordingly. * If we are on joystick configuration, clear the key logger and jump to DKJ1, which reads the joystick equivalents of the primary flight controls. Both options end up at DK4 to scan for other keys, beyond the seven primary flight controls.
Other entry points: auton Get the docking computer to "press" the flight keys to dock the ship
.DOKEY JSR U% \ Call U% to clear the key logger \ --- Mod: Code removed for Elite-A: ------------------> \LDA JSTK \ If JSTK is non-zero, then we are configured to use \BNE DKJ1 \ the joystick rather than keyboard, so jump to DKJ1 \ \ to read the joystick flight controls, before jumping \ \ to DK4 to scan for pause, configuration and secondary \ \ flight keys \ \STA BSTK \ Set BSTK = 0 to disable the Bitstik \ --- And replaced by: --------------------------------> LDA QQ22+1 \ Fetch QQ22+1, which contains the number that's shown \ on-screen during hyperspace countdown BEQ l_open \ If the hyperspace countdown is non-zero, jump to DK4 JMP DK4 \ to skip scanning for primary flight keys, and move on \ to scanning for pause, configuration and secondary \ flight keys .l_open LDA JSTK \ If JSTK is non-zero, then we are configured to use BNE DKJ1 \ the joystick rather than keyboard, so jump to DKJ1 \ to read the joystick flight controls, before jumping \ to DK4 to scan for pause, configuration and secondary \ flight keys \ --- End of replacement ------------------------------> LDY #7 \ We're going to work our way through the primary flight \ control keys (pitch, roll, speed and laser), so set a \ counter in Y so we can loop through all 7 .DKL2 JSR DKS1 \ Call DKS1 to see if the KYTB key at offset Y is being \ pressed, and set the key logger accordingly DEY \ Decrement the loop counter BNE DKL2 \ Loop back for the next key, working our way from A at \ KYTB+7 down to ? at KYTB+1 LDA auto \ If auto is 0, then the docking computer is not BEQ DK15 \ currently activated, so jump to DK15 to skip the \ docking computer manoeuvring code below .auton JSR ZINF \ Call ZINF to reset the INWK ship workspace LDA #96 \ Set nosev_z_hi = 96 STA INWK+14 ORA #%10000000 \ Set sidev_x_hi = -96 STA INWK+22 STA TYPE \ Set the ship type to -96, so the negative value will \ let us check in the DOCKIT routine whether this is our \ ship that is activating its docking computer, rather \ than an NPC ship docking LDA DELTA \ Set the ship speed to DELTA (our speed) STA INWK+27 JSR DOCKIT \ Call DOCKIT to calculate the docking computer's moves \ and update INWK with the results \ We now "press" the relevant flight keys, depending on \ the results from DOCKIT, starting with the pitch keys LDA INWK+27 \ Fetch the updated ship speed from byte #27 into A CMP #22 \ If A < 22, skip the next instruction BCC P%+4 LDA #22 \ Set A = 22, so the maximum speed during docking is 22 STA DELTA \ Update DELTA to the new value in A LDA #&FF \ Set A = &FF, which we can insert into the key logger \ to "fake" the docking computer working the keyboard LDX #0 \ Set X = 0, so we "press" KY1 below ("?", slow down) LDY INWK+28 \ If the updated acceleration in byte #28 is zero, skip BEQ DK11 \ to DK11 BMI P%+3 \ If the updated acceleration is negative, skip the \ following instruction INX \ The updated acceleration is positive, so increment X \ to 1, so we "press" KY2 below (Space, speed up) STA KY1,X \ Store &FF in either KY1 or KY2 to "press" the relevant \ key, depending on whether the updated acceleration is \ negative (in which case we "press" KY1, "?", to slow \ down) or positive (in which case we "press" KY2, \ Space, to speed up) .DK11 \ We now "press" the relevant roll keys, depending on \ the results from DOCKIT LDA #128 \ Set A = 128, which indicates no change in roll when \ stored in JSTX (i.e. the centre of the roll indicator) LDX #0 \ Set X = 0, so we "press" KY3 below ("<", increase \ roll) ASL INWK+29 \ Shift ship byte #29 left, which shifts bit 7 of the \ updated roll counter (i.e. the roll direction) into \ the C flag BEQ DK12 \ If the remains of byte #29 is zero, then the updated \ roll counter is zero, so jump to DK12 set JSTX to 128, \ to indicate there's no change in the roll BCC P%+3 \ If the C flag is clear, skip the following instruction INX \ The C flag is set, i.e. the direction of the updated \ roll counter is negative, so increment X to 1 so we \ "press" KY4 below (">", decrease roll) BIT INWK+29 \ We shifted the updated roll counter to the left above, BPL DK14 \ so this tests bit 6 of the original value, and if it \ is clear (i.e. the magnitude is less than 64), jump to \ DK14 to "press" the key and leave JSTX unchanged LDA #64 \ The magnitude of the updated roll is 64 or more, so STA JSTX \ set JSTX to 64 (so the roll decreases at half the \ maximum rate) LDA #0 \ And set A = 0 so we do not "press" any keys (so if the \ docking computer needs to make a serious roll, it does \ so by setting JSTX directly rather than by "pressing" \ a key) .DK14 STA KY3,X \ Store A in either KY3 or KY4, depending on whether \ the updated roll rate is increasing (KY3) or \ decreasing (KY4) LDA JSTX \ Fetch A from JSTX so the next instruction has no \ effect .DK12 STA JSTX \ Store A in JSTX to update the current roll rate \ We now "press" the relevant pitch keys, depending on \ the results from DOCKIT LDA #128 \ Set A = 128, which indicates no change in pitch when \ stored in JSTX (i.e. the centre of the pitch \ indicator) LDX #0 \ Set X = 0, so we "press" KY5 below ("X", decrease \ pitch, pulling the nose up) ASL INWK+30 \ Shift ship byte #30 left, which shifts bit 7 of the \ updated pitch counter (i.e. the pitch direction) into \ the C flag BEQ DK13 \ If the remains of byte #30 is zero, then the updated \ pitch counter is zero, so jump to DK13 set JSTY to \ 128, to indicate there's no change in the pitch BCS P%+3 \ If the C flag is set, skip the following instruction INX \ The C flag is clear, i.e. the direction of the updated \ pitch counter is positive (dive), so increment X to 1 \ so we "press" KY6 below ("S", increase pitch, so the \ nose dives) STA KY5,X \ Store 128 in either KY5 or KY6 to "press" the relevant \ key, depending on whether the pitch direction is \ negative (in which case we "press" KY5, "X", to \ decrease the pitch, pulling the nose up) or positive \ (in which case we "press" KY6, "S", to increase the \ pitch, pushing the nose down) LDA JSTY \ Fetch A from JSTY so the next instruction has no \ effect .DK13 STA JSTY \ Store A in JSTY to update the current pitch rate .DK15 LDX JSTX \ Set X = JSTX, the current roll rate (as shown in the \ RL indicator on the dashboard) LDA #7 \ Set A to 7, which is the amount we want to alter the \ roll rate by if the roll keys are being pressed LDY KL+3 \ If the "<" key is being pressed, then call the BUMP2 BEQ P%+5 \ routine to increase the roll rate in X by A JSR BUMP2 LDY KL+4 \ If the ">" key is being pressed, then call the REDU2 BEQ P%+5 \ routine to decrease the roll rate in X by A, taking JSR REDU2 \ the keyboard auto re-centre setting into account STX JSTX \ Store the updated roll rate in JSTX ASL A \ Double the value of A, to 14 LDX JSTY \ Set X = JSTY, the current pitch rate (as shown in the \ DC indicator on the dashboard) LDY KL+5 \ If the "X" key is being pressed, then call the REDU2 BEQ P%+5 \ routine to decrease the pitch rate in X by A, taking JSR REDU2 \ the keyboard auto re-centre setting into account LDY KL+6 \ If the "S" key is being pressed, then call the BUMP2 BEQ P%+5 \ routine to increase the pitch rate in X by A JSR BUMP2 STX JSTY \ Store the updated roll rate 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: * DKJ1 calls DK4 * DOKEY calls DK4 * mes9 calls via DK5 * OUCH calls via DK5

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
Other entry points: DK5 Contains an RTS
.DK4 JSR RDKEY \ Scan the keyboard for a key press and return the \ internal key number in A and 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 A and 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: Code removed for Elite-A: ------------------> \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 JMP DEATH2 \ ESCAPE is being pressed, so jump to DEATH2 to end \ the game \ --- Mod: Code removed for Elite-A: ------------------> \CPX #&64 \ If "B" is not being pressed, skip to nobit \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 \ --- End of removed code -----------------------------> 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 DK5 \ view), return from the subroutine (as DK5 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 \ --- Mod: Code removed for Elite-A: ------------------> \LDA #&FF \ Set A to &FF so we can store this in the keyboard \ \ logger for keys that are being pressed \ \.DKL1 \ \LDX KYTB,Y \ Get the internal key number of the Y-th flight key \ \ the KYTB keyboard table \ \CPX KL \ We stored the key that's being pressed in KL above, \ \ so check to see if the Y-th flight key is being \ \ pressed \ \BNE DK1 \ If it is not being pressed, skip to DK1 below \ \STA KL,Y \ The Y-th flight key is being pressed, so set that \ \ key's location in the key logger to &FF \ \.DK1 \ --- And replaced by: --------------------------------> .DKL1 JSR DKS1 \ Call DKS1 to see if the KYTB key at offset Y is being \ pressed, and set the key logger accordingly \ --- End of replacement ------------------------------> DEY \ Decrement the loop counter CPY #7 \ Have we just done the last key? BNE DKL1 \ If not, loop back to process the next key .DK5 RTS \ Return from the subroutine
Name: me1 [Show more] Type: Subroutine Category: Flight 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 EQUB &2C \ Fall through into ou2 to print the new message, but \ skip the first instruction by turning it into \ &2C &A9 &6C, or BIT &6CA9, which does nothing apart \ from affect the flags
Name: ou2, Removed [Show more] Type: Subroutine Category: Flight Summary: Display "E.C.M.SYSTEM DESTROYED" as an in-flight message
Context: See this subroutine on its own page References: No direct references to this subroutine in this source file
\ --- Mod: Code removed for Elite-A: ------------------> \.ou2 \ \LDA #108 \ Set A to recursive token 108 ("E.C.M.SYSTEM") \ \EQUB &2C \ Fall through into ou3 to print the new message, but \ \ skip the first instruction by turning it into \ \ &2C &A9 &6F, or BIT &6FA9, which does nothing apart \ \ from affect the flags \ --- End of removed code ----------------------------->
Name: ou3, Removed [Show more] Type: Subroutine Category: Flight Summary: Display "FUEL SCOOPS DESTROYED" as an in-flight message
Context: See this subroutine on its own page References: No direct references to this subroutine in this source file
\ --- Mod: Code removed for Elite-A: ------------------> \.ou3 \ \LDA #111 \ Set A to recursive token 111 ("FUEL SCOOPS") \ --- End of removed code ----------------------------->
Name: cargo_mtok [Show more] Type: Subroutine Category: Text Summary: Print the name of a specific cargo item
Context: See this subroutine on its own page References: This subroutine is called as follows: * OUCH calls cargo_mtok

Arguments: A The number of the cargo item whose name we want to print (where 0 = food, 1 = textiles, and so on up to 16 for alien items) See QQ23 for a list of market item numbers and their storage units
\ --- Mod: Code added for Elite-A: --------------------> .cargo_mtok ADC #208 \ Add 208 to the value in A, so when we fall through \ into MESS, we print recursive token 48 + A as an \ in-flight token, which will be in the range 48 \ ("FOOD") to 64 ("ALIEN ITEMS") \ --- End of added code ------------------------------->
Name: MESS [Show more] Type: Subroutine Category: Flight Summary: Display an in-flight message
Context: See this subroutine on its own page References: This subroutine is called as follows: * EXNO2 calls MESS * FR1 calls MESS * Ghy calls MESS * KILLSHP calls MESS * Main flight loop (Part 8 of 16) calls MESS * Main flight loop (Part 12 of 16) calls MESS * Main flight loop (Part 15 of 16) calls MESS * me2 calls MESS * OUCH calls MESS * SFRMIS 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 \ --- Mod: Code removed for Elite-A: ------------------> \LDX #0 \ Set QQ17 = 0 to switch to ALL CAPS \STX QQ17 \ --- And replaced by: --------------------------------> JSR vdu_00 \ Call vdu_00 to switch to ALL CAPS \ --- End of replacement ------------------------------> 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: Flight 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 bit 0 of variable de is clear, return from the BCC DK5 \ subroutine (as DK5 contains an RTS) LDA #253 \ Print recursive token 93 (" DESTROYED") and return JMP TT27 \ from the subroutine using a tail call
Name: OUCH [Show more] Type: Subroutine Category: Flight Summary: Potentially lose cargo or equipment following damage
Context: See this subroutine on its own page References: This subroutine is called as follows: * OOPS calls OUCH

Our shields are dead and we are taking damage, so there is a small chance of losing cargo or equipment.
.OUCH JSR DORND \ Set A and X to random numbers BMI DK5 \ If A < 0 (50% chance), return from the subroutine \ (as DK5 contains an RTS) \ --- Mod: Code removed for Elite-A: ------------------> \CPX #22 \ If X >= 22 (91% chance), return from the subroutine \BCS DK5 \ (as DK5 contains an RTS) \ \LDA QQ20,X \ If we do not have any of item QQ20+X, return from the \BEQ DK5 \ subroutine (as DK5 contains an RTS). X is in the range \ \ 0-21, so this not only checks for cargo, but also for \ \ E.C.M., fuel scoops, energy bomb, energy unit and \ \ docking computer, all of which can be destroyed \ --- And replaced by: --------------------------------> CPX #24 \ If X >= 24 (90% chance), return from the subroutine BCS DK5 \ (as DK5 contains an RTS) LDA CRGO,X \ If we do not have any of item CRGO+X, return from the BEQ DK5 \ subroutine (as DK5 contains an RTS). X is in the range \ 0-23, so this not only checks for cargo, but also for \ the I.F.F. system, E.C.M. system, fuel scoops, \ hyperspace unit, energy unit, docking computer and \ galactic hyperdrive, all of which can be destroyed \ --- End of replacement ------------------------------> LDA DLY \ If there is already an in-flight message on-screen, BNE DK5 \ return from the subroutine (as DK5 contains an RTS) LDY #3 \ Set bit 1 of de, the equipment destruction flag, so STY de \ that when we call MESS below, " DESTROYED" is appended \ to the in-flight message \ --- Mod: Code removed for Elite-A: ------------------> \STA QQ20,X \ A is 0 (as we didn't branch with the BNE above), so \ \ this sets QQ20+X to 0, which destroys any cargo or \ \ equipment we have of that type \ \CPX #17 \ If X >= 17 then we just lost a piece of equipment, so \BCS ou1 \ jump to ou1 to print the relevant message \ \TXA \ Print recursive token 48 + A as an in-flight token, \ADC #208 \ which will be in the range 48 ("FOOD") to 64 ("ALIEN \BNE MESS \ ITEMS") as the C flag is clear, so this prints the \ \ destroyed item's name, followed by " DESTROYED" (as we \ \ set bit 1 of the de flag above), and returns from the \ \ subroutine using a tail call \ --- And replaced by: --------------------------------> STA CRGO,X \ A is 0 (as we didn't branch with the BNE above), so \ this sets CRGO+X to 0, which destroys any cargo or \ equipment we have of that type DEX \ Decrement X, so X is now in the range -1 to 22, and a \ value of 0 means we just lost some food, 1 means we \ lost some textiles, and so on BMI ou1 \ If X is now negative, then we just lost the I.F.F. \ system (as X was 0 before being decremented), so jump \ to ou1 to print the relevant message, which will be \ "I.F.F.SYSTEM DESTROYED" as A = 0 and the C flag is \ clear (as we passed through the BCS above) CPX #17 \ If X = 17 then we just lost the E.C.M., so jump to ou1 BEQ ou1 \ to print the relevant message, which will be \ "E.C.M.SYSTEM DESTROYED" as A = 0 and the C flag is \ set from the CPX \ If we get here then X is in the range 0-16 or 18-22 TXA \ Copy the value of X into A BCC cargo_mtok \ If X < 17 then we just lost some cargo (as opposed to \ equipment), so jump to cargo_mtok to print the name of \ the cargo whose number is in A, plus " DESTROYED", and \ return from the subroutine using a tail call \ If we get here then X (and A) are in the range 18-22 CMP #18 \ If A is not 18, jump down to equip_mtok with A in the BNE equip_mtok \ range 19-22 and the C flag set from the CMP, to print \ token 113 ("HYPERSPACE UNIT") through 116 ("GALACTIC \ HYPERSPACE") LDA #111-107-1 \ Otherwise A is 18, so we have lost the fuel scoops, so \ set A to 111-107-1 = 3 and the C flag set from the CMP \ to print token 111 ("FUEL SCOOPS") \ --- End of replacement ------------------------------> .ou1 \ --- Mod: Code removed for Elite-A: ------------------> \BEQ ou2 \ If X = 17, jump to ou2 to print "E.C.M.SYSTEM \ \ DESTROYED" and return from the subroutine using a tail \ \ call \ \CPX #18 \ If X = 18, jump to ou3 to print "FUEL SCOOPS \BEQ ou3 \ DESTROYED" and return from the subroutine using a tail \ \ call \ \TXA \ Otherwise X is in the range 19 to 21 and the C flag is \ADC #113-20 \ set (as we got here via a BCS to ou1), so we set A as \ \ follows: \ \ \ \ A = 113 - 20 + X + C \ \ = 113 - 19 + X \ \ = 113 to 115 \ \BNE MESS \ Print recursive token A ("ENERGY BOMB", "ENERGY UNIT" \ \ or "DOCKING COMPUTERS") as an in-flight message, \ \ followed by " DESTROYED", and return from the \ \ subroutine using a tail call \ --- And replaced by: --------------------------------> ADC #107-93 \ We can reach here with three values of A and the C \ flag, and then add 93 below to print the following \ tokens: \ \ A = 0, C flag clear = token 107 ("I.F.F.SYSTEM") \ A = 0, C flag set = token 108 ("E.C.M.SYSTEM") \ A = 3, C flag set = token 111 ("FUEL SCOOPS") .equip_mtok ADC #93 \ We can either reach here from above, or jump straight \ here with A = 19-22 and the C flag set, in which case \ adding 93 will give us token 113 ("HYPERSPACE UNIT") \ through 116 ("GALACTIC HYPERSPACE ") INC new_hold \ We just lost a piece of equipment, so increment the \ amount of free space in the hold BNE MESS \ Print recursive token A as an in-flight message, \ followed by " DESTROYED", and return from the \ subroutine using a tail call \ --- End of replacement ------------------------------>
Name: ITEM [Show more] Type: Macro Category: Market Summary: Macro definition for the market prices table Deep dive: Market item prices and availability
Context: See this macro on its own page References: This macro is used as follows: * QQ23 uses ITEM

The following macro is used to build the market prices table: ITEM price, factor, units, quantity, mask It inserts an item into the market prices table at QQ23.
Arguments: price Base price factor Economic factor units Units: "t", "g" or "k" quantity Base quantity mask Fluctuations mask
MACRO ITEM price, factor, units, quantity, mask IF factor < 0 s = 1 << 7 ELSE s = 0 ENDIF IF units = 't' u = 0 ELIF units = 'k' u = 1 << 5 ELSE u = 1 << 6 ENDIF e = ABS(factor) EQUB price EQUB s + u + e EQUB quantity EQUB mask ENDMACRO
Name: QQ23 [Show more] Type: Variable Category: Market Summary: Market prices table
Context: See this variable on its own page References: This variable is used as follows: * GVL uses QQ23 * TT151 uses QQ23 * TT210 uses QQ23

Each item has four bytes of data, like this: Byte #0 = Base price Byte #1 = Economic factor in bits 0-4, with the sign in bit 7 Unit in bits 5-6 Byte #2 = Base quantity Byte #3 = Mask to control price fluctuations To make it easier for humans to follow, we've defined a macro called ITEM that takes the following arguments and builds the four bytes for us: ITEM base price, economic factor, units, base quantity, mask So for food, we have the following: * Base price = 19 * Economic factor = -2 * Unit = tonnes * Base quantity = 6 * Mask = %00000001
.QQ23 ITEM 19, -2, 't', 6, %00000001 \ 0 = Food ITEM 20, -1, 't', 10, %00000011 \ 1 = Textiles ITEM 65, -3, 't', 2, %00000111 \ 2 = Radioactives ITEM 40, -5, 't', 226, %00011111 \ 3 = Slaves ITEM 83, -5, 't', 251, %00001111 \ 4 = Liquor/Wines ITEM 196, 8, 't', 54, %00000011 \ 5 = Luxuries ITEM 235, 29, 't', 8, %01111000 \ 6 = Narcotics ITEM 154, 14, 't', 56, %00000011 \ 7 = Computers ITEM 117, 6, 't', 40, %00000111 \ 8 = Machinery ITEM 78, 1, 't', 17, %00011111 \ 9 = Alloys ITEM 124, 13, 't', 29, %00000111 \ 10 = Firearms ITEM 176, -9, 't', 220, %00111111 \ 11 = Furs ITEM 32, -1, 't', 53, %00000011 \ 12 = Minerals ITEM 97, -1, 'k', 66, %00000111 \ 13 = Gold ITEM 171, -2, 'k', 55, %00011111 \ 14 = Platinum ITEM 45, -1, 'g', 250, %00001111 \ 15 = Gem-Stones ITEM 53, 15, 't', 192, %00000111 \ 16 = Alien items
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.D.ELTF ", ~CODE_F%, " ", ~P%, " ", ~LOAD%, " ", ~LOAD_F% \SAVE "3-assembled-output/D.ELTF.bin", CODE_F%, P%, LOAD%