Skip to navigation

Elite on the BBC Micro and NES

Bank 0 (Part 4 of 5)

[NES version]

Name: PrintLaserView [Show more] Type: Subroutine Category: Equipment Summary: Print the name of a laser view in the laser-buying popup, filled to the right by the correct number of spaces to fill the popup
Context: See this subroutine on its own page References: This subroutine is called as follows: * HighlightLaserView calls PrintLaserView * qv calls PrintLaserView

Arguments: Y The number of the laser view: * 0 = front * 1 = rear * 2 = left * 3 = right
Returns: Y Y is preserved
.PrintLaserView LDA #12 ; Move the text cursor to column 12 STA XC TYA ; Store Y on the stack so we can retrieve it at the end PHA ; of the subroutine CLC ; Move the text cursor to row Y + 8, so we print the ADC #8 ; view on row 8 (front) to 11 (right) STA YC JSR TT162 ; Print a space LDA languageNumber ; If either bit 1 or bit 2 of languageNumber is set then AND #%00000110 ; the chosen language is German or French, so jump to BNE lasv1 ; lasv1 to skip the following JSR TT162 ; The chosen language is English, so print a space .lasv1 PLA ; Set A to the argument Y, which we stored on the stack PHA ; above CLC ; Print recursive token 96 + A, which will print from 96 ADC #96 ; ("FRONT") through to 99 ("RIGHT") JSR TT27_b2 .lasv2 JSR TT162 ; Print a space LDA XC ; Keep printing spaces until we reach the column given LDX languageIndex ; in the xLaserView table for the chosen language, so we CMP xLaserView,X ; blank out the rest of the line to the edge of the BNE lasv2 ; popup (so the popup covers what's underneath it) PLA ; Retrieve Y from the stack so it is unchanged by the TAY ; subroutine call RTS ; Return from the subroutine
Name: xLaserView [Show more] Type: Variable Category: Equipment Summary: The text column of the right edge of the laser-buying popup, so the popup gets filled with spaces and covers what's underneath it Deep dive: Multi-language support in NES Elite
Context: See this variable on its own page References: This variable is used as follows: * PrintLaserView uses xLaserView
.xLaserView EQUB 21 ; English EQUB 21 ; German EQUB 22 ; French EQUB 21 ; There is no fourth language, so this byte is ignored
Name: HighlightLaserView [Show more] Type: Subroutine Category: Equipment Summary: Highlight the laser view name in the popup menu
Context: See this subroutine on its own page References: This subroutine is called as follows: * qv calls HighlightLaserView

Arguments: Y The number of the laser view: * 0 = front * 1 = rear * 2 = left * 3 = right
Returns: Y Y is preserved
.HighlightLaserView LDA #2 ; Set the font style to print in the highlight font STA fontStyle JSR PrintLaserView ; Print the name of the laser view specified in Y at the ; correct on-screen position for the popup menu LDA #1 ; Set the font style to print in the normal font STA fontStyle TYA ; Store Y on the stack so we can retrieve it at the end PHA ; of the subroutine JSR DrawScreenInNMI ; Configure the NMI handler to draw the screen, so the ; screen gets updated JSR WaitForPPUToFinish ; Wait until both bitplanes of the screen have been ; sent to the PPU, so the screen is fully updated and ; there is no more data waiting to be sent to the PPU PLA ; Retrieve Y from the stack so it is unchanged by the TAY ; subroutine call RTS ; Return from the subroutine
Name: popupWidth [Show more] Type: Variable Category: Equipment Summary: The width of the popup that shows the views available for installing lasers in the Equipment screen Deep dive: Multi-language support in NES Elite
Context: See this variable on its own page References: This variable is used as follows: * qv uses popupWidth
.popupWidth EQUB 10 ; English EQUB 10 ; German EQUB 11 ; French EQUB 10 ; There is no fourth language, so this byte is ignored
Name: qv [Show more] Type: Subroutine Category: Equipment Summary: Print a popup menu of the four space views, for buying lasers
Context: See this subroutine on its own page References: This subroutine is called as follows: * EQSHP calls qv

This routine does a similar job to the routine of the same name in the BBC Master version of Elite, but the code is significantly different.
Returns: X The chosen view number (0-3)
.qv JSR SetupPPUForIconBar ; If the PPU has started drawing the icon bar, configure ; the PPU to use nametable 0 and pattern table 0 LDA controller1Left03 ; If A button is being pressed, or the left or right ORA controller1Right03 ; buttons were being pressed four VBlanks ago, then ORA controller1A ; loop back to qv until they are released BMI qv LDY #3 ; We now print a popup menu showing all four views, so ; set a view counter in Y, starting with view 3 (right) .vpop1 JSR PrintLaserView ; Print the name of the laser view specified in Y at the ; correct on-screen position for the popup menu DEY ; Decrement the view counter in Y BNE vpop1 ; Loop back to print the next view until we have printed ; all four view names in the popup ; Next, we highlight the first view (front) as by this ; point Y = 0 LDA #2 ; Set the font style to print in the highlight font STA fontStyle JSR PrintLaserView ; Print the name of the laser view specified in Y at the ; correct on-screen position for the popup menu LDA #1 ; Set the font style to print in the normal font STA fontStyle ; We now draw a box around the list of views to make it ; look like a popup menu LDA #11 ; Move the text cursor to column 11 STA XC STA K+2 ; Set K+2 = 11 to pass to DrawSmallBox as the text row ; on which to draw the top-left corner of the small box LDA #7 ; Move the text cursor to row 7 STA YC STA K+3 ; Set K+3 = 7 to pass to DrawSmallBox as the text column ; on which to draw the top-left corner of the small box LDX languageIndex ; Set K to the correct width for the laser view popup in LDA popupWidth,X ; the chosen language, to pass to DrawSmallBox as the STA K ; width of the small box LDA #6 ; Set K+1 = 6 to pass to DrawSmallBox as the height of STA K+1 ; the small box JSR DrawSmallBox_b3 ; Draw a box around the popup, with the top-left corner ; at (7, 11), a height of 6 rows, and the correct width ; for the chosen language JSR DrawScreenInNMI ; Configure the NMI handler to draw the screen, so the ; screen gets updated ; The popup menu is now on-screen, so now we manage the ; process of making a choice LDY #0 ; We use Y to keep track of the highlighted view, which ; we set to the front view above, so set Y = 0 to ; reflect this .vpop2 JSR SetupPPUForIconBar ; If the PPU has started drawing the icon bar, configure ; the PPU to use nametable 0 and pattern table 0 LDA controller1Up ; If the up button is not being pressed, jump to vpop4 BPL vpop4 ; to move on to the next button check ; If we get here then we need to move the highlight up ; the menu, wrapping around if we go off the top JSR PrintLaserView ; Print the name of the laser view specified in Y at the ; correct on-screen position for the popup menu, to ; remove the highlight from the current selection DEY ; Decrement Y to move the number of the selected view up ; the menu BPL vpop3 ; If the view number is positive when we have not gone ; off the top of the menu, so jump to vpop3 to skip the ; following instruction LDY #3 ; We just moved past the top of the menu, so set Y to 3 ; to move the selection to the bottom entry in the menu ; (the right view) .vpop3 JSR HighlightLaserView ; Highlight the Y-th entry in the popup menu, to reflect ; the new choice .vpop4 LDA controller1Down ; If the down button is not being pressed, jump to vpop6 BPL vpop6 ; to move on to the next button check ; If we get here then we need to move the highlight down ; the menu, wrapping around if we go off the bottom JSR PrintLaserView ; Print the name of the laser view specified in Y at the ; correct on-screen position for the popup menu, to ; remove the highlight from the current selection INY ; Increment Y to move the number of the selected view ; down the menu CPY #4 ; If Y is not 4 then we have not gone off the bottom of BNE vpop5 ; the menu, so jump to vpop5 to skip the following ; instruction LDY #0 ; We just moved past the bottom of the menu, so set Y to ; 0 to move the selection to the top entry in the menu ; (the front view) .vpop5 JSR HighlightLaserView ; Highlight the Y-th entry in the popup menu, to reflect ; the new choice .vpop6 LDA controller1A ; If the A button is being pressed, jump to vpop7 to BMI vpop7 ; return the highlighted view as the chosen laser view LDA iconBarChoice ; If iconBarChoice = 0 then nothing has been chosen on BEQ vpop2 ; the icon bar (if it had, iconBarChoice would contain ; the number of the chosen icon bar button), so loop ; back to vpop2 to keep processing the popup keys ; If we get here then either a choice has been made on ; the icon bar during NMI and the number of the icon bar ; button is in iconBarChoice, or the Start button has ; been pressed and iconBarChoice is 80 CMP #80 ; If iconBarChoice = 80 then the Start button has been BNE vpop7 ; pressed to pause the game, so if this is not the case, ; then a different icon bar option has been chosen, so ; jump to vpop7 to return from the subroutine and abort ; the laser purchase ; If we get here then iconBarChoice = 80, which means ; the Start button has been pressed to pause the game LDA #0 ; Set iconBarChoice = 0 to clear the pause button press STA iconBarChoice ; so we don't simply re-enter the pause menu when we ; resume JSR PauseGame_b6 ; Pause the game and process choices from the pause menu ; until the game is unpaused by another press of Start JMP vpop2 ; Jump back to vpop2 to pick up where we left off and go ; back to processing the popup choice .vpop7 TYA ; Copy the number of the highlighted laser view from Y TAX ; into X, so we can return the choice in X RTS ; Return from the subroutine
Name: refund [Show more] Type: Subroutine Category: Equipment Summary: Install a new laser, processing a refund if applicable
Context: See this subroutine on its own page References: This subroutine is called as follows: * EQSHP calls refund

Arguments: A The power of the new laser to be fitted X The view number for fitting the new laser (0-3)
Returns: A A is preserved X X is preserved
.refund STA T1 ; Store A in T1 so we can retrieve it later LDA LASER,X ; If there is no laser in view X (i.e. the laser power BEQ ref3 ; is zero), jump to ref3 to skip the refund code LDY #4 ; If the current laser has power #POW+9 (pulse laser), CMP #POW+9 ; jump to ref1 with Y = 4 (the item number of a pulse BEQ ref1 ; laser in the table at PRXS) LDY #5 ; If the current laser has power #POW+128 (beam laser), CMP #POW+128 ; jump to ref1 with Y = 5 (the item number of a beam BEQ ref1 ; laser in the table at PRXS) LDY #12 ; If the current laser has power #Armlas (military CMP #Armlas ; laser), jump to ref1 with Y = 12 (the item number of a BEQ ref1 ; military laser in the table at PRXS) LDY #13 ; Otherwise this is a mining laser, so fall through into ; ref1 with Y = 13 (the item number of a mining laser in ; the table at PRXS) .ref1 ; We now want to refund the laser of type Y that we are ; exchanging for the new laser STX ZZ ; Store the view number in ZZ so we can retrieve it ; later TYA ; Copy the laser type to be refunded from Y to A JSR prx ; Call prx to set (Y X) to the price of equipment item ; number A JSR MCASH ; Call MCASH to add (Y X) to the cash pot LDX ZZ ; Retrieve the view number from ZZ .ref3 ; Finally, we install the new laser LDA T1 ; Retrieve the new laser's power from T1 into A STA LASER,X ; Set the laser view to the new laser's power JSR BEEP_b7 ; Call the BEEP subroutine to make a short, high beep JMP EQSHP ; Jump back to the EQSHP routine (which called this ; routine using a JMP), to redisplay the Equip Ship ; screen RTS ; Return from the subroutine
Name: PRXS [Show more] Type: Variable Category: Equipment Summary: Equipment prices
Context: See this variable on its own page References: This variable is used as follows: * prx uses PRXS

Equipment prices are stored as 10 * the actual value, so we can support prices with fractions of credits (0.1 Cr). This is used for the price of fuel only.
.PRXS EQUW 2 ; 0 Fuel 0.2 Cr (per 0.1 LY) EQUW 300 ; 1 Missile 30.0 Cr EQUW 4000 ; 2 Large Cargo Bay 400.0 Cr EQUW 6000 ; 3 E.C.M. System 600.0 Cr EQUW 4000 ; 4 Extra Pulse Lasers 400.0 Cr EQUW 10000 ; 5 Extra Beam Lasers 1000.0 Cr EQUW 5250 ; 6 Fuel Scoops 525.0 Cr EQUW 10000 ; 7 Escape Pod 1000.0 Cr EQUW 9000 ; 8 Energy Bomb 900.0 Cr EQUW 15000 ; 9 Energy Unit 1500.0 Cr EQUW 2000 ; 10 Docking Computer 200.0 Cr EQUW 50000 ; 11 Galactic Hyperspace 5000.0 Cr EQUW 60000 ; 12 Extra Military Lasers 6000.0 Cr EQUW 8000 ; 13 Extra Mining Lasers 800.0 Cr
Name: SetSelectedSeeds [Show more] Type: Subroutine Category: Universe Summary: Set the seeds for the selected system in QQ15 to the seeds in the safehouse
Context: See this subroutine on its own page References: This subroutine is called as follows: * MESS calls SetSelectedSeeds
.SetSelectedSeeds LDX #5 ; We now want to copy the seeds for the selected system ; from safehouse into QQ15, where we store the seeds for ; the selected system, so set up a counter in X for ; copying six bytes (for three 16-bit seeds) .safe1 LDA safehouse,X ; Copy the X-th byte in safehouse to the X-th byte in STA QQ15,X ; QQ15 DEX ; Decrement the counter BPL safe1 ; Loop back until we have copied all six bytes
Name: cpl [Show more] Type: Subroutine Category: Universe Summary: Print the selected system name Deep dive: Generating system names Galaxy and system seeds
Context: See this subroutine on its own page References: This subroutine is called as follows: * HME2 calls cpl * PrintCtrlCode calls cpl * SetSelectedSystem calls cpl * TT23 calls cpl * ypl calls cpl

Print control code 3 (the selected system name, i.e. the one in the crosshairs in the Short-range Chart).
.cpl LDX #5 ; First we need to back up the seeds in QQ15, so set up ; a counter in X to cover three 16-bit seeds (i.e. ; 6 bytes) .TT53 LDA QQ15,X ; Copy byte X from QQ15 to QQ19 STA QQ19,X DEX ; Decrement the loop counter BPL TT53 ; Loop back for the next byte to back up LDY #3 ; Step 1: Now that the seeds are backed up, we can ; start the name-generation process. We will either ; need to loop three or four times, so for now set ; up a counter in Y to loop four times BIT QQ15 ; Check bit 6 of s0_lo, which is stored in QQ15 BVS P%+3 ; If bit 6 is set then skip over the next instruction DEY ; Bit 6 is clear, so we only want to loop three times, ; so decrement the loop counter in Y STY T ; Store the loop counter in T .TT55 SETUP_PPU_FOR_ICON_BAR ; If the PPU has started drawing the icon bar, configure ; the PPU to use nametable 0 and pattern table 0 LDA QQ15+5 ; Step 2: Load s2_hi, which is stored in QQ15+5, and AND #%00011111 ; extract bits 0-4 by AND'ing with %11111 BEQ P%+7 ; If all those bits are zero, then skip the following ; two instructions to go to step 3 ORA #%10000000 ; We now have a number in the range 1-31, which we can ; easily convert into a two-letter token, but first we ; need to add 128 (or set bit 7) to get a range of ; 129-159 JSR TT27_b2 ; Print the two-letter token in A JSR TT54 ; Step 3: twist the seeds in QQ15 DEC T ; Decrement the loop counter BPL TT55 ; Loop back for the next two letters LDX #5 ; We have printed the system name, so we can now ; restore the seeds we backed up earlier. Set up a ; counter in X to cover three 16-bit seeds (i.e. 6 ; bytes) .TT56 LDA QQ19,X ; Copy byte X from QQ19 to QQ15 STA QQ15,X DEX ; Decrement the loop counter BPL TT56 ; Loop back for the next byte to restore RTS ; Once all the seeds are restored, return from the ; subroutine
Name: cmn [Show more] Type: Subroutine Category: Status Summary: Print the commander's name
Context: See this subroutine on its own page References: This subroutine is called as follows: * PrintCtrlCode calls cmn

Print control code 4 (the commander's name).
Other entry points: cmn-1 Contains an RTS
.cmn LDY #0 ; Set up a counter in Y, starting from 0 .QUL4 LDA NAME,Y ; The commander's name is stored at NAME, so load the ; Y-th character from NAME CMP #' ' ; If we have found a space, then we have reached the end BEQ ypl-1 ; of the name, return from the subroutine (ypl-1 points ; to the RTS below) JSR DASC_b2 ; Print the character we just loaded INY ; Increment the loop counter CPY #7 ; Loop back for the next character until we have either BNE QUL4 ; found a carriage return or have printed seven ; characters RTS ; Return from the subroutine
Name: ypl [Show more] Type: Subroutine Category: Universe Summary: Print the current system name
Context: See this subroutine on its own page References: This subroutine is called as follows: * ypls calls ypl * cmn calls via ypl-1

Print control code 2 (the current system name).
Other entry points: ypl-1 Contains an RTS
.ypl BIT MJ ; Check the mis-jump flag at MJ, and if bit 7 is set BMI ypl16 ; then we are in witchspace, and witchspace doesn't have ; a system name, so jump to ypl16 to return from the ; subroutine JSR TT62 ; Call TT62 below to swap the three 16-bit seeds in ; QQ2 and QQ15 (before the swap, QQ2 contains the seeds ; for the current system, while QQ15 contains the seeds ; for the selected system) JSR cpl ; Call cpl to print out the system name for the seeds ; in QQ15 (which now contains the seeds for the current ; system) ; Now we fall through into the TT62 subroutine, which ; will swap QQ2 and QQ15 once again, so everything goes ; back into the right place, and the RTS at the end of ; TT62 will return from the subroutine .TT62 LDX #5 ; Set up a counter in X for the three 16-bit seeds we ; want to swap (i.e. 6 bytes) .TT78 LDA QQ15,X ; Swap byte X between QQ2 and QQ15 LDY QQ2,X STA QQ2,X STY QQ15,X DEX ; Decrement the loop counter BPL TT78 ; Loop back for the next byte to swap .ypl16 RTS ; Once all bytes are swapped, return from the ; subroutine
Name: tal [Show more] Type: Subroutine Category: Universe Summary: Print the current galaxy number
Context: See this subroutine on its own page References: This subroutine is called as follows: * tals calls tal

Print control code 1 (the current galaxy number, right-aligned to width 3).
.tal CLC ; We don't want to print the galaxy number with a ; decimal point, so clear the C flag for pr2 to take as ; an argument LDX GCNT ; Load the current galaxy number from GCNT into X INX ; Add 1 to the galaxy number, as the galaxy numbers ; are 0-7 internally, but we want to display them as ; galaxy 1 through 8 JMP pr2 ; Jump to pr2, which prints the number in X to a width ; of 3 figures, left-padding with spaces to a width of ; 3, and return from the subroutine using a tail call
Name: fwl [Show more] Type: Subroutine Category: Status Summary: Print fuel and cash levels
Context: See this subroutine on its own page References: This subroutine is called as follows: * fwls calls fwl * TT213 calls fwl * dn calls via PCASH * PrintCash calls via PCASH

Print control code 5 ("FUEL: ", fuel level, " LIGHT YEARS", newline, "CASH:", control code 0).
Other entry points: PCASH Print the amount of cash only
.fwl LDA languageNumber ; If bit 1 of languageNumber is set then the chosen AND #%00000010 ; language is French, so jump to fuel3 to print the fuel BNE fuel3 ; and cash levels with different indents, to cater for ; the difference in language LDA #105 ; Print recursive token 105 ("FUEL") followed by a JSR TT68 ; colon JSR Print2Spaces ; Print two spaces LDA languageNumber ; If bit 2 of languageNumber is clear then the chosen AND #%00000100 ; language is not French, so jump to fuel1 to skip the BEQ fuel1 ; following JSR Print2Spaces ; Print two spaces .fuel1 LDX QQ14 ; Load the current fuel level from QQ14 SEC ; We want to print the fuel level with a decimal point, ; so set the C flag for pr2 to take as an argument JSR pr2 ; Call pr2, which prints the number in X to a width of ; 3 figures (i.e. in the format x.x, which will always ; be exactly 3 characters as the maximum fuel is 7.0) LDA #195 ; Print recursive token 35 ("LIGHT YEARS") followed by JSR plf ; a newline LDA #197 ; Print recursive token 37 ("CASH") followed by a colon JSR TT68 LDA languageNumber ; If bit 2 of languageNumber is set then the chosen AND #%00000100 ; language is French, so jump to fuel2 to skip the BNE fuel2 ; following two instructions JSR Print2Spaces ; Print two spaces JSR TT162 ; Print a space .fuel2 LDA #0 ; Set A = 0 so we print recursive token 0 at fuel4, ; which prints control code 0 (current amount of cash ; and newline) BEQ fuel4 ; Jump to fuel4 to print the token in A (this BNE is ; effectively a JMP as A is always zero) .fuel3 ; If we get here then the chosen language is French LDA #105 ; Print recursive token 105 ("FUEL") followed by a JSR PrintTokenAndColon ; colon, ensuring that the colon is printed in green ; despite being in a 2x2 attribute block set for white ; text JSR TT162 ; Print a space LDX QQ14 ; Load the current fuel level from QQ14 SEC ; We want to print the fuel level with a decimal point, ; so set the C flag for pr2 to take as an argument JSR pr2 ; Call pr2, which prints the number in X to a width of ; 3 figures (i.e. in the format x.x, which will always ; be exactly 3 characters as the maximum fuel is 7.0) LDA #195 ; Print recursive token 35 ("LIGHT YEARS") followed by JSR plf ; a newline LDA #197 ; Print recursive token 37 ("CASH") followed by a colon JSR TT68 LDA #0 ; Set A = 0 so we print recursive token 0 at fuel4, ; which prints control code 0 (current amount of cash ; and newline) BEQ fuel4 ; Jump to fuel4 to print the token in A (this BNE is ; effectively a JMP as A is always zero) .PCASH LDA #119 ; Set A = 119 so we print recursive token 119 below ; ("CASH:" then control code 0, which prints cash ; levels, then " CR" and newline) .fuel4 JMP spc ; Print the recursive token in A and return from the ; subroutine using a tail call
Name: Print4Spaces [Show more] Type: Subroutine Category: Text Summary: An unused routine that prints four spaces
Context: See this subroutine on its own page References: No direct references to this subroutine in this source file
.Print4Spaces JSR Print2Spaces ; Print two spaces ; Fall through into Print2Spaces to print another two ; newlines
Name: Print2Spaces [Show more] Type: Subroutine Category: Text Summary: Print two spaces
Context: See this subroutine on its own page References: This subroutine is called as follows: * fwl calls Print2Spaces * Print4Spaces calls Print2Spaces
.Print2Spaces JSR TT162 ; Print two spaces, returning from the subroutine using JMP TT162 ; a tail call
Name: ypls [Show more] Type: Subroutine Category: Text Summary: Print the current system name
Context: See this subroutine on its own page References: This subroutine is called as follows: * PrintCtrlCode calls ypls
.ypls JMP ypl ; Jump to ypl to print the current system name and ; return from the subroutine using a tail call
Name: csh [Show more] Type: Subroutine Category: Status Summary: Print the current amount of cash
Context: See this subroutine on its own page References: This subroutine is called as follows: * PrintCtrlCode calls csh

Print control code 0 (the current amount of cash, right-aligned to width 9, followed by " CR" and a newline).
.csh LDX #3 ; We are going to use the BPRNT routine to print out ; the current amount of cash, which is stored as a ; 32-bit number at location CASH. BPRNT prints out ; the 32-bit number stored in K, so before we call ; BPRNT, we need to copy the four bytes from CASH into ; K, so first we set up a counter in X for the 4 bytes .pc1 LDA CASH,X ; Copy byte X from CASH to K STA K,X DEX ; Decrement the loop counter BPL pc1 ; Loop back for the next byte to copy LDA #11 ; We want to print the cash amount using up to 11 digits STA U ; (including the decimal point), so store this in U ; for BRPNT to take as an argument SEC ; We want to print the cash amount with a decimal point, ; so set the C flag for BRPNT to take as an argument JSR BPRNT ; Print the amount of cash to 9 digits with a decimal ; point LDA #226 ; Print recursive token 66 (" CR") JSR TT27_b2 JSR TT162 ; Print two spaces and return from the subroutine using JMP TT162 ; a tail call
Name: plf [Show more] Type: Subroutine Category: Text Summary: Print a text token followed by a newline
Context: See this subroutine on its own page References: This subroutine is called as follows: * fwl calls plf * PrintCombatRank calls plf * PrintLegalStatus calls plf * STATUS calls plf

Arguments: A The text token to be printed
.plf JSR TT27_b2 ; Print the text token in A JMP TT67 ; Jump to TT67 to print a newline and return from the ; subroutine using a tail call
Name: TT68 [Show more] Type: Subroutine Category: Text Summary: Print a text token followed by a colon
Context: See this subroutine on its own page References: This subroutine is called as follows: * fwl calls TT68 * PrintCombatRank calls TT68 * TT146 calls TT68 * TT25 calls TT68

Arguments: A The text token to be printed
.TT68 JSR TT27_b2 ; Print the text token in A and fall through into TT73 ; to print a colon
Name: TT73 [Show more] Type: Subroutine Category: Text Summary: Print a colon
Context: See this subroutine on its own page References: This subroutine is called as follows: * PrintCtrlCode calls TT73
.TT73 LDA #':' ; Print a colon, returning from the subroutine using a JMP TT27_b2 ; tail call
Name: tals [Show more] Type: Subroutine Category: Text Summary: Print the current galaxy number
Context: See this subroutine on its own page References: This subroutine is called as follows: * PrintCtrlCode calls tals
.tals JMP tal ; Jump to tal to print the current galaxy number and ; return from the subroutine using a tail call
Name: PrintCtrlCode [Show more] Type: Subroutine Category: Text Summary: Print a control code (in the range 0 to 9) Deep dive: Multi-language support in NES Elite
Context: See this subroutine on its own page References: This subroutine is called as follows: * PrintCtrlCode_b0 calls PrintCtrlCode
.PrintCtrlCode TXA ; Copy the token number from X to A. We can then keep ; decrementing X and testing it against zero, while ; keeping the original token number intact in A; this ; effectively implements a switch statement on the ; value of the token BEQ csh ; If token = 0, this is control code 0 (current amount ; of cash and newline), so jump to csh to print the ; amount of cash and return from the subroutine using ; a tail call DEX ; If token = 1, this is control code 1 (current galaxy BEQ tals ; number), so jump to tal via tals to print the galaxy ; number and return from the subroutine using a tail ; call DEX ; If token = 2, this is control code 2 (current system BEQ ypls ; name), so jump to ypl via ypls to print the current ; system name and return from the subroutine using a ; tail call DEX ; If token > 3, skip the following instruction BNE P%+5 JMP cpl ; This token is control code 3 (selected system name) ; so jump to cpl to print the selected system name ; and return from the subroutine using a tail call DEX ; If token <> 4, skip the following instruction BNE P%+5 JMP cmn ; This token is control code 4 (commander name) so jump ; to cmn to print the commander name and return from the ; subroutine using a tail call DEX ; If token = 5, this is control code 5 (fuel, newline, BEQ fwls ; cash, newline), so jump to fwl via fwls to print the ; fuel level and return from the subroutine using a tail ; call DEX ; If token > 6, skip the following three instructions BNE ptok2 LDA #%10000000 ; This token is control code 6 (switch to Sentence STA QQ17 ; Case), so set bit 7 of QQ17 to switch to Sentence Case .ptok1 RTS ; Return from the subroutine .ptok2 DEX ; If token = 7, this is control code 7 (beep), so jump BEQ ptok1 ; to ptok1 to return from the subroutine DEX ; If token > 8, jump to ptok3 BNE ptok3 STX QQ17 ; This is control code 8, so set QQ17 = 0 to switch to ; ALL CAPS (we know X is zero as we just passed through ; a BNE) RTS ; Return from the subroutine .ptok3 ; If we get here then token > 8, so this is control code ; 9 (print a colon then tab to column 22 or 23) JSR TT73 ; Print a colon LDA languageNumber ; If bit 1 of languageNumber is set, then the chosen AND #%00000010 ; language is German, so jump to ptok4 to move the text BNE ptok4 ; cursor to column 23 LDA #22 ; Bit 1 of languageNumber is clear, so the chosen STA XC ; language is English or French, so move the text cursor ; to column 22 RTS ; Return from the subroutine .ptok4 LDA #23 ; Move the text cursor to column 23 STA XC RTS ; Return from the subroutine
Name: fwls [Show more] Type: Subroutine Category: Text Summary: Print fuel and cash levels
Context: See this subroutine on its own page References: This subroutine is called as follows: * PrintCtrlCode calls fwls
.fwls JMP fwl ; Jump to fwl to print the fuel and cash levels, and ; return from the subroutine using a tail call
Name: SOS1 [Show more] Type: Subroutine Category: Universe Summary: Update the missile indicators, set up the planet data block
Context: See this subroutine on its own page References: This subroutine is called as follows: * SOLAR calls SOS1 * TT110 calls SOS1

Update the missile indicators, and set up a data block for the planet, but only setting the pitch and roll counters to 127 (no damping).
.SOS1 JSR msblob ; Reset the dashboard's missile indicators so none of ; them are targeted LDA #127 ; Set the pitch and roll counters to 127, so that's a STA INWK+29 ; clockwise roll and a diving pitch with no damping, so STA INWK+30 ; the planet's rotation doesn't slow down LDA tek ; Set A = 128 or 130 depending on bit 1 of the system's AND #%00000010 ; tech level in tek ORA #%10000000 JMP NWSHP ; Add a new planet to our local bubble of universe, ; with the planet type defined by A (128 is a planet ; with an equator and meridian, 130 is a planet with ; a crater)
Name: SOLAR [Show more] Type: Subroutine Category: Universe Summary: Set up various aspects of arriving in a new system Deep dive: The Trumbles mission
Context: See this subroutine on its own page References: This subroutine is called as follows: * PlayDemo calls SOLAR * TT18 calls SOLAR

Halve our legal status, update the missile indicators, and set up data blocks and slots for the planet and sun.
.SOLAR LDA TRIBBLE ; If we have no Trumbles in the hold, skip to nobirths BEQ nobirths ; If we get here then we have Trumbles in the hold, so ; this is where they breed LDA #0 ; Trumbles eat food during the hyperspace journey, so STA QQ20 ; zero the amount of food in the hold JSR DORND ; Take the number of Trumbles from TRIBBLE(1 0), add a AND #15 ; random number between 4 and 15, and double the result, ADC TRIBBLE ; storing the resulting number in TRIBBLE(1 0) ORA #4 ; ROL A ; We start with the low byte STA TRIBBLE ROL TRIBBLE+1 ; And then do the high byte BPL P%+5 ; If bit 7 of the high byte is set, then rotate the high ROR TRIBBLE+1 ; byte back to the right, so the number of Trumbles is ; always positive .nobirths LSR FIST ; Halve our legal status in FIST, making us less bad, ; and moving bit 0 into the C flag (so every time we ; arrive in a new system, our legal status improves a ; bit) JSR ZINF ; Call ZINF to reset the INWK ship workspace, which ; doesn't affect the C flag LDA QQ15+1 ; Fetch s0_hi AND #%00000011 ; Extract bits 0-1 (which also help to determine the ; economy), which will be between 0 and 3 ADC #3 ; Add 3 + C, to get a result between 3 and 7, clearing ; the C flag in the process STA INWK+8 ; Store the result in z_sign in byte #6 LDX QQ15+2 ; Set the C flag if s1_lo >= 128, otherwise clear it CPX #128 ROR A ; Halve A and set the sign bit to the C flag, and set STA INWK+2 ; x_sign to the result, so this moves the planet to the ; right or left of centre ROL A ; Set A to x_sign << 1, ready for us to roll in the ; sign bit again for y_sign LDX QQ15+3 ; Set the C flag if s1_hi >= 128, otherwise clear it CPX #128 ROR A ; Set the sign bit to the C flag and set y_sign to the STA INWK+5 ; result, so this moves the planet up or down from the ; centre JSR SOS1 ; Call SOS1 to set up the planet's data block and add it ; to FRIN, where it will get put in the first slot as ; it's the first one to be added to our local bubble of ; this new system's universe LDA QQ15+3 ; Fetch s1_hi, extract bits 0-2, set bits 0 and 7 and AND #%00000111 ; store in z_sign, so the sun is behind us at a distance ORA #%10000001 ; of 1 to 7 STA INWK+8 LDA QQ15+5 ; Fetch s2_hi, extract bits 0-1 and store in x_sign and AND #%00000011 ; y_sign, so the sun is either dead centre in our rear STA INWK+2 ; laser crosshairs, or off to the top left by a distance STA INWK+1 ; of 1 or 2 when we look out the back LDA #0 ; Set the pitch and roll counters to 0 (no rotation) STA INWK+29 STA INWK+30 STA FRIN+1 ; Set the second slot in the FRIN table to 0, which ; sets this slot to empty, so when we call NWSHP below ; the new sun that gets created will go into FRIN+1 STA SSPR ; Set the "space station present" flag to 0, as we are ; no longer in the space station's safe zone LDA #129 ; Set A = 129, the ship type for the sun JSR NWSHP ; Call NWSHP to set up the sun's data block and add it ; to FRIN, where it will get put in the second slot as ; it's the second one to be added to our local bubble ; of this new system's universe
Name: NWSTARS [Show more] Type: Subroutine Category: Stardust Summary: Initialise the stardust field
Context: See this subroutine on its own page References: This subroutine is called as follows: * LOOK1 calls NWSTARS * TT110 calls NWSTARS

This routine is called when the space view is initialised in routine LOOK1.
.NWSTARS LDA QQ11 ; If this is not a space view (in which case QQ11 > 0), ORA demoInProgress ; or demoInProgress > 0 (in which case we are playing BNE WPSHPS ; the demo), jump to WPSHPS to skip the initialisation ; of the SX, SY and SZ tables
Name: nWq [Show more] Type: Subroutine Category: Stardust Summary: Create a random cloud of stardust
Context: See this subroutine on its own page References: This subroutine is called as follows: * DEATH calls nWq

Create a random cloud of stardust containing the correct number of dust particles, i.e. NOSTM of them, which is 3 in witchspace and 20 (#NOST) in normal space. Also hides ships from the screen. This is called by the DEATH routine when it displays our untimely demise.
.nWq LDA nmiCounter ; Set the random number seeds to a fairly random state CLC ; that's based on the NMI counter (which increments ADC RAND ; every VBlank, so will be pretty random) STA RAND LDA nmiCounter STA RAND+1 LDY NOSTM ; Set Y to the current number of stardust particles, so ; we can use it as a counter through all the stardust .SAL4 SETUP_PPU_FOR_ICON_BAR ; If the PPU has started drawing the icon bar, configure ; the PPU to use nametable 0 and pattern table 0 JSR DORND ; Set A and X to random numbers ORA #8 ; Set A so that it's at least 8 STA SZ,Y ; Store A in the Y-th particle's z_hi coordinate at ; SZ+Y, so the particle appears in front of us STA ZZ ; Set ZZ to the particle's z_hi coordinate JSR DORND ; Set A and X to random numbers ORA #16 ; Set A so that it's at least 16 AND #%11111000 ; Zero bits 0 to 2 of A so that it's a multiple of 8 STA SX,Y ; Store A in the Y-th particle's x_hi coordinate at ; SX+Y, so the particle appears in front of us JSR DORND ; Set A and X to random numbers STA SY,Y ; Store A in the Y-th particle's y_hi coordinate at ; SY+Y, so the particle appears in front of us STA SXL,Y ; Store A in the low bytes of the Y-th particle's three STA SYL,Y ; coordinates STA SZL,Y DEY ; Decrement the counter to point to the next particle of ; stardust BNE SAL4 ; Loop back to SAL4 until we have randomised all the ; stardust particles ; Fall through into WPSHPS to hide ships from the screen
Name: WPSHPS [Show more] Type: Subroutine Category: Dashboard Summary: Set all ships to be hidden from the screen
Context: See this subroutine on its own page References: This subroutine is called as follows: * NWSTARS calls WPSHPS * RES2 calls WPSHPS
.WPSHPS LDX #0 ; Set up a counter in X to work our way through all the ; ship slots in FRIN .WSL1 SETUP_PPU_FOR_ICON_BAR ; If the PPU has started drawing the icon bar, configure ; the PPU to use nametable 0 and pattern table 0 LDA FRIN,X ; Fetch the ship type in slot X BEQ WS2 ; If the slot contains 0 then it is empty and we have ; checked all the slots (as they are always shuffled ; down in the main loop to close up and gaps), so jump ; to WS2 as we are done BMI WS1 ; If the slot contains a ship type with bit 7 set, then ; it contains the planet or the sun, so jump down to WS1 ; to skip this slot, as the planet and sun don't appear ; on the scanner STA TYPE ; Store the ship type in TYPE JSR GINF ; Call GINF to get the address of the data block for ; ship slot X and store it in INF LDY #31 ; Clear bits 3 and 6 in the ship's byte #31, which stops LDA (INF),Y ; drawing the ship on-screen (bit 3), and denotes that AND #%10110111 ; the explosion has not been drawn and there are no STA (INF),Y ; lasers firing (bit 6) .WS1 INX ; Increment X to point to the next ship slot BNE WSL1 ; Loop back up to process the next slot (this BNE is ; effectively a JMP as X will never be zero) .WS2 LDX #0 ; Set X = 0 (though this appears not to be used) RTS ; Return from the subroutine
Name: SHD [Show more] Type: Subroutine Category: Flight Summary: Charge a shield and drain some energy from the energy banks
Context: See this subroutine on its own page References: This subroutine is called as follows: * ChargeShields calls SHD

Charge up a shield, and if it needs charging, drain some energy from the energy banks.
Arguments: X The value of the shield to recharge
DEX ; Increment the shield value so that it doesn't go past ; a maximum of 255 RTS ; Return from the subroutine .SHD INX ; Increment the shield value BEQ SHD-2 ; If the shield value is 0 then this means it was 255 ; before, which is the maximum value, so jump to SHD-2 ; to bring it back down to 258 and return ; Otherwise fall through into DENGY to drain our energy ; to pay for all this shield charging
Name: DENGY [Show more] Type: Subroutine Category: Flight Summary: Drain some energy from the energy banks
Context: See this subroutine on its own page References: This subroutine is called as follows: * FlightLoop4To16 calls DENGY * LASLI calls DENGY

Returns: Z flag Set if we have no energy left, clear otherwise
.DENGY DEC ENERGY ; Decrement the energy banks in ENERGY PHP ; Save the flags on the stack BNE paen2 ; If the energy levels are not yet zero, skip the ; following instruction INC ENERGY ; The minimum allowed energy level is 1, and we just ; reached 0, so increment ENERGY back to 1 .paen2 PLP ; Restore the flags from the stack, so we return with ; the Z flag from the DEC instruction above RTS ; Return from the subroutine
Name: COMPAS [Show more] Type: Subroutine Category: Dashboard Summary: Update the compass Deep dive: Sprite usage in NES Elite
Context: See this subroutine on its own page References: This subroutine is called as follows: * DrawSpaceViewInNMI calls COMPAS
.comp1 LDA #240 ; Hide sprite 13 (the compass dot) by moving it to STA ySprite13 ; y-coordinate 240, off the bottom of the screen RTS ; Return from the subroutine .COMPAS LDA MJ ; If we are in witchspace (i.e. MJ is non-zero), jump up BNE comp1 ; to comp1 to hide the compass dot LDA SSPR ; If we are inside the space station safe zone, jump to BNE SP1 ; SP1 to draw the space station on the compass JSR SPS1 ; Otherwise we need to draw the planet on the compass, ; so first call SPS1 to calculate the vector to the ; planet and store it in XX15 JMP SP2 ; Jump to SP2 to draw XX15 on the compass, returning ; from the subroutine using a tail call
Name: SP1 [Show more] Type: Subroutine Category: Dashboard Summary: Draw the space station on the compass
Context: See this subroutine on its own page References: This subroutine is called as follows: * COMPAS calls SP1
.SP1 JSR SPS4 ; Call SPS4 to calculate the vector to the space station ; and store it in XX15 ; Fall through into SP2 to draw XX15 on the compass
Name: SP2 [Show more] Type: Subroutine Category: Dashboard Summary: Draw a dot on the compass, given the planet/station vector
Context: See this subroutine on its own page References: This subroutine is called as follows: * COMPAS calls SP2

Draw a dot on the compass to represent the planet or station, whose normalised vector is in XX15. XX15 to XX15+2 The normalised vector to the planet or space station, stored as x in XX15, y in XX15+1 and z in XX15+2
.SP2 LDA XX15 ; Set A to the x-coordinate of the planet or station to ; show on the compass, which will be in the range -96 to ; +96 as the vector has been normalised JSR SPS2 ; Set X = A / 16, so X will be from -6 to +6, which ; is the x-offset from the centre of the compass of the ; dot we want to draw. Returns with the C flag clear TXA ; Set the x-coordinate of sprite 13 (the compass dot) to CLC ; 220 + X, as 220 is the pixel x-coordinate of the ADC #220 ; centre of the compass, and X is in the range -6 to +6, STA xSprite13 ; so the dot is in the x-coordinate range 214 to 226 LDA XX15+1 ; Set A to the y-coordinate of the planet or station to ; show on the compass, which will be in the range -96 to ; +96 as the vector has been normalised JSR SPS2 ; Set X = A / 16, so X will be from -6 to +6, which ; is the x-offset from the centre of the compass of the ; dot we want to draw. Returns with the C flag clear ; We now set the y-coordinate of sprite 13 (the compass ; dot) to 186, as 186 is the pixel y-coordinate of the ; centre of the compass, and X is in the range -6 to +6, ; so the dot is in the y-coordinate range 180 to 192 STX T ; Set T = X for use in the calculation below LDA #186+YPAL ; Set A to the pixel y-coordinate of the compass centre SEC ; Set the y-coordinate of sprite 13 to A - X SBC T STA ySprite13 LDA #247 ; Set A to 247, which is the tile number that contains a ; full dot in green, for when the planet or station in ; the compass is in front of us LDX XX15+2 ; If the z-coordinate of the XX15 vector is positive, BPL P%+4 ; skip the following instruction LDA #246 ; The z-coordinate of XX15 is negative, so the planet or ; station is behind us and the compass dot should be ; hollow and yellow, so set A to 246, which is the tile ; number for the hollow yellow dot STA pattSprite13 ; Set the pattern number for sprite 13 to A, so we draw ; the compass dot using the correct pattern RTS ; Return from the subroutine
Name: SPS4 [Show more] Type: Subroutine Category: Maths (Geometry) Summary: Calculate the vector to the space station
Context: See this subroutine on its own page References: This subroutine is called as follows: * SP1 calls SPS4

Calculate the vector between our ship and the space station and store it in XX15.
.SPS4 LDX #8 ; First we need to copy the space station's coordinates ; into K3, so set a counter to copy the first 9 bytes ; (the 3-byte x, y and z coordinates) from the station's ; data block at K% + NI% into K3 .SPL1 LDA K%+NIK%,X ; Copy the X-th byte from the station's data block at STA K3,X ; K% + NIK% to the X-th byte of K3 DEX ; Decrement the loop counter BPL SPL1 ; Loop back to SPL1 until we have copied all 9 bytes JMP TAS2 ; Call TAS2 to build XX15 from K3, returning from the ; subroutine using a tail call
Name: OOPS [Show more] Type: Subroutine Category: Flight Summary: Take some damage
Context: See this subroutine on its own page References: This subroutine is called as follows: * Main flight loop (Part 10 of 16) calls OOPS * TACTICS (Part 1 of 7) calls OOPS * TACTICS (Part 6 of 7) calls OOPS

We just took some damage, so reduce the shields if we have any, or reduce the energy levels and potentially take some damage to the cargo if we don't.
Arguments: A The amount of damage to take INF The address of the ship block for the ship that attacked us, or the ship that we just ran into
.OOPS STA T ; Store the amount of damage in T LDX #0 ; Fetch byte #8 (z_sign) for the ship attacking us, and LDY #8 ; set X = 0 LDA (INF),Y BMI OO1 ; If A is negative, then we got hit in the rear, so jump ; to OO1 to process damage to the aft shield LDA FSH ; Otherwise the forward shield was damaged, so fetch the SBC T ; shield strength from FSH and subtract the damage in T BCC OO2 ; If the C flag is clear then this amount of damage was ; too much for the shields, so jump to OO2 to set the ; shield level to 0 and start taking damage directly ; from the energy banks STA FSH ; Store the new value of the forward shield in FSH RTS ; Return from the subroutine .OO2 LDX #0 ; Set the forward shield to 0 STX FSH BCC OO3 ; Jump to OO3 to start taking damage directly from the ; energy banks (this BCC is effectively a JMP as the C ; flag is clear, as we jumped to OO2 with a BCC) .OO1 LDA ASH ; The aft shield was damaged, so fetch the shield SBC T ; strength from ASH and subtract the damage in T BCC OO5 ; If the C flag is clear then this amount of damage was ; too much for the shields, so jump to OO5 to set the ; shield level to 0 and start taking damage directly ; from the energy banks STA ASH ; Store the new value of the aft shield in ASH RTS ; Return from the subroutine .OO5 LDX #0 ; Set the forward shield to 0 STX ASH .OO3 ADC ENERGY ; A is negative and contains the amount by which the STA ENERGY ; damage overwhelmed the shields, so this drains the ; energy banks by that amount (and because the energy ; banks are shown over four indicators rather than one, ; but with the same value range of 0-255, energy will ; appear to drain away four times faster than the ; shields did) BEQ P%+4 ; If we have just run out of energy, skip the next ; instruction to jump straight to our death BCS P%+5 ; If the C flag is set, then subtracting the damage from ; the energy banks didn't underflow, so we had enough ; energy to survive, and we can skip the next ; instruction to make a sound and take some damage JMP DEATH ; Otherwise our energy levels are either 0 or negative, ; and in either case that means we jump to our DEATH, ; returning from the subroutine using a tail call JSR EXNO3 ; We didn't die, so call EXNO3 to make the sound of a ; collision JMP OUCH ; And jump to OUCH to take damage and return from the ; subroutine using a tail call
Name: NWSPS [Show more] Type: Subroutine Category: Universe Summary: Add a new space station to our local bubble of universe
Context: See this subroutine on its own page References: This subroutine is called as follows: * SpawnSpaceStation calls NWSPS * TT110 calls NWSPS
.NWSPS LDX #%10000001 ; Set the AI flag in byte #32 to %10000001 (hostile, STX INWK+32 ; no AI, has an E.C.M.) LDX #0 ; Set pitch counter to 0 (no pitch, roll only) STX INWK+30 STX NEWB ; Set NEWB to %00000000, though this gets overridden by ; the default flags from E% in NWSHP below STX FRIN+1 ; Set the second slot in the FRIN table to 0, so when we ; fall through into NWSHP below, the new station that ; gets created will go into slot FRIN+1, as this will be ; the first empty slot that the routine finds DEX ; Set the roll counter to 255 (maximum anti-clockwise STX INWK+29 ; roll with no damping) LDX #10 ; Call NwS1 to flip the sign of nosev_x_hi (byte #10) JSR NwS1 JSR NwS1 ; And again to flip the sign of nosev_y_hi (byte #12) JSR NwS1 ; And again to flip the sign of nosev_z_hi (byte #14) LDA #SST ; Set A to the space station type, and fall through ; into NWSHP to finish adding the space station to the ; universe JSR NWSHP ; Call NWSHP to add the space station to the universe LDX XX21+2*SST-2 ; Set (Y X) to the address of the Coriolis station's LDY XX21+2*SST-1 ; ship blueprint LDA tek ; If the system's tech level in tek is less than 10, CMP #10 ; jump to notadodo, so tech levels 0 to 9 have Coriolis BCC notadodo ; stations, while 10 and above will have Dodo stations LDX XX21+2*DOD-2 ; Set (Y X) to the address of the Dodo station's ship LDY XX21+2*DOD-1 ; blueprint .notadodo STX spasto ; Store the address of the space station in spasto(1 0) STY spasto+1 ; so we spawn the correct type of station in part 4 of ; the main flight loop JMP UpdateIconBar_b3 ; Update the icon bar so the docking computer icon gets ; displayed to reflect that we are in the station's safe ; zone, returning from the subroutine using a tail call
Name: NWSHP [Show more] Type: Subroutine Category: Universe Summary: Add a new ship to our local bubble of universe
Context: See this subroutine on its own page References: This subroutine is called as follows: * BRIEF calls NWSHP * FRS1 calls NWSHP * GTHG calls NWSHP * KS4 calls NWSHP * Main game loop (Part 1 of 6) calls NWSHP * Main game loop (Part 2 of 6) calls NWSHP * Main game loop (Part 3 of 6) calls NWSHP * Main game loop (Part 4 of 6) calls NWSHP * NWSPS calls NWSHP * PlayDemo calls NWSHP * SFS1 calls NWSHP * SOLAR calls NWSHP * SOS1 calls NWSHP * TITLE calls NWSHP

This creates a new block of ship data in the K% workspace, adds the new ship's type into the first empty slot in FRIN, and adds a pointer to the ship data into UNIV. If there isn't enough free memory for the new ship, it isn't added.
Arguments: A The type of the ship to add (see variable XX21 for a list of ship types)
Returns: C flag Set if the ship was successfully added, clear if it wasn't (as there wasn't enough free memory) INF Points to the new ship's data block in K%
.NW2 STA FRIN,X ; Store the ship type in the X-th byte of FRIN, so the ; this slot is now shown as occupied in the index table TAX ; Copy the ship type into X LDA #0 ; Zero the ship's number on the scanner so that it STA INWK+33 ; doesn't appear on the scanner JMP NW8 ; Jump down to NW8 to continue setting up the new ship .NWSHP STA T ; Store the ship type in location T SETUP_PPU_FOR_ICON_BAR ; If the PPU has started drawing the icon bar, configure ; the PPU to use nametable 0 and pattern table 0 LDX #0 ; Before we can add a new ship, we need to check ; whether we have an empty slot we can put it in. To do ; this, we need to loop through all the slots to look ; for an empty one, so set a counter in X that starts ; from the first slot at 0. When ships are killed, then ; the slots are shuffled down by the KILLSHP routine, so ; the first empty slot will always come after the last ; filled slot .NWL1 LDA FRIN,X ; Load the ship type for the X-th slot BEQ NW1 ; If it is zero, then this slot is empty and we can use ; it for our new ship, so jump down to NW1 INX ; Otherwise increment X to point to the next slot CPX #NOSH ; If we haven't reached the last slot yet, loop back up BCC NWL1 ; to NWL1 to check the next slot (note that this means ; only slots from 0 to #NOSH - 1 are populated by this ; routine, but there is one more slot reserved in FRIN, ; which is used to identify the end of the slot list ; when shuffling the slots down in the KILLSHP routine) .NW3 CLC ; Otherwise we don't have an empty slot, so we can't RTS ; add a new ship, so clear the C flag to indicate that ; we have not managed to create the new ship, and return ; from the subroutine .NW1 ; If we get here, then we have found an empty slot at ; index X, so we can go ahead and create our new ship. ; We do that by creating a ship data block at INWK and, ; when we are done, copying the block from INWK into ; the K% workspace (specifically, to INF) JSR GINF ; Get the address of the data block for ship slot X ; (which is in workspace K%) and store it in INF LDA T ; If the type of ship that we want to create is BMI NW2 ; negative, then this indicates a planet or sun, so ; jump down to NW2, as the next section sets up a ship ; data block, which doesn't apply to planets and suns, ; as they don't have things like shields, missiles, ; vertices and edges ; This is a ship, so first we need to set up various ; pointers to the ship blueprint we will need. The ; blueprints for each ship type in Elite are stored ; in a table at location XX21, so refer to the comments ; on that variable for more details on the data we're ; about to access ASL A ; Set Y = ship type * 2 TAY LDA XX21-1,Y ; The ship blueprints at XX21 start with a lookup ; table that points to the individual ship blueprints, ; so this fetches the high byte of this particular ship ; type's blueprint BEQ NW3 ; If the high byte is 0 then this is not a valid ship ; type, so jump to NW3 to clear the C flag and return ; from the subroutine STA XX0+1 ; This is a valid ship type, so store the high byte in ; XX0+1 LDA XX21-2,Y ; Fetch the low byte of this particular ship type's STA XX0 ; blueprint and store it in XX0, so XX0(1 0) now ; contains the address of this ship's blueprint STX SC2 ; Store the new ship's slot number in SC2 to we can ; retrieve it below LDX T ; Set X to the ship type that we stored in T above LDA #0 ; Zero the ship's number on the scanner so that it STA INWK+33 ; doesn't appear on the scanner for now LDA scacol,X ; Set A to the scanner colour for this ship type from ; the X-th entry in the scacol table (the colour is ; actually a sprite palette number) BMI nwsh3 ; If bit 7 is set of the scanner colour then this ship ; has a cloaking device and is not visible on the ; scanner, so jump to nwsh3 to skip the following so ; the ship is not configured to appear on the scanner TAX ; Set X to the scanner colour for this ship LDY #8 ; We now work our way through the list of scanner ; numbers to try to find a number to allocate to the ; new ship, starting from 8 and working down towards ; 1, so set a number counter in Y .nwsh1 LDA scannerNumber,Y ; If the Y-th entry in scannerNumber is zero then this BEQ nwsh2 ; number is available, so jump to nwsh2 to allocate it ; to our new ship DEY ; Otherwise decrement the index in Y to point to the ; next number down BNE nwsh1 ; Loop back to check the next entry in the table until ; we have found a free number, or we have checked all ; numbers from 8 to 1 BEQ nwsh3 ; We didn't find an available number for the new ship, ; so jump to nwsh3 to skip the following as there isn't ; room for another ship on the scanner .nwsh2 LDA #$FF ; Set the scannerNumber entry for this ship to $FF to STA scannerNumber,Y ; indicate that this scanner number is now being used ; for our new ship STY INWK+33 ; Set the ship's byte #33 to the scanner number for the ; new ship TYA ; Set Y = (A * 2 + A) * 4 ASL A ; = A * 3 * 4 ADC INWK+33 ; ASL A ; This gives us the offset of the first scanner sprite ASL A ; for this ship within the sprite buffer, as each TAY ; ship has three sprites allocated to it, and there are ; four bytes per sprite in the buffer ; ; The offset is from the first scanner sprite in the ; sprite buffer, so this is the offset within the block ; of scanner sprites in the buffer ; ; That said, this value is not used here, as Y gets ; overwritten below before this value is used TXA ; Set A to the scanner colour for this ship, which we ; put in X above LDX INWK+33 ; Set X to the scanner number for the new ship STA scannerColour,X ; Set the X-th entry in the scannerColour table to the ; colour of this ship on the scanner .nwsh3 LDX SC2 ; Set X to the new ship's slot number that we stored in ; SC2 above .NW6 LDY #14 ; Fetch ship blueprint byte #14, which contains the JSR GetShipBlueprint ; ship's energy, and store it in byte #35 STA INWK+35 LDY #19 ; Fetch ship blueprint byte #19, which contains the JSR GetShipBlueprint ; number of missiles and laser power, and AND with %111 AND #%00000111 ; to extract the number of missiles before storing in STA INWK+31 ; byte #31 LDA T ; Restore the ship type we stored above STA FRIN,X ; Store the ship type in the X-th byte of FRIN, so the ; this slot is now shown as occupied in the index table TAX ; Copy the ship type into X BMI NW8 ; If the ship type is negative (planet or sun), then ; jump to NW8 to skip the following instructions CPX #HER ; If the ship type is a rock hermit, jump to gangbang BEQ gangbang ; to increase the junk count CPX #JL ; If JL <= X < JH, i.e. the type of ship we killed in X BCC NW7 ; is junk (escape pod, alloy plate, cargo canister, CPX #JH ; asteroid, splinter, Shuttle or Transporter), then keep BCS NW7 ; going, otherwise jump to NW7 .gangbang INC JUNK ; We're adding junk, so increase the junk counter .NW7 INC MANY,X ; Increment the total number of ships of type X LDY T ; Restore the ship type we stored above JSR GetDefaultNEWB ; Fetch the E% byte for this ship to get the default ; settings for the ship's NEWB flags AND #%01101111 ; Zero bits 4 and 7 (so the new ship is not docking, has ; not been scooped, and has not just docked) ORA NEWB ; Apply the result to the ship's NEWB flags, which sets STA NEWB ; bits 0-3 and 5-6 in NEWB if they are set in the E% ; byte AND #%00000100 ; If bit 2 of the ship's NEWB flags is clear then the BEQ NW8 ; ship is not hostile, so jump to NW8 to skip the ; following LDA allowInSystemJump ; We are spawning a hostile ship, so set bit 7 of ORA #%10000000 ; allowInSystemJump to prevent us from being able to STA allowInSystemJump ; perform an in-system jump .NW8 SETUP_PPU_FOR_ICON_BAR ; If the PPU has started drawing the icon bar, configure ; the PPU to use nametable 0 and pattern table 0 LDY #NI%-1 ; The final step is to copy the new ship's data block ; from INWK to INF, so set up a counter for NI% bytes ; in Y .NWL3 LDA INWK,Y ; Load the Y-th byte of INWK and store in the Y-th byte STA (INF),Y ; of the workspace pointed to by INF DEY ; Decrement the loop counter BPL NWL3 ; Loop back for the next byte until we have copied them ; all over SETUP_PPU_FOR_ICON_BAR ; If the PPU has started drawing the icon bar, configure ; the PPU to use nametable 0 and pattern table 0 SEC ; We have successfully created our new ship, so set the ; C flag to indicate success RTS ; Return from the subroutine
Name: NwS1 [Show more] Type: Subroutine Category: Universe Summary: Flip the sign and double an INWK byte
Context: See this subroutine on its own page References: This subroutine is called as follows: * NWSPS calls NwS1

Flip the sign of the INWK byte at offset X, and increment X by 2. This is used by the space station creation routine at NWSPS.
Arguments: X The offset of the INWK byte to be flipped
Returns: X X is incremented by 2
.NwS1 LDA INWK,X ; Load the X-th byte of INWK into A and flip bit 7, EOR #%10000000 ; storing the result back in the X-th byte of INWK STA INWK,X INX ; Add 2 to X INX RTS ; Return from the subroutine
Name: KS1 [Show more] Type: Subroutine Category: Universe Summary: Remove the current ship from our local bubble of universe
Context: See this subroutine on its own page References: This subroutine is called as follows: * Main flight loop (Part 12 of 16) calls KS1 * KS2 calls via KS3

Part 12 of the main flight loop calls this routine to remove the ship that is currently being analysed by the flight loop. Once the ship is removed, it jumps back to MAL1 to rejoin the main flight loop, with X pointing to the same slot that we just cleared (and which now contains the next ship in the local bubble of universe).
Arguments: XX0 The address of the blueprint for this ship INF The address of the data block for this ship
Other entry points: KS3 Contains an RTS
.KS3 RTS ; Return from the subroutine .KS1 LDX XSAV ; Store the current ship's slot number in XSAV JSR KILLSHP ; Call KILLSHP to remove the ship in slot X from our ; local bubble of universe LDX XSAV ; Restore the current ship's slot number from XSAV, ; which now points to the next ship in the bubble RTS ; Return from the subroutine
Name: KS4 [Show more] Type: Subroutine Category: Universe Summary: Remove the space station and replace it with the sun
Context: See this subroutine on its own page References: This subroutine is called as follows: * KILLSHP calls KS4
.KS4 JSR ZINF ; Call ZINF to reset the INWK ship workspace LDA #0 ; Set A = 0 so we can zero the following flags STA FRIN+1 ; Set the second slot in the FRIN table to 0, which ; sets this slot to empty, so when we call NWSHP below ; the new sun that gets created will go into FRIN+1 STA SSPR ; Set the "space station present" flag to 0, as we are ; no longer in the space station's safe zone LDA #6 ; Set the sun's y_sign to 6 STA INWK+5 LDA #129 ; Set A = 129, the ship type for the sun JSR NWSHP ; Call NWSHP to set up the sun's data block and add it ; to FRIN, where it will get put in the second slot as ; we just cleared out the second slot, and the first ; slot is already taken by the planet JMP UpdateIconBar_b3 ; Update the icon bar so the docking computer icon gets ; removed to reflect that we are no longer in the safe ; zone, returning from the subroutine using a tail call
Name: KS2 [Show more] Type: Subroutine Category: Universe Summary: Check the local bubble for missiles with target lock
Context: See this subroutine on its own page References: This subroutine is called as follows: * KILLSHP calls KS2

Check the local bubble of universe to see if there are any missiles with target lock in the vicinity. If there are, then check their targets; if we just removed their target in the KILLSHP routine, then switch off their AI so they just drift in space, otherwise update their targets to reflect the newly shuffled slot numbers. This is called from KILLSHP once the slots have been shuffled down, following the removal of a ship.
Arguments: XX4 The slot number of the ship we removed just before calling this routine
.KS2 LDX #$FF ; We want to go through the ships in our local bubble ; and pick out all the missiles, so set X to $FF to ; use as a counter .KSL4 SETUP_PPU_FOR_ICON_BAR ; If the PPU has started drawing the icon bar, configure ; the PPU to use nametable 0 and pattern table 0 INX ; Increment the counter (so it starts at 0 on the first ; iteration) LDA FRIN,X ; If slot X is empty then we have worked our way through BEQ KS3 ; all the slots, so jump to KS3 to stop looking CMP #MSL ; If the slot does not contain a missile, loop back to BNE KSL4 ; KSL4 to check the next slot ; We have found a slot containing a missile, so now we ; want to check whether it has target lock TXA ; Set Y = X * 2 and fetch the Y-th address from UNIV ASL A ; and store it in SC and SC+1 - in other words, set TAY ; SC(1 0) to point to the missile's ship data block LDA UNIV,Y STA SC LDA UNIV+1,Y STA SC+1 LDY #32 ; Fetch byte #32 from the missile's ship data (AI) LDA (SC),Y BPL KSL4 ; If bit 7 of byte #32 is clear, then the missile is ; dumb and has no AI, so loop back to KSL4 to move on ; to the next slot AND #%01111111 ; Otherwise this missile has AI, so clear bit 7 and LSR A ; shift right to set the C flag to the missile's "is ; locked" flag, and A to the target's slot number CMP XX4 ; If this missile's target is less than XX4, then the BCC KSL4 ; target's slot isn't being shuffled down, so jump to ; KSL4 to move on to the next slot BEQ KS6 ; If this missile was locked onto the ship that we just ; removed in KILLSHP, jump to KS6 to stop the missile ; from continuing to hunt it down SBC #1 ; Otherwise this missile is locked and has AI enabled, ; and its target will have moved down a slot, so ; subtract 1 from the target number (we know C is set ; from the BCC above) ASL A ; Shift the target number left by 1, so it's in bits ; 1-6 once again, and also set bit 0 to 1, as the C ; flag is still set, so this makes sure the missile is ; still set to being locked ORA #%10000000 ; Set bit 7, so the missile's AI is enabled STA (SC),Y ; Update the missile's AI flag to the value in A BNE KSL4 ; Loop back to KSL4 to move on to the next slot (this ; BNE is effectively a JMP as A will never be zero) .KS6 LDA #0 ; The missile's target lock just got removed, so set the STA (SC),Y ; AI flag to 0 to make it dumb and not locked BEQ KSL4 ; Loop back to KSL4 to move on to the next slot (this ; BEQ is effectively a JMP as A is always zero)
Name: RemoveShip [Show more] Type: Subroutine Category: Universe Summary: Fetch a ship data block and remove that ship from our local bubble of universe
Context: See this subroutine on its own page References: This subroutine is called as follows: * InSystemJump calls RemoveShip

Arguments: X The slot number of the ship to remove INF The address of the data block for the ship to remove
.RemoveShip JSR SetupPPUForIconBar ; If the PPU has started drawing the icon bar, configure ; the PPU to use nametable 0 and pattern table 0 LDY #NI%-1 ; There are NI% bytes in each ship data block (and in ; the INWK workspace, so we set a counter in Y so we can ; loop through them .cink1 LDA (INF),Y ; Load the Y-th byte of INF and store it in the Y-th STA INWK,Y ; byte of INWK DEY ; Decrement the loop counter BPL cink1 ; Loop back for the next byte until we have copied the ; last byte from INF to INWK ; Fall through into KILLSHP to remove the ship from our ; local bubble of universe
Name: KILLSHP [Show more] Type: Subroutine Category: Universe Summary: Remove a ship from our local bubble of universe
Context: See this subroutine on its own page References: This subroutine is called as follows: * KS1 calls KILLSHP

Remove the ship in slot X from our local bubble of universe. This happens when we kill a ship, collide with a ship and destroy it, or when a ship moves outside our local bubble. We also use this routine when we move out of range of the space station, in which case we replace it with the sun. When removing a ship, this creates a gap in the ship slots at FRIN, so we shuffle all the later slots down to close the gap. We also shuffle the ship data blocks at K% to reclaim all the memory that the removed ship used to occupy.
Arguments: X The slot number of the ship to remove XX0 The address of the blueprint for the ship to remove INF The address of the data block for the ship to remove
.KILLSHP STX XX4 ; Store the slot number of the ship to remove in XX4 JSR HideFromScanner_b1 ; Hide the ship from the scanner LDX XX4 ; Set X to the slot number of the ship to remove LDA MSTG ; Check whether this slot matches the slot number in CMP XX4 ; MSTG, which is the target of our missile lock BNE KS5 ; If our missile is not locked on this ship, jump to KS5 LDY #108 ; Otherwise we need to remove our missile lock, so call JSR ABORT ; ABORT to disarm the missile and update the missile ; indicators on the dashboard to the pattern number in ; Y (black indicator = pattern 108) LDA #200 ; Print recursive token 40 ("TARGET LOST") as an JSR MESS ; in-flight message .KS5 LDY XX4 ; Restore the slot number of the ship to remove into Y LDX FRIN,Y ; Fetch the contents of the slot, which contains the ; ship type CPX #SST ; If this is the space station, then jump to KS4 to BNE kill1 ; replace the space station with the sun JMP KS4 .kill1 CPX #CON ; Did we just kill the Constrictor from mission 1? If BNE lll ; not, jump to lll LDA TP ; We just killed the Constrictor from mission 1, so set ORA #%00000010 ; bit 1 of TP to indicate that we have successfully STA TP ; completed mission 1 INC TALLY+1 ; Award 256 kill points for killing the Constrictor .lll CPX #HER ; Did we just kill a rock hermit? If we did, jump to BEQ blacksuspenders ; blacksuspenders to decrease the junk count CPX #JL ; If JL <= X < JH, i.e. the type of ship we killed in X BCC KS7 ; is junk (escape pod, alloy plate, cargo canister, CPX #JH ; asteroid, splinter, Shuttle or Transporter), then keep BCS KS7 ; going, otherwise jump to KS7 .blacksuspenders DEC JUNK ; We just killed junk, so decrease the junk counter .KS7 DEC MANY,X ; Decrease the number of this type of ship in our little ; bubble, which is stored in MANY+X (where X is the ship ; type) LDX XX4 ; Restore the slot number of the ship to remove into X .KSL1 SETUP_PPU_FOR_ICON_BAR ; If the PPU has started drawing the icon bar, configure ; the PPU to use nametable 0 and pattern table 0 INX ; On entry, X points to the empty slot we want to ; shuffle the next ship into (the destination), so ; this increment points X to the next slot - i.e. the ; source slot we want to shuffle down LDA FRIN,X ; Copy the contents of the source slot into the STA FRIN-1,X ; destination slot BNE P%+5 ; If the slot we just shuffled down is not empty, then ; skip the following instruction JMP KS2 ; The source slot is empty and we are done shuffling, ; so jump to KS2 to move on to processing missiles TXA ; Set Y = X * 2 so it can act as an index into the ASL A ; two-byte lookup table at UNIV, which contains the TAY ; addresses of the ship data blocks. In this case we are ; multiplying X by 2, and X contains the source ship's ; slot number so Y is now an index for the source ship's ; entry in UNIV LDA UNIV,Y ; Set SC(1 0) to the address of the data block for the STA SC ; source ship LDA UNIV+1,Y STA SC+1 SETUP_PPU_FOR_ICON_BAR ; If the PPU has started drawing the icon bar, configure ; the PPU to use nametable 0 and pattern table 0 ; We have now set up our variables as follows: ; ; SC(1 0) points to the source's ship data block ; ; INF(1 0) points to the destination's ship data block ; ; P(1 0) points to the destination's line heap ; ; so let's start copying data from the source to the ; destination LDY #41 ; We are going to be using Y as a counter for the 42 ; bytes of ship data we want to copy from the source ; to the destination, so we set it to 41 to start things ; off, and will decrement Y for each byte we copy .KSL2 LDA (SC),Y ; Copy the Y-th byte of the source to the Y-th byte of STA (INF),Y ; the destination DEY ; Decrement the counter BPL KSL2 ; Loop back to KSL2 to copy the next byte until we have ; copied the whole block ; We have now shuffled the ship's slot and the ship's ; data block, so we only have the heap data itself to do LDA SC ; First, we copy SC into INF, so when we loop round STA INF ; again, INF will correctly point to the destination for LDA SC+1 ; the next iteration STA INF+1 SETUP_PPU_FOR_ICON_BAR ; If the PPU has started drawing the icon bar, configure ; the PPU to use nametable 0 and pattern table 0 JMP KSL1 ; We have now shuffled everything down one slot, so ; jump back up to KSL1 to see if there is another slot ; that needs shuffling down
Name: ABORT [Show more] Type: Subroutine Category: Dashboard Summary: Disarm missiles and update the dashboard indicators
Context: See this subroutine on its own page References: This subroutine is called as follows: * FRMIS calls ABORT * KILLSHP calls ABORT * Main flight loop (Part 3 of 16) calls ABORT

Arguments: Y The new status of the leftmost missile indicator
.ABORT LDX #0 ; Set MSAR = 0 to indicate that the leftmost missile STX MSAR ; is no longer seeking a target lock DEX ; Set X to $FF, which is the value of MSTG when we have ; no target lock for our missile ; Fall through into ABORT2 to set the missile lock to ; the value in X, which effectively disarms the missile
Name: ABORT2 [Show more] Type: Subroutine Category: Dashboard Summary: Set/unset the lock target for a missile and update the dashboard
Context: See this subroutine on its own page References: This subroutine is called as follows: * Main flight loop (Part 11 of 16) calls ABORT2

Set the lock target for the active missile and update the dashboard.
Arguments: X The slot number of the ship to lock our missile onto, or $FF to remove missile lock Y The pattern number for the new missile indicator: * 133 = no missile indicator * 109 = red (armed and locked) * 108 = black (disarmed) The armed missile flashes black and red, so the tile is swapped between 108 and 109 in the main loop
.ABORT2 STX MSTG ; Store the target of our missile lock in MSTG SETUP_PPU_FOR_ICON_BAR ; If the PPU has started drawing the icon bar, configure ; the PPU to use nametable 0 and pattern table 0 LDX NOMSL ; Call MSBAR to update the active indicator in the JSR MSBAR ; dashboard's missile bar, which returns with Y = 0 JMP UpdateIconBar_b3 ; Update the icon bar so the missile button shows the ; correct available option for the active missile, ; returning from the subroutine using a tail call .msbpars EQUB 4, 0, 0, 0, 0 ; These bytes appear to be unused (they are left over ; from the 6502 Second Processor version of Elite)
Name: YESNO [Show more] Type: Subroutine Category: Controllers Summary: Display "YES" or "NO" and wait until one is chosen
Context: See this subroutine on its own page References: This subroutine is called as follows: * TBRIEF calls YESNO

This routine does a similar job to the routine of the same name in the BBC Master version of Elite, but the code is significantly different.
Returns: A The result: * 1 if "YES" was chosen * 2 if "NO" was chosen
.YESNO LDA fontStyle ; Store the current font style on the stack, so we can PHA ; restore it when we return from the subroutine LDA #2 ; Set the font style to print in the highlight font STA fontStyle LDA #1 ; Push a value of 1 onto the stack, so the following PHA ; prints extended token 1 ("YES") .yeno1 JSR CLYNS ; Clear the bottom two text rows of the upper screen, ; and move the text cursor to column 1 on row 21, i.e. ; the start of the top row of the two bottom rows LDA #15 ; Move the text cursor to column 15 STA XC PLA ; Print the extended token whose number is on the stack, PHA ; so this will be "YES" (token 1) or "NO" (token 2) JSR DETOK_b2 JSR DrawMessageInNMI ; Configure the NMI to display the YES/NO message that ; we just printed LDA controller1A ; If the A button is being pressed on the controller, BMI yeno3 ; jump to yeno3 to record the choice LDA controller1Up ; If neither the up nor down arrow is being pressed on ORA controller1Down ; the controller, jump to yeno2 to pause and loop back BPL yeno2 ; to keep waiting for a choice to be made ; If we get here then either the up or down arrow is ; being pressed, so we toggle the on-screen choice ; between "YES" and "NO" PLA ; Flip the value on the top of the stack between 1 and 2 EOR #3 ; by EOR'ing with 3, which toggles the token between PHA ; "YES" and "NO" .yeno2 LDY #8 ; Wait until eight NMI interrupts have passed (i.e. the JSR DELAY ; next eight VBlanks) JMP yeno1 ; Loop back to print "YES" or NO" and wait for a choice .yeno3 LDA #0 ; Reset the key logger entry for the icon bar button STA iconBarKeyPress ; choice to clear any icon bar choices that might have ; been processed in the background (via the pause menu, ; for example) STA controller1A ; Reset the key logger for the A button as we have ; consumed the button press PLA ; Set X to the value from the top of the stack, which TAX ; will be 1 for "YES" or 2 for "NO", giving us our ; result to return PLA ; Restore the font style that we stored on the stack STA fontStyle ; so it's unchanged by the routine TXA ; Copy X to A, so we return the result in both A and X RTS ; Return from the subroutine
Name: TT17 [Show more] Type: Subroutine Category: Controllers Summary: Scan the key logger for the directional pad buttons
Context: See this subroutine on its own page References: This subroutine is called as follows: * Main game loop (Part 5 of 6) calls TT17

X and Y are integers between -1 and +1 depending on which buttons are pressed. This routine does a similar job to the routine of the same name in the BBC Master version of Elite, but the code is significantly different.
Returns: A The button number, icon bar button was chosen X Change in the x-coordinate according to the directional keys being pressed on controller 1 Y Change in the y-coordinate according to the directional keys being pressed on controller 1
.TT17 LDA QQ11 ; If this is not the space view, jump to dpad1 to read BNE dpad1 ; the directional pad on controller 1 JSR DOKEY ; This is the space view, so populate the key logger ; and apply the docking computer manoeuvring code TXA ; Transfer the value of the key pressed from X to A RTS ; Return from the subroutine .dpad1 JSR DOKEY ; Populate the key logger and apply the docking computer ; manoeuvring code LDX #0 ; Set the initial values for the results, X = Y = 0, LDY #0 ; which we now increase or decrease appropriately LDA controller1B ; If the B button is being pressed on controller 1, BMI dpad5 ; jump to dpad5 to return from the subroutine, as the ; arrow buttons act differently when B is also pressed LDA controller1Left03 ; If the left button on controller 1 was not being held BPL dpad2 ; down four VBlanks ago or for the three VBlanks before ; that, jump to dpad2 to skip the following instruction DEX ; The left button has been held down for some time, so ; decrement the x-delta in X .dpad2 LDA controller1Right03 ; If the right button on controller 1 was not being held BPL dpad3 ; down four VBlanks ago or for the three VBlanks before ; that, jump to dpad3 to skip the following instruction INX ; The right button has been held down for some time, so ; increment the x-delta in X .dpad3 LDA controller1Up ; If the up button on controller 1 is not being pressed, BPL dpad4 ; jump to dpad4 to skip the following instruction INY ; The up button is being pressed, so increment the ; y-delta in Y .dpad4 LDA controller1Down ; If the down button on controller 1 is not being BPL dpad5 ; pressed, jump to dpad5 to skip the following ; instruction DEY ; The down button is being pressed, so decrement the ; y-delta in Y .dpad5 LDA iconBarKeyPress ; Set A to the key logger entry for the icon bar button ; press, to return from the subroutine RTS ; Return from the subroutine
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: * 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: * ShowStartScreen calls RESET * TITLE 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: * BETA to BETA+6, 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 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 ; Reset the ship slots for the local bubble of universe, ; and various flight and ship status variables LDA #%00000000 ; Clear bits 6 and 7 of selectedSystemFlag to indicate STA selectedSystemFlag ; that there is no currently selected system LDX #6 ; Set up a counter for zeroing BETA through BETA+6 .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 and QQ12 STA QQ12 ; to $FF to indicate we are docked 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 LDA #$FF ; Set iconBarType to $FF so no icon bar is shown STA iconBarType ; 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 * DOENTRY calls RES2 * ESCAPE calls RES2 * MJP calls RES2 * PlayDemo 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 SEI ; Disable interrupts from any source except NMI, as we ; don't want any other interrupts to occur LDA #1 ; Set enableBitplanes to 1 so the game starts to use STA enableBitplanes ; two different bitplanes when displaying the screen LDA #1 ; Set the tile number for the left edge of the box to STA boxEdge1 ; tile 1, which is the standard edge for the box LDA #2 ; Set the tile number for the right edge of the box to STA boxEdge2 ; tile 2, which is the standard edge for the box LDA #80 ; Tell the PPU to send nametable entries up to tile STA lastNameTile ; 80 * 8 = 640 (i.e. to the end of tile row 19) in both STA lastNameTile+1 ; bitplanes LDA BOMB ; If the energy bomb has not been set off, jump to rese1 BPL rese1 ; to skip the following JSR HideHiddenColour ; Set the hidden colour to black, to switch off the ; energy bomb effect (as the effect works by showing ; hidden content instead of the visible content) STA BOMB ; The call to HideHiddenColour sets A = 15, which has ; bit 7 clear, so this clears bit 7 of BOMB to disable ; the energy bomb explosion .rese1 LDA #NOST ; Reset NOSTM, the number of stardust particles, to the STA NOSTM ; maximum allowed (20) LDX #$FF ; Reset MSTG, the missile target, to $FF (no target) STX MSTG LDA allowInSystemJump ; Set bit 7 of allowInSystemJump to prevent us from ORA #%10000000 ; being able to perform an in-system jump, as this is STA allowInSystemJump ; the default setting after launching LDA #128 ; Set the current pitch and roll rates to the mid-point, STA JSTX ; 128 STA JSTY STA ALP2 ; Reset ALP2 (roll sign) and BET2 (pitch sign) STA BET2 ; to negative, i.e. pitch and roll negative ASL A ; This sets A to 0 STA demoInProgress ; Set demoInProgress to 0 to reset the demo flag, so if ; we are starting the game after playing the demo, the ; flag will be set correctly STA BETA ; Reset BETA (pitch angle alpha) to 0 STA BET1 ; Reset BET1 (magnitude of the pitch angle) to 0 STA ALP2+1 ; Reset ALP2+1 (flipped roll sign) and BET2+1 (flipped STA BET2+1 ; pitch sign) to positive, i.e. pitch and roll negative STA MCNT ; Reset MCNT (the main loop counter) to 0 STA LAS ; Set LAS to 0, to switch off laser pulsing STA unusedVariable ; Set unusedVariable to 0 (this is never read, so this ; has no effect) STA chargeDockingFee ; Set chargeDockingFee to 0 so the docking fee is marked ; as being not already paid LDA #3 ; Reset DELTA (speed) to 3 STA DELTA STA ALPHA ; Reset ALPHA (roll angle alpha) to 3 STA ALP1 ; Reset ALP1 (magnitude of roll angle alpha) to 3 LDA #72 ; Set the screen height variables for a screen height of JSR SetScreenHeight ; 144 (i.e. 2 * 72) 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 LDA QQ11a ; If bit 7 of the old view in QQ11a is set, then the old BMI rese2 ; view does not have a dashboard, so jump to rese2 to ; skip the following, as there is no scanner to clear JSR HideExplosionBurst ; Hide the four sprites that make up the explosion burst JSR ClearScanner ; Remove all ships from the scanner and hide the scanner ; sprites .rese2 JSR ZERO ; Reset the ship slots for the local bubble of universe, ; and various flight and ship status variables ; 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: * BRIEF calls ZINF * DOKEY calls ZINF * FRS1 calls ZINF * KS4 calls ZINF * Main game loop (Part 2 of 6) calls ZINF * SetupDemoShip calls ZINF * SOLAR calls ZINF * Ze 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 SETUP_PPU_FOR_ICON_BAR ; If the PPU has started drawing the icon bar, configure ; the PPU to use nametable 0 and pattern table 0 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 SETUP_PPU_FOR_ICON_BAR ; If the PPU has started drawing the icon bar, configure ; the PPU to use nametable 0 and pattern table 0 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: SetScreenHeight [Show more] Type: Subroutine Category: Drawing the screen Summary: Set the screen height variables to the specified height
Context: See this subroutine on its own page References: This subroutine is called as follows: * DEATH calls SetScreenHeight * RES2 calls SetScreenHeight * SendSpaceViewToPPU calls SetScreenHeight * TT22 calls SetScreenHeight

Arguments: A The y-coordinate of the centre of the screen (i.e. half the screen height)
.SetScreenHeight STA halfScreenHeight ; Store the half-screen height in halfScreenHeight ASL A ; Double the half-screen height in A to get the full ; screen height, while setting the C flag to bit 7 of ; the original argument ; ; This routine is only ever called with A set to either ; 72 or 77, so the C flag is never set STA screenHeight ; Store the full screen height in screenHeight SBC #0 ; Set the value of Yx2M1 as follows: STA Yx2M1 ; ; * If the C flag is set: Yx2M1 = screenHeight ; ; * If the C flag is clear: Yx2M1 = screenHeight - 1 ; ; This routine is only ever called with A set to either ; 72 or 77, so the C flag is never set, so we always set ; Yx2M1 = screenHeight - 1 RTS ; Return from the subroutine
Name: msblob [Show more] Type: Subroutine Category: Dashboard Summary: Display the dashboard's missile indicators in black or grey
Context: See this subroutine on its own page References: This subroutine is called as follows: * SOS1 calls msblob * TT66 calls msblob

Display the dashboard's missile indicators, with all the missiles reset to black (i.e. not armed or locked), or grey if there is no missile.
.msblob LDX #4 ; Set up a loop counter in X to count through all four ; missile indicators .ss 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 ; black LDY #133 ; Set the pattern for the missile indicator at position JSR MSBAR ; X to 133, which is the same grey as the dashboard, ; so this effectively hides the indicator 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 #108 ; Set the pattern for the missile indicator at position JSR MSBAR ; X to 108, which is a black indicator DEX ; Decrement the counter to point to the next missile BNE SAL8 ; Loop back to SAL8 if we still have missiles to draw 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 AND #15 ; Set the ship speed to our random number, set to a ADC #10 ; minimum of 10 and a maximum of 26 (as the C flag is STA INWK+27 ; also randomly set) 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 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 CMP #HER ; If A is not the ship type of a rock hermit, jump to BNE game1 ; game1 to skip the following instruction LDA #CYL ; This is a rock hermit, so set A = #CYL so we spawn a ; Cobra Mk III .game1 JSR NWSHP ; Add a new ship of type A to the local bubble and fall ; through into the main game loop again JMP MLOOP ; Jump down to MLOOP to do some end-of-loop tidying and ; restart the main loop
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

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
.TT100 LDA nmiTimerLo ; Store the low byte of the NMI timer (which will be STA RAND ; pretty random) in the RAND seed LDA K%+6 ; Store the z_lo coordinate for the planet (which will STA RAND+1 ; be pretty random) in the RAND+1 seed LDA soundVibrato ; Store the soundVibrato variable (which will be pretty STA RAND+3 ; random) in the RAND+3 seed LDA QQ12 ; Fetch the docked flag from QQ12 into A BEQ game2 ; If we are docked, jump down to MLOOP to skip all the JMP MLOOP ; the flight and spawning code in the top part of the ; main loop .game2 JSR M% ; Call M% to iterate through the main flight loop 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 (in which case MJ > 0) or ORA demoInProgress ; demoInProgress > 0 (in which case we are playing the BNE ytq ; demo), jump down to MLOOP (via ytq above) JSR DORND ; Set A and X to random numbers CMP #40 ; If A >= 40 (85% chance), jump down to MTT1 to skip BCS MTT1 ; the spawning of an asteroid or cargo canister and ; potentially spawn something else 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 JSR ZINF ; Call ZINF to reset the INWK ship workspace LDA #38 ; Set z_hi = 38 (far away) STA INWK+7 JSR DORND ; Set A, X and C flag to random numbers STA INWK ; Set x_lo = random STX INWK+3 ; Set y_lo = random ; ; Note that because we use the value of X returned by ; DORND, and X contains the value of A returned by the ; previous call to DORND, this does not set the new ship ; to a totally random location. See the deep dive on ; "Fixing ship positions" for details AND #%10000000 ; Set x_sign = bit 7 of x_lo STA INWK+2 TXA ; Set y_sign = bit 7 of y_lo AND #%10000000 STA INWK+5 ROL INWK+1 ; Set bit 1 of x_hi to the C flag, which is random, so ROL INWK+1 ; this randomly moves us off-centre by 512 (as if x_hi ; is %00000010, then (x_hi x_lo) is 512 + x_lo) JSR DORND ; Set A, X and V flag to random numbers AND #%00110000 ; If either of bits 4 and 5 are set (75% chance), skip BNE P%+5 ; the following instruction JMP MTT4 ; Jump up to MTT4 to spawn a trader (25% chance) 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 #31 ; Set the ship speed to our random number, reduced to ORA #16 ; the range 16 to 31 STA INWK+27 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 #252 ; If random A < 252 (98.8% of the time), jump to thongs BCC thongs ; to skip the following LDA #HER ; Set A to #HER so we spawn a rock hermit 1.2% of the ; time STA INWK+32 ; Set byte #32 to %00001111 to give the rock hermit an ; E.C.M. BNE whips ; Jump to whips (this BNE is effectively a JMP as A will ; never be zero) .thongs 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) .whips JSR NWSHP ; Add our new asteroid or canister to the universe
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 * Very rarely, consider spawning a Thargoid, or vanishingly rarely, a Cougar
.MLOOPS JMP MLOOP ; Jump to MLOOP to skip the following .MTT1 LDA SSPR ; If we are inside the space station's safe zone, jump BNE MLOOPS ; to MLOOP via MLOOPS 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. See the deep dive on ; "Fixing ship positions" for details CMP #136 ; If the random number in A = 136 (0.4% chance), jump BNE P%+5 ; to fothg in part 4 to spawn either a Thargoid or, very JMP fothg ; rarely, a Cougar CMP T ; If the random value in A >= our badness level, which BCS game3 ; 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 NEWB ; We are a fugitive or a bad offender, and we are about ORA #%00000100 ; to spawn a cop, so set bit 2 of the ship's NEWB flags STA NEWB ; to make it hostile LDA #COPS ; Add a new police ship to the local bubble JSR NWSHP .game3 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, a Thargoid, or up to four pirates Deep dive: Program flow of the main game loop Ship data blocks Fixing ship positions The elusive Cougar
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 (35% chance) either a lone bounty hunter (a Cobra Mk III, Asp Mk II, Python or Fer-de-lance), a Thargoid, or a group of up to 4 pirates (a mix of Sidewinders, Mambas, Kraits, Adders, Geckos, Cobras Mk I and III, and Worms) * Also potentially spawn a Constrictor if this is the mission 1 endgame, or Thargoids if mission 2 is in progress
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+15 ; Call GTHG+15 to spawn a lone Thargoid, without a ; Thargon companion and with slightly less aggression ; than normal JMP MLOOP ; Jump down to MLOOP to do some end-of-loop tidying and ; restart the main loop .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 a ; lone bounty hunter LDY JUNK ; Set Y to the number of junk items in our local bubble ; of universe (where junk is asteroids, canisters, ; escape pods and so on) LDX FRIN+2,Y ; The ship slots at FRIN are ordered with the first two ; slots reserved for the planet and sun/space station, ; and then any ships, so if the slot at FRIN+2+Y is not ; empty (i.e. is non-zero), then that means the number ; of non-asteroids in the vicinity is at least 1 BEQ game4 ; So if X = 0, there are no ships in the vicinity, so ; jump to game4 to skip the following and increase the ; chances of spawning CMP #50 ; If the random number in A >= 50 (80% chance), jump to BCS MLOOPS ; MLOOPS to stop spawning (so there's a 25% chance of ; spawning pirates or bounty hunters) .game4 CMP #100 ; If the random number in A >= 100 (61% chance), jump to BCS MLOOPS ; MLOOPS to stop spawning (so there's a 39% 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 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. See the deep dive on ; "Fixing ship positions" for details CMP #100 ; Set the C flag depending on whether the random number ; in A >= 100, for the BCS below AND #15 ; Set A to our random number but in the range 16 to 31 ORA #16 STA INWK+27 ; Give the ship we're about to spawn a speed of between ; 16 and 31 BCS mt1 ; If the random number in A >= 100 (61% chance), jump ; to mt1 to spawn pirates, otherwise keep going to ; spawn a lone bounty hunter or a Thargoid 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 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 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 JSR DORND ; Set A and X to random numbers CMP #200 ; First, set the C flag if X >= 200 (22% chance) ROL A ; Set bit 0 of A to the C flag (i.e. there's a 22% ; 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 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, Thargoid, ; Cougar or Constrictor .mj1 JMP MLOOP ; Jump down to MLOOP, as we are done spawning ships .fothg LDA K%+6 ; Fetch the z_lo coordinate of the first ship in the K% AND #%00111110 ; block (i.e. the planet) and extract bits 1-5 BNE fothg2 ; If any of bits 1-5 are set (96.8% chance), jump up to ; fothg2 to spawn a Thargoid ; If we get here then we're going to spawn a Cougar, a ; very rare event indeed. How rare? Well, all the ; following have to happen in sequence: ; ; * Main loop iteration = 0 (1 in 256 iterations) ; * Skip asteroid spawning (87% chance) ; * Skip cop spawning (0.4% chance) ; * Skip Thargoid spawning (3.2% chance) ; ; so the chances of spawning a Cougar on any single main ; loop iteration are slim, to say the least LDA #18 ; Give the ship we're about to spawn a speed of 27 STA INWK+27 LDA #%01111001 ; Give it an E.C.M., and make it hostile and pretty STA INWK+32 ; aggressive (though don't give it AI) LDA #COU ; Set the ship type to a Cougar and jump up to focoug BNE focoug ; to spawn it .mt1 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 LDA #%00000100 ; Set bit 2 of the NEWB flags and clear all other bits, STA NEWB ; so the ship we are about to spawn is hostile 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 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) JSR NWSHP ; Try adding a new ship of type A to the local bubble 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
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 The Trumbles mission
Context: See this subroutine on its own page References: This subroutine is called as follows: * Main game loop (Part 1 of 6) calls via MLOOP * 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 * PlayDemo 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 LDX LASCT ; Set X to the value of LASCT, the laser pulse count BEQ NOLASCT ; If X = 0 then jump to NOLASCT to skip reducing LASCT, ; as it can't be reduced any further DEX ; Decrement the value of LASCT in X BEQ P%+3 ; If X = 0, skip the next instruction DEX ; Decrement the value of LASCT in X again STX LASCT ; Store the decremented value of X in LASCT, so LASCT ; gets reduced by 2, but not into negative territory .NOLASCT LDA QQ11 ; If this is a space view, skip the following two BEQ P%+7 ; instructions (i.e. jump to JSR TT17 below) LDY #4 ; Wait for 4/50 of a second (0.08 seconds), to slow the JSR DELAY ; main loop down a bit LDA TRIBBLE+1 ; If the high byte of TRIBBLE(1 0), the number of BEQ game5 ; Trumbles in the hold, is zero, jump to game5 to skip ; the following ; We have a lot of Trumbles in the hold, so let's see if ; any of them are breeding (note that Trumbles always ; breed when we jump into a new system in the SOLAR ; routine, but when we have lots of them, they also ; breed here in the main flight loop) JSR DORND ; Set A and X to random numbers CMP #220 ; If A >= 220 then set the C flag (14% chance) LDA TRIBBLE ; Add the C flag to TRIBBLE(1 0), starting with the low ADC #0 ; bytes STA TRIBBLE BCC game5 ; And then the high bytes INC TRIBBLE+1 ; ; So there is a 14% chance of a Trumble being born BPL game5 ; If the high byte of TRIBBLE(1 0) is now $80, then DEC TRIBBLE+1 ; decrement it back to $7F, so the number of Trumbles ; never goes above $7FFF (32767) .game5 LDA TRIBBLE+1 ; If the high byte of TRIBBLE(1 0), the number of BEQ game7 ; Trumbles in the hold, is zero, jump to game7 to skip ; the following ; We have a lot of Trumbles in the hold, so they are ; probably making a bit of a noise LDY CABTMP ; If the cabin temperature is >= 224 then jump to game6 CPY #224 ; to skip the following and leave the value of A as a BCS game6 ; high value, so the chances of the Trumbles making a ; noise in hot temperature is greater (specifically, ; this is the temperature at which the fuel scoop start ; working) LSR A ; Set A = A / 2 LSR A .game6 STA T ; Set T = A, which will be higher with more Trumbles and ; higher temperatures JSR DORND ; Set A and X to random numbers CMP T ; If A >= T then jump to game7 to skip making any noise, BCS game7 ; so there is a higher chance of Trumbles making noise ; when there are lots of them or the cabin temperature ; is hot enough for the fuel scoops to work AND #3 ; Set Y to our random number reduced to the range 0 to 3 TAY LDA trumbleSounds,Y ; Set Y to the Y-th sound effect from the trumbleSounds TAY ; table, so there's a 75% change of Y being set to 5, ; and a 25% chance of Y being set to 6 JSR NOISE ; Call the NOISE routine to make the sound of the ; Trumbles in Y, which will be one of 5 or 6, with 5 ; more likely than 6 .game7 LDA allowInSystemJump ; Set A to the value of allowInSystemJump, which ; determines whether we are allowed to perform an ; in-system jump (which is the same as saying whether ; the fast-forward button is enabled) LDX QQ22+1 ; Fetch into X the number that's shown on-screen during ; the hyperspace countdown BEQ game8 ; If the counter is zero then we are not counting down ; to hyperspace, so jump to game8 to skip the next ; instruction ORA #%10000000 ; Set bit 7 of A to prevent in-system jumps, as there ; is a hyperspace countdown in progress .game8 LDX demoInProgress ; If the demo is not in progress, jump to game9 to skip BEQ game9 ; the following AND #%01111111 ; Clear bit 7 of A to enable the fast-forward button, as ; this is the combat demo and the fast-forward button ; lets us skip the rest of the demo .game9 STA allowInSystemJump ; Store the updated value of A in allowInSystemJump AND #%11000000 ; If bits 6 and 7 of allowInSystemJump are both clear BEQ game10 ; then in-system jumps are allowed, so jump to game10 ; to leave allowInSystemJump alone CMP #%11000000 ; If bits 6 and 7 of allowInSystemJump are both set then BEQ game10 ; in-system jumps are not allowed, so jump to game10 to ; leave allowInSystemJump alone CMP #%10000000 ; If bit 7 of allowInSystemJump is set but bit 6 isn't, ; then this sets the C flag, otherwise it clears the C ; flag ROR A ; This updates allowInSystemJump as follows: STA allowInSystemJump ; ; * %10xxxxxx rotates to %11xxxxxx ; ; * %01xxxxxx rotates to %00xxxxxx ; ; In other words, when bit 7 of the allowInSystemJump ; flag is set, then that condition will spread to both ; bit 6 and 7, but if only bit 6 is set, then the flag ; will clear at this point in the main game loop ; ; So once bit 7 is cleared, in-system jumps will be ; allowed within an iteration of the main loop, assuming ; no more preventative conditions appear JSR UpdateIconBar_b3 ; Update the icon bar to hide or show the in-system jump ; icon bar button, according to the new value of the ; allowInSystemJump flag .game10 JSR TT17 ; Scan the key logger for the directional pad buttons, ; returning the cursor's delta values in X and Y and ; the button pressed in A
Name: Main game loop (Part 6 of 6) [Show more] Type: Subroutine Category: Main loop Summary: Process non-flight key presses (icon bar selections) Deep dive: Program flow of the main game loop
Context: See this subroutine on its own page References: This subroutine is called as follows: * BAY calls 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 icon bar selections 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 the Status Mode screen.
Other entry points: FRCE The entry point for the main game loop if we want to jump straight to a specific screen, by pretending to "press" a key, in which case A contains the internal key number of the key we want to "press"
.FRCE JSR TT102 ; Call TT102 to process the key pressed in A JMP TT100 ; Jump to TT100 to restart the main loop from the start
Name: trumbleSounds [Show more] Type: Variable Category: Sound Summary: The range of sounds that the Trumbles make in the hold Deep dive: Sound effects in NES Elite The Trumbles mission
Context: See this variable on its own page References: This variable is used as follows: * Main game loop (Part 5 of 6) uses trumbleSounds
.trumbleSounds EQUB 5, 5, 5, 6
Name: TT102 [Show more] Type: Subroutine Category: Icon bar Summary: Process icon bar controller choices
Context: See this subroutine on its own page References: This subroutine is called as follows: * Main game loop (Part 6 of 6) calls TT102 * HME2 calls via ReturnFromSearch

This routine does a similar job to the routine of the same name in the BBC Master version of Elite, but the code is significantly different.
Arguments: A The button number of the chosen icon from the icon bar 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: ReturnFromSearch Re-entry point following a system search in HME2
.TT102 CMP #0 ; If no icon was chosen, jump to HME1 to skip all the BNE P%+5 ; icon checks below JMP HME1 CMP #3 ; If the Status Mode icon was chosen, jump to STATUS to BNE P%+5 ; show the Status Mode screen, returning from the JMP STATUS ; subroutine using a tail call CMP #4 ; If the Charts icon was chosen from the docked icon BEQ barb1 ; bar, jump to barb1 to show the correct chart CMP #36 ; If the Switch chart range icon from the Charts icon BNE barb2 ; bar was not chosen, jump to barb2 to keep checking LDA chartToShow ; The Switch chart range icon from the Charts icon bar EOR #%10000000 ; was chosen, so flip bit 7 of chartToShow to toggle STA chartToShow ; the chart between the Long-range and Short-range ; Chart .barb1 LDA chartToShow ; If chartToShow = 0 then jump to TT23 to show the BPL P%+5 ; Short-range Chart, otherwise jump to TT22 to show the JMP TT22 ; Long-range Chart, in either case returning from the JMP TT23 ; subroutine using a tail call .barb2 CMP #35 ; If the Data on System icon was chosen, call the BNE TT92 ; SetSelectedSystem routine to set the selected system JSR SetSelectedSystem ; to the nearest system, if we don't already have a JMP TT25 ; selected system, and then jump to TT25 to show the ; Data on System screen, returning from the subroutine ; using a tail call .TT92 CMP #8 ; If the Inventory icon was chosen, jump to TT213 to BNE P%+5 ; show the Inventory screen, returning from the JMP TT213 ; subroutine using a tail call CMP #2 ; If the Market Price icon was chosen, jump to TT167 to BNE P%+5 ; show the Market Price screen, returning from the JMP TT167 ; subroutine using a tail call CMP #1 ; If the Launch icon was not chosen, jump to fvw to BNE fvw ; skip the following launch code ; The Launch icon was chosen, so we now attempt to ; launch LDX QQ12 ; If QQ12 is zero then we are not docked, so jump to fvw BEQ fvw ; as we can't launch from the station if we are already ; in space JSR SelectNearbySystem ; Set the current system to the nearest system to ; (QQ9, QQ10), which will be the system we are currently ; docked at, and update the selected system flags ; accordingly JMP TT110 ; Jump to TT110 to launch our ship, returning from the ; subroutine using a tail call .fvw CMP #17 ; If the Docking Computer icon was not chosen, jump to BNE barb8 ; barb8 to move on to the next icon ; If we get here then the Docking Computer icon was ; chosen LDX QQ12 ; If QQ12 is non-zero then we are docked, so jump to BNE barb8 ; barb8 to move on to the next icon as we can't engage ; the docking computer if we aren't in space LDA auto ; If the docking computer is already activated, jump BNE barb5 ; to barb5 to skip the docking fee calculations and ; disable the docking computer (so the icon bar button ; toggles it on and off) LDA SSPR ; If we are not inside the space station safe zone, jump BEQ barb8 ; to barb8 to move on to the next icon as we can't ; engage the docking computer if we aren't in the safe ; zone ; We now deduct a docking fee of 5.0 credits for using ; the docking computer LDA DKCMP ; If we have a docking computer fitted (DKCMP is ORA chargeDockingFee ; non-zero) or we have already been charged a docking BNE barb4 ; fee (chargeDockingFee is non-zero), then jump to ; barb4 to engage the docking computer without charging ; a docking fee ; Otherwise we do not have a docking computer fitted ; or we have not yet been charged a docking fee, so ; now we charge the docking fee LDY #0 ; Set (Y X) = 50, so the docking fee is 5.0 credits LDX #50 JSR LCASH ; Subtract (Y X) cash from the cash pot, but only if ; we have enough cash BCS barb3 ; If the C flag is set then we did have enough cash for ; the transaction, so jump to barb3 to skip the ; following instruction ; If we get here then we don't have enough cash for the ; docking fee, so make a beep and return from the ; subroutine without engaging the docking computer JMP BOOP ; Call the BOOP routine to make a long, low beep, and ; return from the subroutine using a tail call .barb3 DEC chargeDockingFee ; Set chargeDockingFee to $FF so we don't charge another ; docking fee LDA #0 ; Print control code 0 (current amount of cash and JSR MESS ; newline) as an in-flight message, to show our balance ; after the docking fee has been paid .barb4 LDA #1 ; Set A = 1 to pass to the ChooseMusic routine to play ; the docking music (The Blue Danube) JSR WaitForNMI ; Wait until the next NMI interrupt has passed (i.e. the ; next VBlank) JSR ChooseMusic_b6 ; Select and play the docking music (tune 1, "The Blue ; Danube") LDA #$FF ; Set A = $FF to set as the value of auto below, so the ; docking computer is flagged as being enabled BNE barb6 ; Jump to barb6 to store A in auto (this BNE is ; effectively a JMP as A is never zero) .barb5 ; If we get here then we need to turn off the docking ; computer JSR ResetMusicAfterNMI ; Wait for the next NMI before resetting the current ; tune to 0 (no tune) and stopping the docking music LDA #0 ; Set A = 0 to set as the value of auto below, so the ; docking computer is flagged as being disabled .barb6 STA auto ; Set auto to the value in A, to disable or enable the ; docking computer as required LDA QQ11 ; If this is the space view, jump to barb7 to return BEQ barb7 ; from the subroutine JSR CLYNS ; Clear the bottom two text rows of the upper screen, ; and move the text cursor to column 1 on row 21, i.e. ; the start of the top row of the two bottom rows JSR DrawScreenInNMI ; Configure the NMI handler to draw the screen, so the ; screen gets updated .barb7 RTS ; Return from the subroutine .barb8 JSR CheckForPause ; If the Start button has been pressed then process the ; pause menu and set the C flag, otherwise clear it CMP #21 ; If the "Front space view" icon was not chosen, jump to BNE barb11 ; barb11 to move on to the next icon ; If we get here then the "Front space view" icon was ; chosen LDA QQ12 ; If QQ12 is zero then we are not docked and in space, BPL barb9 ; so jump to barb9 to process the "Front space view" ; icon RTS ; Otherwise the icon does nothing, so return from the ; subroutine .barb9 ; If we get here then the "Front space view" icon was ; chosen and we are in space LDA #0 ; Set A = 0 to use as the view number if we jump to ; barb10 to show the front space view (i.e. view 0) LDX QQ11 ; If this is not the space view, jump to barb10 to show BNE barb10 ; the front space view LDA VIEW ; Otherwise add 1 to the view number in VIEW and wrap it CLC ; round using mod 4, so VIEW goes from 0 to 3 and back ADC #1 ; to 0 again (i.e. front, rear, left, right and back to AND #3 ; front again) .barb10 TAX ; Set X to the view number to show JMP LOOK1 ; Jump to LOOK1 to switch to view X (front, rear, left ; or right), returning from the subroutine using a tail ; call .barb11 BIT QQ12 ; If bit 7 of QQ12 is clear (i.e. we are not docked, but BPL LABEL_3 ; in space), jump to LABEL_3 to skip the following ; checks for the save commander file key press CMP #5 ; If the Equip Ship icon was chosen, jump to TT219 to BNE P%+5 ; show the Equip Ship screen, returning from the JMP EQSHP ; subroutine using a tail call CMP #6 ; If the Save and Load icon was chosen, jump to SVE to BNE LABEL_3 ; show the Save and Load screen, returning from the JMP SVE_b6 ; subroutine using a tail call .LABEL_3 CMP #22 ; If the Hyperspace icon was chosen, jump to hyp to do BNE P%+5 ; a hyperspace jump (if we are in space), returning from JMP hyp ; the subroutine using a tail call CMP #41 ; If the Galactic Hyperspace icon was chosen, jump to BNE P%+5 ; GalacticHyperdrive to do a galactic hyperspace jump, JMP GalacticHyperdrive ; returning from the subroutine using a tail call CMP #39 ; If the "Search for system" icon was not chosen, jump BNE HME1 ; to HME1 to move on to the next icon LDA QQ22+1 ; Fetch QQ22+1, which contains the number that's shown ; on-screen during hyperspace countdown BNE t95 ; If it is non-zero, return from the subroutine (as t95 ; contains an RTS), as there is a countdown in progress LDA QQ11 ; If the view in QQ11 is not %0000110x (i.e. 12 or 13, AND #%00001110 ; which are the Short-range Chart and Long-range Chart), CMP #%00001100 ; jump to t95 to return from the subroutine (as t95 BNE t95 ; contains an RTS) JMP HME2 ; Jump to HME2 to let us search for a system, returning ; from the subroutine using a tail call .HME1 STA T1 ; Store A (the key that's been pressed) in T1 LDA QQ11 ; If the view in QQ11 is not %0000110x (i.e. 12 or 13, AND #%00001110 ; which are the Short-range Chart and Long-range Chart), CMP #%00001100 ; jump to TT107 to skip the following and move on to BNE TT107 ; updating the hyperspace 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 LDA T1 ; Restore the original value of A (the key that's been ; pressed) from T1 CMP #38 ; If the "Return pointer to current system" icon was not BNE ee2 ; chosen, jump to ee2 to skip the following JSR ping ; Set the target system to the current system (which ; will move the location in (QQ9, QQ10) to the current ; home system .ReturnFromSearch ASL selectedSystemFlag ; Clear bit 7 of selectedSystemFlag to indicate that LSR selectedSystemFlag ; there is no currently selected system, so the call to ; SetSelectedSystem selects the system in (QQ9, QQ10) JMP SetSelectedSystem ; Jump to SetSelectedSystem to update the message on ; the chart that shows the current system, returning ; from the subroutine using a tail call .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 LDA #5 ; Reset the internal hyperspace counter to 5 STA QQ22 DEC QQ22+1 ; Decrement the on-screen hyperspace countdown BEQ barb12 ; If the countdown is zero, jump to barb12 to do the ; jump LDA #250 ; Print in-flight token 250, which is the hyperspace JMP MESS ; countdown, and return from the subroutine using a ; tail call .barb12 JMP TT18 ; The countdown has finished, so jump to TT18 to do a ; hyperspace jump, returning from the subroutine using ; a tail call .t95 RTS ; Return from the subroutine
Name: BAD [Show more] Type: Subroutine Category: Status Summary: Calculate how bad we have been
Context: See this subroutine on its own page References: This subroutine is called as follows: * Main game loop (Part 3 of 6) calls BAD * TT110 calls BAD

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
.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
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. This routine does a similar job to the routine of the same name in the BBC Master version of Elite, but the code is significantly different.
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 INWK+2 ; If any of x_sign, y_sign or z_sign are non-zero ORA INWK+5 ; (ignoring the sign in bit 7), then jump to faro2 to ORA INWK+8 ; return the C flag clear, to indicate that one of x, y ASL A ; and z is greater than 224 BNE faro2 LDA #224 ; If x_hi > 224, jump to faro1 to return the C flag CMP INWK+1 ; clear BCC faro1 CMP INWK+4 ; If y_hi > 224, jump to faro1 to return the C flag BCC faro1 ; clear CMP INWK+7 ; If z_hi > 224, clear the C flag, otherwise set it .faro1 ; By this point the C flag is clear if any of x_hi, y_hi ; or z_hi are greater than 224, otherwise all three are ; less than or equal to 224 and the C flag is set RTS ; Return from the subroutine .faro2 CLC ; Clear the C flag to indicate that at least one of the ; axes is greater than 224 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: CheckForPause [Show more] Type: Subroutine Category: Icon bar Summary: Pause the game if the pause button (Start) is pressed
Context: See this subroutine on its own page References: This subroutine is called as follows: * CheckForPause_b0 calls CheckForPause * EQSHP calls CheckForPause * RunDemoFlightLoop calls CheckForPause * TT102 calls CheckForPause * BuyAndSellCargo calls via CheckForPause-3 * LAUN calls via CheckForPause-3

Arguments: A The button number to check to see if it is the pause button (a value of 80 indicates the pause button)
Returns: C flag The status of the pause button: * Clear if the pause button is not being pressed * Set if the pause button is being pressed, in which case we return from the subroutine after pausing the the game, processing any choices from the icon bar, and unpausing the game when Start is pressed again
Other entry points: CheckForPause-3 Set A to the number of the icon bar button in iconBarChoice so we check whether the pause button is being pressed
LDA iconBarChoice ; Set A to the number of the icon bar button that has ; been chosen from the icon bar (for when this routine ; is called via the CheckForPause-3 entry point) .CheckForPause CMP #80 ; If iconBarChoice = 80 then the Start button has been BNE cpse1 ; pressed to pause the game, so if this is not the case, ; jump to cpse1 to return from the subroutine with the ; C flag clear and without pausing LDA #0 ; Set iconBarChoice = 0 to clear the pause button press STA iconBarChoice ; so we don't simply re-enter the pause menu when we ; resume JSR PauseGame_b6 ; Pause the game and process choices from the pause menu ; until the game is unpaused by another press of Start SEC ; Set the C flag to indicate that the game was paused RTS ; Return from the subroutine .cpse1 CLC ; Clear the C flag to indicate that the game was not ; paused RTS ; Return from the subroutine
Name: DEATH [Show more] Type: Subroutine Category: Start and end Summary: Display the death screen Deep dive: Splitting the main loop in the NES version
Context: See this subroutine on its own page References: This subroutine is called as follows: * CheckAltitude calls DEATH * Main flight loop (Part 9 of 16) calls DEATH * 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 ResetMusicAfterNMI ; Wait for the next NMI before resetting the current ; tune to 0 (no tune) and stopping the music 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 LDA #0 ; Set the tile number for the left edge of the box to STA boxEdge1 ; the blank tile, so the box around the space view ; disappears STA boxEdge2 ; Set the tile number for the right edge of the box to ; the blank tile, so the box around the space view ; disappears STA autoPlayDemo ; Disable auto-play by setting autoPlayDemo to zero, in ; case we die during the auto-play combat demo LDA #$C4 ; Clear the screen and set the view type in QQ11 to $95 JSR TT66 ; (Game Over screen) JSR ClearDashEdge_b6 ; Clear the right edge of the dashboard JSR CopyNameBuffer0To1 ; Copy the contents of nametable buffer 0 to nametable ; buffer JSR SetScreenForUpdate ; Get the screen ready for updating by hiding all ; sprites, after fading the screen to black if we are ; changing view LDA #0 ; Set showIconBarPointer to 0 to indicate that we should STA showIconBarPointer ; hide the icon bar pointer LDA #$C4 ; Configure the PPU for view type $C4 (Game Over screen) JSR SendViewToPPU_b3 LDA #$00 ; Set the view type in QQ11 to $00 (Space view with no STA QQ11 ; font loaded) STA QQ11a ; Set the old view type in QQ11a to $00 (Space view with ; no fonts loaded) LDA firstFreePattern ; Tell the NMI handler to send pattern entries from the STA firstPattern ; first free pattern onwards, so we don't waste time ; resending the static patterns we have already sent LDA #116 ; Tell the NMI handler to only clear nametable entries STA maxNameTileToClear ; up to tile 116 * 8 = 800 (i.e. up to the end of tile ; row 28) LDX #8 ; Tell the NMI handler to send nametable entries from STX firstNameTile ; tile 8 * 8 = 64 onwards (i.e. from the start of tile ; row 2) LDA #104 ; Set the screen height variables for a screen height of JSR SetScreenHeight ; 208 (i.e. 2 * 104) ; Next we fill the scannerNumber table with non-zero ; entries so when we spawn ships for the death screen, ; they don't appear on the scanner because the scanner ; number table doesn't have any free slots LDY #8 ; Set an index in Y to work through the eight entries ; in the scannerNumber table LDA #1 ; Set A = 1 to use as the value for every ship in the ; scannerNumber table, which is non-zero so the NWSHP ; routine will skip the scanner configuration for any ; ships we spawn .deaf1 STA scannerNumber,Y ; Set the Y-th scannerNumber entry to 1 DEY ; Decrement the index in Y BNE deaf1 ; Loop back until we have set entries 1 to 8 in the ; table to 1, so nothing spawns on the scanner JSR nWq ; Create a cloud of stardust containing the correct ; number of dust particles (i.e. NOSTM of them) ; We now give our ship a random amount of roll by ; setting all the various alpha angle variables JSR DORND ; Set A and X to random numbers AND #%10000111 ; Set the roll angle in ALPHA to the random number, STA ALPHA ; reduced to the range 0 to 7, and with a random sign AND #7 ; Set the magnitude of roll angle alpha in ALP1 to the STA ALP1 ; same value, but with the sign bit cleared (so ALP1 ; contains the magnitude of the roll) LDA ALPHA ; Set the sign of the roll angle alpha in ALP2 to the AND #%10000000 ; sign of ALPHA (so ALP2 contains the sign of the roll) STA ALP2 EOR #%10000000 ; Set the sign of the roll angle alpha in ALP2+1 to the STA ALP2+1 ; flipped sign of ALPHA (so ALP2 contains the flipped ; sign of the roll) .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 #$00 ; Set the view type in QQ11 to $00 (Space view with no STY QQ11 ; font loaded) STY INWK+1 ; Set the following to 0: x_hi, y_hi, z_hi and the AI STY INWK+4 ; flag (no AI or E.C.M. and not hostile) 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 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 LDY #64 ; Set the laser count to 64 to act as a counter in the STY LASCT ; D2 loop below, so this setting determines how long the ; death animation lasts (it's 64 * 2 iterations of the ; main flight loop) SEC ; Set the C flag ROR A ; This sets A to a number between 0 and +7, which we AND #%10000111 ; store in byte #30 (the pitch counter) to give our ship STA INWK+30 ; a very gentle downwards 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+6 ; 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 seventh slot is empty, and if it ; is we loop back to D1 to add another canister, until ; we have added seven of them LDA #8 ; Set our speed in DELTA to 8, so the camera moves STA DELTA ; forward slowly LDA #12 ; Set the text row for in-flight messages in the space STA messYC ; view to row 12 LDA #146 ; Print recursive token 146 ("{all caps}GAME OVER") in LDY #120 ; the middle of the screen and leave it there for 120 JSR PrintMessage ; ticks of the DLY counter JSR HideMostSprites ; Hide all sprites except for sprite 0 and the icon bar ; pointer LDA #30 ; Set the laser count to 30 to act as a counter in the STA LASCT ; D2 loop below, so this setting determines how long the ; death animation lasts .D2 JSR FlipDrawingPlane ; Flip the drawing bitplane so we draw into the bitplane ; that isn't visible on-screen JSR FlightLoop4To16 ; Display in-flight messages, call parts 4 to 12 of the ; main flight loop for each ship slot, and finish off ; with parts 13 to 16 of the main flight loop JSR ClearDashEdge_b6 ; Clear the right edge of the dashboard LDA #%11001100 ; Set the bitplane flags for the drawing bitplane to the JSR SetDrawPlaneFlags ; following: ; ; * Bit 2 set = send tiles up to end of the buffer ; * Bit 3 set = clear buffers after sending data ; * Bit 4 clear = we've not started sending data yet ; * Bit 5 clear = we have not yet sent all the data ; * Bit 6 set = send both pattern and nametable data ; * Bit 7 set = send data to the PPU ; ; Bits 0 and 1 are ignored and are always clear ; ; This configures the NMI to send nametable and pattern ; data for the drawing bitplane to the PPU during VBlank DEC LASCT ; Decrement the counter in LASCT, which we set above, ; so for each loop around D2, we decrement LASCT by 5 ; (the main loop decrements it by 4, and this one makes ; it 5) BNE D2 ; Loop back to call the main flight loop again, until we ; have called it 127 times JMP DEATH2 ; Jump to DEATH2 to reset and restart the game