Skip to navigation

Elite on the BBC Micro and NES

Bank 6 (Part 3 of 3)

[NES version]

Name: LTDEF [Show more] Type: Variable Category: Combat demo Summary: Line definitions for characters in the Star Wars scroll text Deep dive: The 6502 Second Processor demo mode The NES combat demo
Context: See this variable on its own page References: This variable is used as follows: * GRIDSET uses LTDEF

Characters in the scroll text are drawn using lines on a 3x6 numbered grid like this: 0 1 2 . . . 3 4 5 . . . 6 7 8 9 A B The low nibble of each byte is the starting point for that line segment, and the high nibble is the end point, so a value of $28, for example, means "draw a line from point 8 to point 2". This table contains definitions for all the characters we can use in the scroll text, as lines on the above grid. See the deep dive on "the 6502 Second Processor demo mode" for details.
.LTDEF EQUB $00, $00, $00, $00, $00 ; Letter definition for " " (blank) EQUB $14, $25, $12, $45, $78 ; Letter definition for "!" EQUB $24, $00, $00, $00, $00 ; Letter definition for """ ("'") EQUB $02, $17, $68, $00, $00 ; Letter definition for "#" (serif "I") EQUB $35, $36, $47, $58, $00 ; Letter definition for "$" ("m") EQUB $47, $11, $00, $00, $00 ; Letter definition for "%" ("i") EQUB $17, $35, $00, $00, $00 ; Letter definition for "&" ("+") EQUB $36, $47, $34, $00, $00 ; Letter definition for "'" ("n") EQUB $12, $13, $37, $78, $00 ; Letter definition for "(" EQUB $01, $15, $57, $67, $00 ; Letter definition for ")" EQUB $17, $35, $08, $26, $00 ; Letter definition for "*" EQUB $17, $35, $00, $00, $00 ; Letter definition for "+" EQUB $36, $34, $47, $67, $79 ; Letter definition for "," EQUB $35, $00, $00, $00, $00 ; Letter definition for "-" EQUB $36, $34, $47, $67, $00 ; Letter definition for "." EQUB $16, $00, $00, $00, $00 ; Letter definition for "/" EQUB $37, $13, $15, $57, $00 ; Letter definition for "0" EQUB $13, $17, $00, $00, $00 ; Letter definition for "1" EQUB $02, $25, $35, $36, $68 ; Letter definition for "2" EQUB $02, $28, $68, $35, $00 ; Letter definition for "3" EQUB $28, $23, $35, $00, $00 ; Letter definition for "4" EQUB $02, $03, $35, $58, $68 ; Letter definition for "5" EQUB $02, $06, $68, $58, $35 ; Letter definition for "6" EQUB $02, $28, $00, $00, $00 ; Letter definition for "7" EQUB $06, $02, $28, $68, $35 ; Letter definition for "8" EQUB $28, $02, $03, $35, $00 ; Letter definition for "9" EQUB $13, $34, $46, $00, $00 ; Letter definition for ":" ("s") EQUB $01, $06, $34, $67, $00 ; Letter definition for ";" (slim "E") EQUB $13, $37, $00, $00, $00 ; Letter definition for "<" EQUB $45, $78, $00, $00, $00 ; Letter definition for "=" EQUB $00, $00, $00, $00, $00 ; Letter definition for ">" (blank) EQUB $00, $00, $00, $00, $00 ; Letter definition for "?" (blank) EQUB $00, $00, $00, $00, $00 ; Letter definition for "@" (blank) EQUB $06, $02, $28, $35, $00 ; Letter definition for "A" EQUB $06, $02, $28, $68, $35 ; Letter definition for "B" EQUB $68, $06, $02, $00, $00 ; Letter definition for "C" EQUB $06, $05, $56, $00, $00 ; Letter definition for "D" EQUB $68, $06, $02, $35, $00 ; Letter definition for "E" EQUB $06, $02, $35, $00, $00 ; Letter definition for "F" EQUB $45, $58, $68, $60, $02 ; Letter definition for "G" EQUB $06, $28, $35, $00, $00 ; Letter definition for "H" EQUB $17, $00, $00, $00, $00 ; Letter definition for "I" EQUB $28, $68, $36, $00, $00 ; Letter definition for "J" EQUB $06, $23, $38, $00, $00 ; Letter definition for "K" EQUB $68, $06, $00, $00, $00 ; Letter definition for "L" EQUB $06, $04, $24, $28, $00 ; Letter definition for "M" EQUB $06, $08, $28, $00, $00 ; Letter definition for "N" EQUB $06, $02, $28, $68, $00 ; Letter definition for "O" EQUB $06, $02, $25, $35, $00 ; Letter definition for "P" EQUB $06, $02, $28, $68, $48 ; Letter definition for "Q" EQUB $06, $02, $25, $35, $48 ; Letter definition for "R" EQUB $02, $03, $35, $58, $68 ; Letter definition for "S" EQUB $02, $17, $00, $00, $00 ; Letter definition for "T" EQUB $28, $68, $06, $00, $00 ; Letter definition for "U" EQUB $27, $07, $00, $00, $00 ; Letter definition for "V" EQUB $28, $48, $46, $06, $00 ; Letter definition for "W" EQUB $26, $08, $00, $00, $00 ; Letter definition for "X" EQUB $47, $04, $24, $00, $00 ; Letter definition for "Y" EQUB $02, $26, $68, $00, $00 ; Letter definition for "Z"
Name: NOFX [Show more] Type: Variable Category: Combat demo Summary: The x-coordinates of the scroll text letter grid
Context: See this variable on its own page References: This variable is used as follows: * GRS1 uses NOFX
.NOFX EQUB 1 ; Grid points 0-2 EQUB 2 EQUB 3 EQUB 1 ; Grid points 3-5 EQUB 2 EQUB 3 EQUB 1 ; Grid points 6-8 EQUB 2 EQUB 3 EQUB 1 ; Grid points 9-B EQUB 2 EQUB 3
Name: NOFY [Show more] Type: Variable Category: Combat demo Summary: The y-coordinates of the scroll text letter grid
Context: See this variable on its own page References: This variable is used as follows: * GRS1 uses NOFY
.NOFY EQUB 0 ; Grid points 0-2 EQUB 0 EQUB 0 EQUB WY ; Grid points 3-5 EQUB WY EQUB WY EQUB 2*WY ; Grid points 6-8 EQUB 2*WY EQUB 2*WY EQUB 3*WY ; Grid points 9-B EQUB 3*WY EQUB 3*WY
Name: scrollText1Lo [Show more] Type: Variable Category: Combat demo Summary: Lookup table for the low byte of the address of the scrollText1 text for each language Deep dive: Multi-language support in NES Elite
Context: See this variable on its own page References: This variable is used as follows: * ShowScrollText uses scrollText1Lo
.scrollText1Lo EQUB LO(scrollText1_EN) ; English EQUB LO(scrollText1_DE) ; German EQUB LO(scrollText1_FR) ; French EQUB LO(scrollText1_EN) ; There is no fourth language, so this byte is ; ignored
Name: scrollText1Hi [Show more] Type: Variable Category: Combat demo Summary: Lookup table for the high byte of the address of the scrollText1 text for each language Deep dive: Multi-language support in NES Elite
Context: See this variable on its own page References: This variable is used as follows: * ShowScrollText uses scrollText1Hi
.scrollText1Hi EQUB HI(scrollText1_EN) ; English EQUB HI(scrollText1_DE) ; German EQUB HI(scrollText1_FR) ; French EQUB HI(scrollText1_EN) ; There is no fourth language, so this byte is ; ignored
Name: scrollText2Lo [Show more] Type: Variable Category: Combat demo Summary: Lookup table for the low byte of the address of the scrollText2 text for each language Deep dive: Multi-language support in NES Elite
Context: See this variable on its own page References: This variable is used as follows: * ShowScrollText uses scrollText2Lo
.scrollText2Lo EQUB LO(scrollText2_EN) ; English EQUB LO(scrollText2_DE) ; German EQUB LO(scrollText2_FR) ; French EQUB LO(scrollText2_EN) ; There is no fourth language, so this byte is ; ignored
Name: scrollText2Hi [Show more] Type: Variable Category: Combat demo Summary: Lookup table for the high byte of the address of the scrollText2 text for each language Deep dive: Multi-language support in NES Elite
Context: See this variable on its own page References: This variable is used as follows: * ShowScrollText uses scrollText2Hi
.scrollText2Hi EQUB HI(scrollText2_EN) ; English EQUB HI(scrollText2_DE) ; German EQUB HI(scrollText2_FR) ; French EQUB HI(scrollText2_EN) ; There is no fourth language, so this byte is ; ignored
Name: creditsText1Lo [Show more] Type: Variable Category: Combat demo Summary: Lookup table for the low byte of the address of the creditsText1 text for each language
Context: See this variable on its own page References: This variable is used as follows: * ShowScrollText uses creditsText1Lo
.creditsText1Lo EQUB LO(creditsText1) ; English EQUB LO(creditsText1) ; German EQUB LO(creditsText1) ; French EQUB LO(creditsText1) ; There is no fourth language, so this byte is ignored
Name: creditsText1Hi [Show more] Type: Variable Category: Combat demo Summary: Lookup table for the high byte of the address of the creditsText1 text for each language
Context: See this variable on its own page References: This variable is used as follows: * ShowScrollText uses creditsText1Hi
.creditsText1Hi EQUB HI(creditsText1) ; English EQUB HI(creditsText1) ; German EQUB HI(creditsText1) ; French EQUB HI(creditsText1) ; There is no fourth language, so this byte is ignored
Name: creditsText2Lo [Show more] Type: Variable Category: Combat demo Summary: Lookup table for the low byte of the address of the creditsText2 text for each language
Context: See this variable on its own page References: This variable is used as follows: * ShowScrollText uses creditsText2Lo
.creditsText2Lo EQUB LO(creditsText2) ; English EQUB LO(creditsText2) ; German EQUB LO(creditsText2) ; French EQUB LO(creditsText2) ; There is no fourth language, so this byte is ignored
Name: creditsText2Hi [Show more] Type: Variable Category: Combat demo Summary: Lookup table for the high byte of the address of the creditsText2 text for each language
Context: See this variable on its own page References: This variable is used as follows: * ShowScrollText uses creditsText2Hi
.creditsText2Hi EQUB HI(creditsText2) ; English EQUB HI(creditsText2) ; German EQUB HI(creditsText2) ; French EQUB HI(creditsText2) ; There is no fourth language, so this byte is ignored
Name: creditsText3Lo [Show more] Type: Variable Category: Combat demo Summary: Lookup table for the low byte of the address of the creditsText3 text for each language
Context: See this variable on its own page References: This variable is used as follows: * ShowScrollText uses creditsText3Lo
.creditsText3Lo EQUB LO(creditsText3) ; English EQUB LO(creditsText3) ; German EQUB LO(creditsText3) ; French EQUB LO(creditsText3) ; There is no fourth language, so this byte is ignored
Name: creditsText3Hi [Show more] Type: Variable Category: Combat demo Summary: Lookup table for the high byte of the address of the creditsText3 text for each language
Context: See this variable on its own page References: This variable is used as follows: * ShowScrollText uses creditsText3Hi
.creditsText3Hi EQUB HI(creditsText3) ; English EQUB HI(creditsText3) ; German EQUB HI(creditsText3) ; French EQUB HI(creditsText3) ; There is no fourth language, so this byte is ignored
Name: scrollText1_EN [Show more] Type: Variable Category: Combat demo Summary: Text for the first scroll text in English Deep dive: Multi-language support in NES Elite The NES combat demo
Context: See this variable on its own page References: This variable is used as follows: * scrollText1Hi uses scrollText1_EN * scrollText1Lo uses scrollText1_EN
.scrollText1_EN IF _NTSC EQUS " NTSC EMULATION " EQUS " --- E L # T E --- " EQUS "(C)BELL & BRABEN 1991" ELIF _PAL EQUS " IMAGINEER PRESENTS " EQUS " --- E L # T E --- " EQUS "(C)BRABEN & BELL 1991" ENDIF EQUS " " EQUS "PREPARE FOR PRACTICE " EQUS "COMBAT SEQUENCE......"
Name: scrollText2_EN [Show more] Type: Variable Category: Combat demo Summary: Text for the second scroll text in English Deep dive: Multi-language support in NES Elite The NES combat demo
Context: See this variable on its own page References: This variable is used as follows: * scrollText2Hi uses scrollText2_EN * scrollText2Lo uses scrollText2_EN
.scrollText2_EN EQUS " CONGRATULATIONS! YOU" EQUS "COMPLETED THE COMBAT" EQUS " IN " EQUB $83, $82 EQUS " MIN " EQUB $81, $80 EQUS " SEC. " EQUS " " EQUS "YOU BEGIN YOUR CAREER" EQUS "DOCKED AT THE PLANET" EQUS "LAVE WITH 100 CREDITS" EQUS "3 MISSILES AND A FULL" EQUS "TANK OF FUEL. " EQUS "GOOD LUCK, COMMANDER!"
Name: scrollText1_FR [Show more] Type: Variable Category: Combat demo Summary: Text for the first scroll text in French Deep dive: Multi-language support in NES Elite The NES combat demo
Context: See this variable on its own page References: This variable is used as follows: * scrollText1Hi uses scrollText1_FR * scrollText1Lo uses scrollText1_FR
.scrollText1_FR IF _NTSC EQUS " NTSC EMULATION " EQUS " --- E L # T E --- " EQUS "(C)BELL & BRABEN 1991" ELIF _PAL EQUS " IMAGINEER PRESENTE " EQUS " --- E L # T E --- " EQUS "(C)BRABEN & BELL 1991" ENDIF EQUS " " EQUS " PREPAREZ-VOUS A LA" EQUS "SIMULATION DU COMBAT!"
Name: scrollText2_FR [Show more] Type: Variable Category: Combat demo Summary: Text for the second scroll text in French Deep dive: Multi-language support in NES Elite The NES combat demo
Context: See this variable on its own page References: This variable is used as follows: * scrollText2Hi uses scrollText2_FR * scrollText2Lo uses scrollText2_FR
.scrollText2_FR EQUS " FELICITATIONS! VOTRE" EQUS "COMBAT EST TERMINE EN" EQUS " " EQUB $83, $82 EQUS " MIN " EQUB $81, $80 EQUS " SEC. " EQUS " " EQUS " VOUS COMMENCEZ VOTRE" EQUS "COURS SUR LA PLANETE" EQUS "LAVE AVEC 100 CREDITS" EQUS "ET TROIS MISSILES. " EQUS " BONNE CHANCE " EQUS " COMMANDANT! "
Name: scrollText1_DE [Show more] Type: Variable Category: Combat demo Summary: Text for the first scroll text in German Deep dive: Multi-language support in NES Elite The NES combat demo
Context: See this variable on its own page References: This variable is used as follows: * scrollText1Hi uses scrollText1_DE * scrollText1Lo uses scrollText1_DE
.scrollText1_DE IF _NTSC EQUS " NTSC EMULATION " EQUS " --- E L # T E --- " EQUS "(C)BELL & BRABEN 1991" ELIF _PAL EQUS " IMAGINEER ZEIGT " EQUS " --- E L # T E --- " EQUS "(C)BRABEN & BELL 1991" ENDIF EQUS " " EQUS "RUSTEN SIE SICH ZUM" EQUS "PROBEKAMPF..........."
Name: scrollText2_DE [Show more] Type: Variable Category: Combat demo Summary: Text for the second scroll text in German Deep dive: Multi-language support in NES Elite The NES combat demo
Context: See this variable on its own page References: This variable is used as follows: * scrollText2Hi uses scrollText2_DE * scrollText2Lo uses scrollText2_DE
.scrollText2_DE EQUS " BRAVO! SIE HABEN DEN" EQUS "KAMPF GEWONNEN ZEIT" EQUS " " EQUB $83, $82 EQUS " MIN " EQUB $81, $80 EQUS " SEK. " EQUS " " EQUS " SIE BEGINNEN IHRE" EQUS "KARRIERE IM DOCK DES" EQUS "PLANETS LAVE MIT DREI" EQUS "RAKETEN, 100 CR, UND" EQUS "EINEM VOLLEN TANK. " EQUS "VIEL GLUCK,COMMANDER!"
Name: creditsText1 [Show more] Type: Variable Category: Combat demo Summary: Text for the first part of the credits scroll text
Context: See this variable on its own page References: This variable is used as follows: * creditsText1Hi uses creditsText1 * creditsText1Lo uses creditsText1
.creditsText1 EQUS "ORIGINAL GAME AND NES" EQUS "CONVERSION BY DAVID" EQUS "BRABEN AND #AN BELL." EQUS " " EQUS "DEVELOPED USING PDS." EQUS "HANDLED BY MARJACQ. " EQUS " " EQUS "ARTWORK BY EUROCOM" EQUS "DEVELOPMENTS LTD. " EQUS " "
Name: creditsText2 [Show more] Type: Variable Category: Combat demo Summary: Text for the second part of the credits scroll text
Context: See this variable on its own page References: This variable is used as follows: * creditsText2Hi uses creditsText2 * creditsText2Lo uses creditsText2
.creditsText2 EQUS "MUSIC & SOUNDS CODED" EQUS "BY DAVID WHITTAKER." EQUS " " EQUS "MUSIC BY AIDAN BELL" EQUS "AND JOHANN STRAUSS." EQUS " " EQUS "TESTERS=CHRIS JORDAN," EQUS "SAM AND JADE BRIANT, " EQUS "R AND M CHADWICK. "
Name: creditsText3 [Show more] Type: Variable Category: Combat demo Summary: Text for the third part of the credits scroll text
Context: See this variable on its own page References: This variable is used as follows: * creditsText3Hi uses creditsText3 * creditsText3Lo uses creditsText3
.creditsText3 EQUS "ELITE LOGO DESIGN BY " EQUS "PHILIP CASTLE. " EQUS " " EQUS "GAME TEXT TRANSLATERS" EQUS "UBI SOFT, " EQUS "SUSANNE DIECK, " EQUS "IMOGEN RIDLER. "
Name: saveHeader1_EN [Show more] Type: Subroutine Category: Save and load Summary: The Save and Load screen title in English Deep dive: Multi-language support in NES Elite
Context: See this subroutine on its own page References: This subroutine is called as follows: * saveHeader1Hi calls saveHeader1_EN * saveHeader1Lo calls saveHeader1_EN

In the following, EQUB 12 is a newline and EQUB 6 switches to Sentence Case. The text is terminated by EQUB 0.
.saveHeader1_EN EQUS "STORED COMMANDERS" EQUB 12 EQUB 12 EQUB 12 EQUB 6 EQUB 0
Name: saveHeader2_EN [Show more] Type: Subroutine Category: Save and load Summary: The subheaders for the Save and Load screen title in English Deep dive: Multi-language support in NES Elite
Context: See this subroutine on its own page References: This subroutine is called as follows: * saveHeader2Hi calls saveHeader2_EN * saveHeader2Lo calls saveHeader2_EN

In the following, EQUB 12 is a newline and the text is terminated by EQUB 0.
.saveHeader2_EN EQUS " STORED" EQUB 12 EQUS " POSITIONS" EQUB 12 EQUB 12 EQUB 12 EQUB 12 EQUB 12 EQUB 12 EQUB 12 EQUS "CURRENT" EQUB 12 EQUS "POSITION" EQUB 0
Name: saveHeader1_DE [Show more] Type: Subroutine Category: Save and load Summary: The Save and Load screen title in German Deep dive: Multi-language support in NES Elite
Context: See this subroutine on its own page References: This subroutine is called as follows: * saveHeader1Hi calls saveHeader1_DE * saveHeader1Lo calls saveHeader1_DE

In the following, EQUB 12 is a newline and EQUB 6 switches to Sentence Case. The text is terminated by EQUB 0.
.saveHeader1_DE EQUS "GESPEICHERTE KOMMANDANTEN" EQUB 12 EQUB 12 EQUB 12 EQUB 6 EQUB 0
Name: saveHeader2_DE [Show more] Type: Subroutine Category: Save and load Summary: The subheaders for the Save and Load screen title in German Deep dive: Multi-language support in NES Elite
Context: See this subroutine on its own page References: This subroutine is called as follows: * saveHeader2Hi calls saveHeader2_DE * saveHeader2Lo calls saveHeader2_DE

In the following, EQUB 12 is a newline and the text is terminated by EQUB 0.
.saveHeader2_DE EQUS " GESP." EQUB 12 EQUS " POSITIONEN" EQUB 12 EQUB 12 EQUB 12 EQUB 12 EQUB 12 EQUB 12 EQUB 12 EQUS "GEGENW." EQUB 12 EQUS "POSITION" EQUB 0
Name: saveHeader1_FR [Show more] Type: Subroutine Category: Save and load Summary: The Save and Load screen title in French Deep dive: Multi-language support in NES Elite
Context: See this subroutine on its own page References: This subroutine is called as follows: * saveHeader1Hi calls saveHeader1_FR * saveHeader1Lo calls saveHeader1_FR

In the following, EQUB 12 is a newline and EQUB 6 switches to Sentence Case. The text is terminated by EQUB 0.
.saveHeader1_FR EQUS "COMMANDANTS SAUVEGARDES" EQUB 12 EQUB 12 EQUB 12 EQUB 6 EQUB 0
Name: saveHeader2_FR [Show more] Type: Subroutine Category: Save and load Summary: The subheaders for the Save and Load screen title in French Deep dive: Multi-language support in NES Elite
Context: See this subroutine on its own page References: This subroutine is called as follows: * saveHeader2Hi calls saveHeader2_FR * saveHeader2Lo calls saveHeader2_FR

In the following, EQUB 12 is a newline and the text is terminated by EQUB 0.
.saveHeader2_FR EQUS " POSITIONS" EQUB 12 EQUS " SAUVEGARD EQUB 12 EQUB 12 EQUB 12 EQUB 12 EQUB 12 EQUB 12 EQUB 12 EQUS "POSITION" EQUB 12 EQUS "ACTUELLE" EQUB 0
Name: xSaveHeader [Show more] Type: Variable Category: Save and load Summary: The text column for the Save and Load screen headers for each language Deep dive: Multi-language support in NES Elite
Context: See this variable on its own page References: This variable is used as follows: * SVE uses xSaveHeader
.xSaveHeader EQUB 8 ; English EQUB 4 ; German EQUB 4 ; French EQUB 5 ; There is no fourth language, so this byte is ignored
Name: saveHeader1Lo [Show more] Type: Variable Category: Save and load Summary: Lookup table for the low byte of the address of the saveHeader1 text for each language
Context: See this variable on its own page References: This variable is used as follows: * SVE uses saveHeader1Lo
.saveHeader1Lo EQUB LO(saveHeader1_EN) ; English EQUB LO(saveHeader1_DE) ; German EQUB LO(saveHeader1_FR) ; French
Name: saveHeader1Hi [Show more] Type: Variable Category: Save and load Summary: Lookup table for the high byte of the address of the saveHeader1 text for each language
Context: See this variable on its own page References: This variable is used as follows: * SVE uses saveHeader1Hi
.saveHeader1Hi EQUB HI(saveHeader1_EN) ; English EQUB HI(saveHeader1_DE) ; German EQUB HI(saveHeader1_FR) ; French
Name: saveHeader2Lo [Show more] Type: Variable Category: Save and load Summary: Lookup table for the low byte of the address of the saveHeader2 text for each language
Context: See this variable on its own page References: This variable is used as follows: * SVE uses saveHeader2Lo
.saveHeader2Lo EQUB LO(saveHeader2_EN) ; English EQUB LO(saveHeader2_DE) ; German EQUB LO(saveHeader2_FR) ; French
Name: saveHeader2Hi [Show more] Type: Variable Category: Save and load Summary: Lookup table for the high byte of the address of the saveHeader2 text for each language
Context: See this variable on its own page References: This variable is used as follows: * SVE uses saveHeader2Hi
.saveHeader2Hi EQUB HI(saveHeader2_EN) ; English EQUB HI(saveHeader2_DE) ; German EQUB HI(saveHeader2_FR) ; French
Name: saveBracketPatts [Show more] Type: Variable Category: Save and load Summary: Pattern numbers for the bracket on the Save and Load screen
Context: See this variable on its own page References: This variable is used as follows: * SVE uses saveBracketPatts
.saveBracketPatts EQUB 104 EQUB 106 EQUB 105 EQUB 106 EQUB 105 EQUB 106 EQUB 105 EQUB 106 EQUB 107 EQUB 106 EQUB 105 EQUB 106 EQUB 105 EQUB 106 EQUB 108 EQUB 0
Name: PrintSaveHeader [Show more] Type: Subroutine Category: Save and load Summary: Print header text for the Save and Load screen
Context: See this subroutine on its own page References: This subroutine is called as follows: * SVE calls PrintSaveHeader

Arguments: V(1 0) The address of a null-terminated string to print
.PrintSaveHeader LDY #0 ; Set an index in Y so we can work through the text .stxt1 LDA (V),Y ; Fetch the Y-th character from V(1 0) BEQ stxt2 ; If A = 0 then we have reached the null terminator, so ; jump to stxt2 to return from the subroutine JSR TT27_b2 ; Print the character in A INY ; Increment the character counter BNE stxt1 ; Loop back to print the next character (this BNE is ; effectively a JMP as we will reach a null terminator ; well before Y wraps around to zero) .stxt2 RTS ; Return from the subroutine
Name: SVE [Show more] Type: Subroutine Category: Save and load Summary: Display the Save and Load screen and process saving and loading of commander files
Context: See this subroutine on its own page References: This subroutine is called as follows: * SVE_b6 calls SVE

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.
.SVE LDA #$BB ; Clear the screen and set the view type in QQ11 to $BB JSR TT66_b0 ; (Save and load with the normal and highlight fonts ; loaded) LDA #$8B ; Set the view type in QQ11 to $8B (Save and load with STA QQ11 ; no fonts loaded) LDY #0 ; Clear bit 7 of autoPlayDemo so we do not play the demo STY autoPlayDemo ; automatically while the save screen is active STY QQ17 ; Set QQ17 = 0 to switch to ALL CAPS STY YC ; Move the text cursor to row 0 LDX languageIndex ; Move the text cursor to the correct column for the LDA xSaveHeader,X ; Stored Commanders title in the chosen language STA XC LDA saveHeader1Lo,X ; Set V(1 0) to the address of the correct Stored STA V ; Commanders title for the chosen language LDA saveHeader1Hi,X STA V+1 JSR PrintSaveHeader ; Print the null-terminated string at V(1 0), which ; prints the Stored Commanders title for the chosen ; language at the top of the screen LDA #$BB ; Set the view type in QQ11 to $BB (Save and load with STA QQ11 ; the normal and highlight fonts loaded) LDX languageIndex ; Set V(1 0) to the address of the correct subheaders LDA saveHeader2Lo,X ; for the Save and Load screen in the chosen language STA V ; (e.g. the "STORED POSITIONS" and "CURRENT POSITION" LDA saveHeader2Hi,X ; subheaders in English) STA V+1 JSR PrintSaveHeader ; Print the null-terminated string at V(1 0), which ; prints the subheaders JSR NLIN4 ; Draw a horizontal line on tile row 2 to box in the ; title JSR SetScreenForUpdate ; Get the screen ready for updating by hiding all ; sprites, after fading the screen to black if we are ; changing view ; We now draw the tall bracket image that sits between ; the current and stored positions LDY #5*4 ; We are going to draw the bracket using sprites 5 to ; 19, so set Y to the offset of sprite 5 in the sprite ; buffer, where each sprite takes up four bytes LDA #57+YPAL ; The top tile in the bracket is at y-coordinate 57, so STA T ; store this in T so we can use it as the y-coordinate ; for each sprite as we draw the bracket downwards LDX #0 ; The tile numbers are in the saveBracketPatts table, so ; set X as an index to work our way through the table .save1 LDA #%00100010 ; Set the attributes for sprite Y / 4 as follows: STA attrSprite0,Y ; ; * Bits 0-1 = sprite palette 2 ; * Bit 5 set = show behind background ; * Bit 6 clear = do not flip horizontally ; * Bit 7 clear = do not flip vertically LDA saveBracketPatts,X ; Set A to the X-th entry in the saveBracketPatts table BEQ save2 ; If A = 0 then we have reached the end of the tile ; list, so jump to save2 to move on to the next stage STA pattSprite0,Y ; Otherwise we have the next tile number, so set the ; pattern number for sprite Y / 4 to A LDA #83 ; Set the x-coordinate for sprite Y / 4 to 83 STA xSprite0,Y LDA T ; Set the x-coordinate for sprite Y / 4 to T STA ySprite0,Y CLC ; Set T = T + 8 so it points to the next row down (as ADC #8 ; each row is eight pixels high) STA T INY ; Set Y = Y + 4 so it points to the next sprite in the INY ; sprite buffer (as each sprite takes up four bytes in INY ; the buffer) INY INX ; Increment the table index in X to point to the next ; entry in the saveBracketPatts table JMP save1 ; Jump back to save1 to draw the next bracket tile .save2 STY CNT ; Set CNT to the offset in the sprite buffer of the ; next free sprite (i.e. the sprite after the last ; sprite in the bracket) so we can pass it to ; DrawSaveSlotMark below ; We now draw dashes to the left of each of the save ; slots on the right side of the screen LDY #7 ; We are going to draw eight slot marks, so set a ; counter in Y .save3 TYA ; Move the text cursor to row 6 + Y * 2 ASL A ; CLC ; So the slot marks are printed on even rows from row 6 ADC #6 ; to row 20 (though we print them from bottom to top) STA YC LDX #20 ; Move the text cursor to column 20, so we print the STX XC ; slot mark in column 20 JSR DrawSaveSlotMark ; Draw the slot mark for save slot Y DEY ; Decrement the counter in Y BPL save3 ; Loop back until we have printed all eight slot marks JSR DrawSmallLogo_b4 ; Set the sprite buffer entries for the small Elite logo ; in the top-left corner of the screen ; We now work through the save slots and print their ; names LDA #0 ; Set A = 0 to use as the save slot number in the ; following loop (the loop runs from A = 0 to 8, but we ; only print the name for A = 0 to 7, and do nothing for ; A = 8) .save4 CMP #8 ; If A = 8, jump to save5 to skip the following BEQ save5 ; instruction JSR PrintSaveName ; Print the name of the commander file saved in slot A .save5 CLC ; Set A = A + 1 to move on to the next save slot ADC #1 CMP #9 ; Loop back to save4 until we have processed all nine BCC save4 ; slots, leaving A = 9 JSR HighlightSaveName ; Print the name of the commander file saved in slot 9 ; as a highlighted name, so this prints the current ; commander name on the left of the screen, under the ; "CURRENT POSITION" header, in the highlight font JSR UpdateView_b0 ; Update the view to draw all the sprites and tiles ; on-screen LDA #9 ; Set A = 9, which is the slot number we use for the ; current commander name on the left of the screen, so ; this sets the initial position of the highlighted name ; to the current commander name on the left ; Fall through into MoveInLeftColumn to start iterating ; around the main loop for the Save and Load screen
Name: MoveInLeftColumn [Show more] Type: Subroutine Category: Save and load Summary: Process moving the highlight when it's in the left column (the current commander)
Context: See this subroutine on its own page References: This subroutine is called as follows: * MoveToLeftColumn calls MoveInLeftColumn

Arguments: A Must be set to 9, as that represents the slot number of the left column containing the current commander
.MoveInLeftColumn JSR SetupPPUForIconBar ; If the PPU has started drawing the icon bar, configure ; the PPU to use nametable 0 and pattern table 0 LDX controller1Left03 ; If the left button on controller 1 was not being held BPL mlef3 ; down four VBlanks ago or for the three VBlanks before ; that, jump to mlef3 to check the right button ; If we get here then the left button is being pressed, ; so we need to move the highlight left from its current ; position (which is given in A and is always 9) to the ; right column JSR PrintSaveName ; Print the name of the commander file in its current ; position in A, to remove the highlight CMP #9 ; If A = 9 then we have pressed the left button while BEQ mlef1 ; highlighting the current commander name on the left ; of the screen, so we need to move the highlight to the ; right column, so jump to mlef1 to do this ; ; This will always be the case as this routine is only ; called with A = 9 (as that's the slot number we use ; to represent the current commander in the left ; column), so presumably this logic is left over from a ; time when this routine was a bit more generic LDA #0 ; Otherwise the highlight must currently be in either ; the middle or right column, so set A = 0 so the ; highlight moves to the top of the new column (though ; again, this will never happen) JMP mlef2 ; Jump to mlef2 to move the highlight to the right ; column .mlef1 ; If we get here then we have pressed the left button ; while highlighting the current commander name on the ; left of the screen LDA #4 ; Set A = 4 so the call to MoveInRightColumn moves the ; highlight to slot 4 in the right column, which is at ; the same vertical position as the current commander ; name on the left .mlef2 JMP MoveInRightColumn ; Move the highlight left to the specified slot number ; in the right column and process any further button ; presses accordingly .mlef3 LDX controller1Right03 ; If the right button on controller 1 was not being held BPL mlef6 ; down four VBlanks ago or for the three VBlanks before ; that, jump to mlef6 to check the icon bar buttons ; If we get here then the right button is being pressed, ; so we need to move the highlight right from its ; current position (which is given in A and is always 9) ; to the middle column JSR PrintSaveName ; Print the name of the commander file in its current ; position in A, to remove the highlight CMP #9 ; If A = 9 then we have pressed the right button while BEQ mlef4 ; highlighting the current commander name on the left of ; the screen, so we need to move the highlight to the ; middle column, so jump to mlef4 to do this ; ; This will always be the case as this routine is only ; called with A = 9 (as that's the slot number we use ; to represent the current commander in the left ; column), so presumably this logic is left over from a ; time when this routine was a bit more generic LDA #0 ; Otherwise the highlight must currently be in either ; the middle or right column, so set A = 0 so the ; highlight moves to the top of the new column (though ; again, this will never happen) JMP mlef5 ; Jump to mlef5 to move the highlight to the middle ; column .mlef4 ; If we get here then we have pressed the right button ; while highlighting the current commander name on the ; left of the screen LDA #4 ; Set A = 4 so the call to MoveInMiddleColumn moves the ; highlight to slot 4 in the middle column, which is at ; the same vertical position as the current commander ; name on the left .mlef5 JMP MoveInMiddleColumn ; Move the highlight left to the specified slot number ; in the middle column and process any further button ; presses accordingly .mlef6 ; If we get here then neither of the left or right ; buttons have been pressed, so we move on to checking ; the icon bar buttons JSR CheckSaveLoadBar ; Check the icon bar buttons to see if any of them have ; been chosen BCS MoveInLeftColumn ; The C flag will be set if we are to resume what we ; were doing (so we pick up where we left off after ; processing the pause menu, for example), so loop back ; to the start of the routine to keep checking for left ; and right button presses ; If we get here then the C flag is clear and we need to ; return from the SVE routine and go back to the icon ; bar processing routine in TT102 RTS ; Return from the subroutine
Name: CheckSaveLoadBar [Show more] Type: Subroutine Category: Save and load Summary: Check the icon bar buttons on the Save and Load icon bar and process any choices
Context: See this subroutine on its own page References: This subroutine is called as follows: * MoveInLeftColumn calls CheckSaveLoadBar * MoveInMiddleColumn calls CheckSaveLoadBar * MoveInRightColumn calls CheckSaveLoadBar

Returns: C flag Determines the next step when we return from the routine: * Clear = exit from the SVE routine when we return and go back to the icon bar processing routine in TT102, so the button choice can be processed there * Set = keep going as if nothing has happened (used to resume from the pause menu or if nothing was chosen, for example) A A is preserved
.CheckSaveLoadBar LDX iconBarChoice ; If iconBarChoice = 0 then nothing has been chosen on BEQ cbar1 ; the icon bar (if it had, iconBarChoice would contain ; the number of the chosen icon bar button), so jump to ; cbar1 to return from the subroutine with the C flag ; set, so we pick up where we left off PHA ; Store the value of A on the stack so we can restore it ; at the end of the subroutine CPX #7 ; If the Change Commander Name button was pressed, BEQ cbar2 ; jump to cbar2 to process it TXA ; Otherwise set X to the button number to pass to the ; CheckForPause routine JSR CheckForPause_b0 ; If the Start button has been pressed then process the ; pause menu and set the C flag, otherwise clear it ; ; We now return this value of the C flag, so if we just ; processed the pause menu then the C flag will be set, ; so we pick up where we left off when we return, ; otherwise it will be clear and we need to pass the ; button choice back to TT102 to be processed there PLA ; Restore the value of A that we stored on the stack, so ; A is preserved RTS ; Return from the subroutine .cbar1 SEC ; Set the C flag so that when we return from the ; routine, we pick up where we left off RTS ; Return from the subroutine .cbar2 LDA COK ; If bit 7 of COK is set, then cheat mode has been BMI cbar4 ; applied, so jump to cbar4 to return from the ; subroutine with the C flag clear, as cheats can't ; change their commander name LDA #0 ; Set iconBarChoice = 0 to clear the icon button choice STA iconBarChoice ; so we don't process it again JSR ChangeCmdrName_b6 ; Process changing the commander name LDA iconBarChoice ; If iconBarChoice = 0 then nothing has been chosen on BEQ cbar3 ; the icon bar during the renaming routine (if it had, ; iconBarChoice would contain the number of the chosen ; icon bar button), so jump to cbar3 to force a reload ; of the Save and Load screen CMP #7 ; If the Change Commander Name button was pressed BEQ cbar2 ; during the renaming routine, jump to cbar2 to restart ; the renaming process .cbar3 LDA #6 ; Set iconBarChoice to the Save and Load button, so STA iconBarChoice ; when we return from the routine with the C flag clear, ; the TT102 routine processes this as if we had chosen ; this button, and reloads the Save and Load screen .cbar4 CLC ; Clear the C flag so that when we return from the ; routine, the button number in iconBarChoice is passed ; to TT102 to be processed as a button choice PLA ; Restore the value of A that we stored on the stack, so ; A is preserved RTS ; Return from the subroutine
Name: WaitForNoDirection [Show more] Type: Subroutine Category: Controllers Summary: Wait until the left and right buttons on controller 1 have been released and remain released for at least four VBlanks
Context: See this subroutine on its own page References: This subroutine is called as follows: * MoveInMiddleColumn calls WaitForNoDirection * MoveInRightColumn calls WaitForNoDirection * MoveToLeftColumn calls WaitForNoDirection

Returns: A A is preserved
.WaitForNoDirection PHA ; Store the value of A on the stack so we can restore it ; at the end of the subroutine .ndir1 JSR SetupPPUForIconBar ; If the PPU has started drawing the icon bar, configure ; the PPU to use nametable 0 and pattern table 0 LDA controller1Left03 ; Keep looping back to ndir1 until both the left and ORA controller1Right03 ; right button on controller 1 have been released and BMI ndir1 ; remain released for at least four VBlanks PLA ; Restore the value of A that we stored on the stack, so ; A is preserved RTS ; Return from the subroutine
Name: MoveToLeftColumn [Show more] Type: Subroutine Category: Save and load Summary: Move the highlight to the left column (the current commander)
Context: See this subroutine on its own page References: This subroutine is called as follows: * MoveInMiddleColumn calls MoveToLeftColumn * MoveInRightColumn calls MoveToLeftColumn
.MoveToLeftColumn LDA #9 ; Set A = 9 to set the position of the highlight to slot ; 9, which we use to represent the current commander in ; the left column JSR HighlightSaveName ; Print the name of the commander file saved in slot 9 ; as a highlighted name, so this prints the current ; commander name on the left of the screen, under the ; "CURRENT POSITION" header, in the highlight font JSR UpdateSaveScreen ; Update the screen JSR WaitForNoDirection ; Wait until the left and right buttons on controller 1 ; have been released and remain released for at least ; four VBlanks JMP MoveInLeftColumn ; Move the highlight to the current commander in the ; left column and process any further button presses ; accordingly
Name: MoveInRightColumn [Show more] Type: Subroutine Category: Save and load Summary: Process moving the highlight when it's in the right column (the save slots)
Context: See this subroutine on its own page References: This subroutine is called as follows: * MoveInLeftColumn calls MoveInRightColumn * MoveInMiddleColumn calls MoveInRightColumn

Arguments: A The slot number in the right column containing the highlight (0 to 7)
.MoveInRightColumn JSR HighlightSaveName ; Highlight the name of the save slot in A, so the ; highlight is shown in the correct slot in the right ; column JSR UpdateSaveScreen ; Update the screen JSR WaitForNoDirection ; Wait until the left and right buttons on controller 1 ; have been released and remain released for at least ; four VBlanks .mrig1 JSR SetupPPUForIconBar ; If the PPU has started drawing the icon bar, configure ; the PPU to use nametable 0 and pattern table 0 LDX controller1Up ; If the up button on controller 1 is not being pressed, BPL mrig2 ; jump to mrig2 to move on to the next button ; If we get here then the up button is being pressed CMP #0 ; If A = 0 then we are already in the top slot in the BEQ mrig2 ; column, so jump to mrig2 to move on to the next button ; as we can't move beyond the top of the column JSR PrintSaveName ; Print the name of the commander file saved in slot A ; so that it reverts to the normal font, as we are about ; to move the highlight elsewhere SEC ; Set A = A - 1 SBC #1 ; ; So A is now the slot number of the slot above JSR HighlightSaveName ; Highlight the name of the save slot in A, so the ; highlight moves to the new position JSR UpdateSaveScreen ; Update the screen .mrig2 LDX controller1Down ; If the down button on controller 1 is not being BPL mrig3 ; pressed, jump to mrig3 to move on to the next button ; If we get here then the down button is being pressed CMP #7 ; If A >= 7 then we are already in the bottom slot in BCS mrig3 ; the column, so jump to mrig3 to move on to the next ; button as we can't move beyond the bottom of the ; column JSR PrintSaveName ; Print the name of the commander file saved in slot A ; so that it reverts to the normal font, as we are about ; to move the highlight elsewhere CLC ; Set A = A + 1 ADC #1 ; ; So A is now the slot number of the slot below JSR HighlightSaveName ; Highlight the name of the save slot in A, so the ; highlight moves to the new position JSR UpdateSaveScreen ; Update the screen .mrig3 LDX controller1Left03 ; If the left button on controller 1 was not being held BPL mrig4 ; down four VBlanks ago, jump to mrig4 to move on to the ; next button ; If we get here then the left button is being pressed JSR PrintSaveName ; Print the name of the commander file saved in slot A ; so that it reverts to the normal font, as we are about ; to move the highlight elsewhere JMP MoveInMiddleColumn ; Move the highlight left to the specified slot number ; in the middle column and process any further button ; presses accordingly .mrig4 LDX controller1Right03 ; If the right button on controller 1 was not being held BPL mrig5 ; down four VBlanks ago, jump to mrig5 to check the icon ; bar buttons ; If we get here then the right button is being pressed JSR PrintSaveName ; Print the name of the commander file saved in slot A ; so that it reverts to the normal font, as we are about ; to move the highlight elsewhere LDA #4 ; This instruction has no effect as the first thing that ; MoveToLeftColumn does is to set A to 9, which is the ; slot number for the current commander JMP MoveToLeftColumn ; Move the highlight to the left column (the current ; commander) and process any further button presses ; accordingly .mrig5 ; If we get here then neither of the left or right ; buttons have been pressed, so we move on to checking ; the icon bar buttons JSR CheckSaveLoadBar ; Check the icon bar buttons to see if any of them have ; been chosen BCS mrig1 ; The C flag will be set if we are to resume what we ; were doing (so we pick up where we left off after ; processing the pause menu, for example, or keep going ; if no button was chosen), so loop back to mrig1 to ; keep checking for left and right button presses ; If we get here then the C flag is clear and we need to ; return from the SVE routine and go back to the icon ; bar processing routine in TT102, so the button choice ; can be processed there RTS ; Return from the subroutine
Name: MoveInMiddleColumn [Show more] Type: Subroutine Category: Save and load Summary: Process moving the highlight when it's in the middle column
Context: See this subroutine on its own page References: This subroutine is called as follows: * MoveInLeftColumn calls MoveInMiddleColumn * MoveInRightColumn calls MoveInMiddleColumn

Arguments: A The slot number in the middle column containing the highlight (0 to 7)
.MoveInMiddleColumn JSR PrintNameInMiddle ; Print the name of the commander file in A, so the ; highlight is shown in the correct slot in the middle ; column JSR UpdateSaveScreen ; Update the screen JSR WaitForNoDirection ; Wait until the left and right buttons on controller 1 ; have been released and remain released for at least ; four VBlanks .mmid1 JSR SetupPPUForIconBar ; If the PPU has started drawing the icon bar, configure ; the PPU to use nametable 0 and pattern table 0 LDX controller1Up ; If the up button on controller 1 is not being pressed, BPL mmid2 ; jump to mmid2 to move on to the next button ; If we get here then the up button is being pressed CMP #0 ; If A = 0 then we are already in the top slot in the BEQ mmid2 ; column, so jump to mmid2 to move on to the next button ; as we can't move beyond the top of the column JSR ClearNameInMiddle ; Clear the name of the commander file from slot A in ; the middle column, as we are about to move the ; highlight elsewhere SEC ; Set A = A - 1 SBC #1 ; ; So A is now the slot number of the slot above JSR PrintNameInMiddle ; Print the name of the commander file in slot A in the ; middle column, so the highlight moves to the new ; position JSR UpdateSaveScreen ; Update the screen .mmid2 LDX controller1Down ; If the down button on controller 1 is not being BPL mmid3 ; pressed, jump to mmid3 to move on to the next button ; If we get here then the down button is being pressed CMP #7 ; If A >= 7 then we are already in the bottom slot in BCS mmid3 ; the column, so jump to mmid3 to move on to the next ; button as we can't move beyond the bottom of the ; column JSR ClearNameInMiddle ; Clear the name of the commander file from slot A in ; the middle column, as we are about to move the ; highlight elsewhere CLC ; Set A = A + 1 ADC #1 ; ; So A is now the slot number of the slot below JSR PrintNameInMiddle ; Print the name of the commander file in slot A in the ; middle column, so the highlight moves to the new ; position JSR UpdateSaveScreen ; Update the screen .mmid3 LDX controller1Left03 ; If the left button on controller 1 was not being held BPL mmid4 ; down four VBlanks ago, jump to mmid4 to move on to the ; next button ; If we get here then the left button is being pressed CMP #4 ; We can only move left from the middle column if we are BNE mmid4 ; at the same height as the current commander slot in ; the column to the left ; ; The current commander slot is to the left of slot 4 ; in the middle column, so jump to mmid4 to move on to ; the next button if we are not currently in slot 4 in ; the middle column ; If we get here then we are in slot 4 in the middle ; column, so we can now move left JSR ClearNameInMiddle ; Clear the name of the commander file from slot A in ; the middle column, as we are about to move the ; highlight elsewhere LDA #9 ; Set A = 9 to set the position of the highlight to slot ; 9, which we use to represent the current commander in ; the left column JSR SaveLoadCommander ; Load the chosen commander file into NAME to overwrite ; the game's current commander, so this effectively ; loads the chosen commander into the game JSR UpdateIconBar_b3 ; Update the icon bar in case we just changed the ; current commander to a cheat file, in which case we ; hide the button that lets you change the commander ; name JMP MoveToLeftColumn ; Move the highlight to the left column (the current ; commander) and process any further button presses ; accordingly .mmid4 LDX controller1Right03 ; If the right button on controller 1 was not being held BPL mmid5 ; down four VBlanks ago, jump to mmid5 to check the icon ; bar buttons ; If we get here then the right button is being pressed JSR ClearNameInMiddle ; Clear the name of the commander file from slot A in ; the middle column, as we are about to move the ; highlight elsewhere JSR SaveLoadCommander ; Save the commander into the chosen save slot by ; splitting it up and saving it into three parts in ; saveSlotPart1, saveSlotPart2 and saveSlotPart3 JMP MoveInRightColumn ; Move the highlight to the right column (the save ; slots) and process any further button presses ; accordingly .mmid5 ; If we get here then neither of the left or right ; buttons have been pressed, so we move on to checking ; the icon bar buttons JSR CheckSaveLoadBar ; Check the icon bar buttons to see if any of them have ; been chosen BCS mmid1 ; The C flag will be set if we are to resume what we ; were doing (so we pick up where we left off after ; processing the pause menu, for example, or keep going ; if no button was chosen), so loop back to mmid1 to ; keep checking for left and right button presses ; If we get here then the C flag is clear and we need to ; return from the SVE routine and go back to the icon ; bar processing routine in TT102, so the button choice ; can be processed there RTS ; Return from the subroutine
Name: DrawSaveSlotMark [Show more] Type: Subroutine Category: Save and load Summary: Draw a slot mark (a dash) next to a saved slot
Context: See this subroutine on its own page References: This subroutine is called as follows: * SVE calls DrawSaveSlotMark

Arguments: Y The save slot number (0 to 7) CNT The offset of the first free sprite in the sprite buffer
Returns: Y Y is preserved
.DrawSaveSlotMark STY YSAV2 ; Store Y in YSAV2 so we can retrieve it below LDY CNT ; Set Y to the offset of the first free sprite in the ; sprite buffer LDA #109 ; Set the pattern number for sprite Y to 109, which is STA pattSprite0,Y ; the dash that we want to use for the slot mark LDA XC ; Set the x-coordinate for sprite Y to XC * 8 ASL A ; ASL A ; As each tile is eight pixels wide, this sets the pixel ASL A ; x-coordinate to tile column XC ADC #0 STA xSprite0,Y LDA #%00100010 ; Set the attributes for sprite Y as follows: STA attrSprite0,Y ; ; * Bits 0-1 = sprite palette 2 ; * Bit 5 set = show behind background ; * Bit 6 clear = do not flip horizontally ; * Bit 7 clear = do not flip vertically LDA YC ; Set the y-coordinate for sprite Y to 6 + YC * 8 ASL A ; ASL A ; As each tile is eight pixels tall, this sets the pixel ASL A ; y-coordinate to the sixth pixel line within tile row ADC #6+YPAL ; YC STA ySprite0,Y TYA ; Set CNT = Y + 4 CLC ; ADC #4 ; So CNT points to the next sprite in the sprite buffer STA CNT ; (as each sprite takes up four bytes in the buffer) LDY YSAV2 ; Restore the value of Y that we stored in YSAV2 above ; so that Y is preserved RTS ; Return from the subroutine
Name: PrintSaveName [Show more] Type: Subroutine Category: Save and load Summary: Print the name of a specific save slot
Context: See this subroutine on its own page References: This subroutine is called as follows: * HighlightSaveName calls PrintSaveName * MoveInLeftColumn calls PrintSaveName * MoveInRightColumn calls PrintSaveName * SVE calls PrintSaveName

Arguments: A The save slot number to print: * 0 to 7 = print the name of a specific save slot on the right of the screen * 8 = print the current commander name in the middle column * 9 = print the current commander name in the left column
Returns: A A is preserved
.PrintSaveName JSR CopyCommanderToBuf ; Copy the commander file from save slot A into the ; buffer at BUF, so we can access its name PHA ; Store the value of A on the stack so we can restore it ; at the end of the subroutine CMP #8 ; If A < 8 then this is one of the save slots on the BCC psav3 ; right of the screen, so jump to pav3 to print the name ; in the right column LDX #1 ; Move the text cursor to column 1 STX XC CMP #9 ; If A < 9 then A = 8, which represents the middle BCC psav2 ; column, so jump to psav2 to print the name in the ; middle column BEQ psav1 ; If A = 9 then this represents the current commander in ; the left column so jump to psav1 to print the name on ; the left of the screen ; If we get here then A >= 10, which is never the case, ; so this code might be left over from functionality ; that was later removed LDA #18 ; Move the text cursor to row 18 STA YC JMP psav4 ; Jump to psav4 to print the name of the file in the ; save slot .psav1 ; If we get here then A = 9, so we need to print the ; commander name in the left column LDA #14 ; Move the text cursor to row 14 STA YC JMP psav4 ; Jump to psav4 to print the name of the file in the ; save slot .psav2 ; If we get here then A = 8, so we need to print the ; commander name in the middle column LDA #6 ; Move the text cursor to row 6 STA YC JMP psav4 ; Jump to psav4 to print the name of the file in the ; save slot .psav3 ; If we get here then A is in the range 0 to 7, so we ; need to print the commander name in the right column ASL A ; Move the text cursor to row 6 + A * 2 CLC ; ADC #6 ; So this is the text row for slot number A in the right STA YC ; column of the screen LDA #21 ; Move the text cursor to column 21 for the column of STA XC ; slot names on the right of the screen .psav4 PLA ; Restore the value of A that we stored on the stack, so ; A is preserved ; Fall through into PrintCommanderName to print the name ; of the commander file in BUF, followed by the save ; count
Name: PrintCommanderName [Show more] Type: Subroutine Category: Save and load Summary: Print the commander name from the commander file in BUF, with the save count added to the end
Context: See this subroutine on its own page References: This subroutine is called as follows: * PrintNameInMiddle calls PrintCommanderName

Returns: A A is preserved
.PrintCommanderName PHA ; Store the value of A on the stack so we can restore it ; at the end of the subroutine LDY #0 ; We start by printing the commander name from the first ; seven bytes of the commander file at BUF, so set a ; character index in Y so we can loop though the name ; one character at a time .pnam1 LDA BUF,Y ; Set A to the Y-th character from the name at BUF JSR DASC_b2 ; Print the character INY ; Increment the character index in Y CPY #7 ; Loop back until we have printed all seven characters BCC pnam1 ; in the BUF buffer from BUF to BUF+6 ; Now that the name is printed, we print the save count ; after the end of the name as a one- or two-digit ; decimal value LDX #0 ; Set X = 0 to use as a division counter in the loop ; below LDA BUF+7 ; Set A to the byte after the end of the name, which ; contains the save counter in SVC AND #%01111111 ; Clear bit 7 of the save counter so we are left with ; the number of saves in A SEC ; Set the C flag for the subtraction below .pnam2 SBC #10 ; Set A = A - 10 INX ; Increment X BCS pnam2 ; If the subtraction didn't underflow, jump back to ; pnam2 to subtract another 10 TAY ; By this point X contains the number of whole tens in ; the original number, plus 1 (as that extra one broke ; the subtraction), while A contains the remainder, so ; this instruction sets Y so the following is true: ; ; SVC = 10 * (X + 1) - (10 - Y) ; = 10 * (X + 1) + (Y - 10) LDA #' ' ; Set A to the ASCII for space DEX ; Decrement X so this is now true: ; ; SVC = 10 * X + (Y - 10) BEQ pnam3 ; If X = 0 then jump to pnam3 to print a space for the ; first digit of the save count, as it is less than ten TXA ; Otherwise set A to the ASCII code for the digit in X ADC #'0' ; so we print the correct tens digit for the save ; counter .pnam3 JSR DASC_b2 ; Print the character in A to print the first digit of ; the save counter TYA ; The remainder of the calculation above is Y - 10, so CLC ; to get the second digit in the value of SVC, we need ADC #'0'+10 ; to add 10 to the value in Y, before adding ASCII "0" ; to convert it into a character JSR DASC_b2 ; Print the character in A to print the second digit of ; the save counter PLA ; Restore the value of A that we stored on the stack, so ; A is preserved RTS ; Return from the subroutine
Name: HighlightSaveName [Show more] Type: Subroutine Category: Save and load Summary: Highlight the name of a specific save slot
Context: See this subroutine on its own page References: This subroutine is called as follows: * MoveInRightColumn calls HighlightSaveName * MoveToLeftColumn calls HighlightSaveName * SVE calls HighlightSaveName

Arguments: A The save slot number to highlight
.HighlightSaveName LDX #2 ; Set the font style to print in the highlight font STX fontStyle JSR PrintSaveName ; Print the name of the commander file saved in slot A LDX #1 ; Set the font style to print in the normal font STX fontStyle RTS ; Return from the subroutine
Name: UpdateSaveScreen [Show more] Type: Subroutine Category: Save and load Summary: Update the Save and Load screen
Context: See this subroutine on its own page References: This subroutine is called as follows: * MoveInMiddleColumn calls UpdateSaveScreen * MoveInRightColumn calls UpdateSaveScreen * MoveToLeftColumn calls UpdateSaveScreen

Returns: A A is preserved
.UpdateSaveScreen PHA ; Store the value of A on the stack so we can restore it ; at the end of the subroutine JSR DrawScreenInNMI_b0 ; Configure the NMI handler to draw the screen 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 ; Restore the value of A that we stored on the stack, so ; A is preserved RTS ; Return from the subroutine
Name: PrintNameInMiddle [Show more] Type: Subroutine Category: Save and load Summary: Print the commander name in the middle column using the highlight font
Context: See this subroutine on its own page References: This subroutine is called as follows: * MoveInMiddleColumn calls PrintNameInMiddle

Arguments: A The slot number in which to print the commander name in the middle column (0 to 7)
Returns: A A is preserved
.PrintNameInMiddle LDX #2 ; Set the font style to print in the highlight font STX fontStyle LDX #11 ; Move the text cursor to column 11, so we print the STX XC ; name in the middle column of the screen PHA ; Store the value of A on the stack so we can restore it ; after the following calculation ASL A ; Move the text cursor to row 6 + A * 2 CLC ; ADC #6 ; So this is the text row for slot number A in the STA YC ; middle column of the screen PLA ; Restore the value of A that we stored on the stack JSR PrintCommanderName ; Print the commander name from the commander file in ; BUF, along with the save count LDX #1 ; Set the font style to print in the normal font STX fontStyle RTS ; Return from the subroutine
Name: ClearNameInMiddle [Show more] Type: Subroutine Category: Save and load Summary: Remove the commander name from the middle column
Context: See this subroutine on its own page References: This subroutine is called as follows: * MoveInMiddleColumn calls ClearNameInMiddle

Arguments: A The slot number to clear in the middle column (0 to 7)
Returns: A A is preserved
.ClearNameInMiddle LDX #11 ; Move the text cursor to column 11, so we print the STX XC ; name in the middle column of the screen PHA ; Store the value of A on the stack so we can restore it ; at the end of the subroutine ASL A ; Move the text cursor to row 6 + A * 2 CLC ; ADC #6 ; So this is the text row for slot number A in the STA YC ; middle column of the screen JSR GetRowNameAddress ; Get the addresses in the nametable buffers for the ; start of character row YC, as follows: ; ; SC(1 0) = the address in nametable buffer 0 ; ; SC2(1 0) = the address in nametable buffer 1 LDA SC ; Set SC(1 0) = SC(1 0) + XC CLC ; ADC XC ; So SC(1 0) is the address in nametable buffer 0 for STA SC ; the tile at cursor position (XC, YC) LDY #8 ; We now want to print 8 spaces over the top of the slot ; at (XC, YC), so set Y as a loop counter to count down ; from 8 LDA #0 ; Set A = 0 to use as the pattern number for the blank ; background tile .cpos1 STA (SC),Y ; Set the Y-th tile of the slot in nametable buffer 0 to ; the blank tile DEY ; Decrement the tile counter BPL cpos1 ; Loop back until we have blanked out every character ; of the slot PLA ; Restore the value of A that we stored on the stack, so ; A is preserved RTS ; Return from the subroutine
Name: galaxySeeds [Show more] Type: Variable Category: Save and load Summary: The galaxy seeds to add to a commander save file
Context: See this variable on its own page References: This variable is used as follows: * CopyCommanderToBuf uses galaxySeeds
.galaxySeeds EQUB $4A, $5A, $48, $02, $53, $B7, $00, $00 EQUB $94, $B4, $90, $04, $A6, $6F, $00, $00 EQUB $29, $69, $21, $08, $4D, $DE, $00, $00 EQUB $52, $D2, $42, $10, $9A, $BD, $00, $00 EQUB $A4, $A5, $84, $20, $35, $7B, $00, $00 EQUB $49, $4B, $09, $40, $6A, $F6, $00, $00 EQUB $92, $96, $12, $80, $D4, $ED, $00, $00 EQUB $25, $2D, $24, $01, $A9, $DB, $00, $00
Name: saveSlotAddr1 [Show more] Type: Variable Category: Save and load Summary: The address of the first saved part for each save slot
Context: See this variable on its own page References: This variable is used as follows: * GetSaveAddresses uses saveSlotAddr1
.saveSlotAddr1 EQUW saveSlotPart1 + 0 * 73 EQUW saveSlotPart1 + 1 * 73 EQUW saveSlotPart1 + 2 * 73 EQUW saveSlotPart1 + 3 * 73 EQUW saveSlotPart1 + 4 * 73 EQUW saveSlotPart1 + 5 * 73 EQUW saveSlotPart1 + 6 * 73 EQUW saveSlotPart1 + 7 * 73
Name: saveSlotAddr2 [Show more] Type: Variable Category: Save and load Summary: The address of the second saved part for each save slot
Context: See this variable on its own page References: This variable is used as follows: * GetSaveAddresses uses saveSlotAddr2
.saveSlotAddr2 EQUW saveSlotPart2 + 0 * 73 EQUW saveSlotPart2 + 1 * 73 EQUW saveSlotPart2 + 2 * 73 EQUW saveSlotPart2 + 3 * 73 EQUW saveSlotPart2 + 4 * 73 EQUW saveSlotPart2 + 5 * 73 EQUW saveSlotPart2 + 6 * 73 EQUW saveSlotPart2 + 7 * 73
Name: saveSlotAddr3 [Show more] Type: Variable Category: Save and load Summary: The address of the third saved part for each save slot
Context: See this variable on its own page References: This variable is used as follows: * GetSaveAddresses uses saveSlotAddr3
.saveSlotAddr3 EQUW saveSlotPart3 + 0 * 73 EQUW saveSlotPart3 + 1 * 73 EQUW saveSlotPart3 + 2 * 73 EQUW saveSlotPart3 + 3 * 73 EQUW saveSlotPart3 + 4 * 73 EQUW saveSlotPart3 + 5 * 73 EQUW saveSlotPart3 + 6 * 73 EQUW saveSlotPart3 + 7 * 73
Name: ResetSaveBuffer [Show more] Type: Subroutine Category: Save and load Summary: Reset the commander file buffer at BUF to the default commander
Context: See this subroutine on its own page References: This subroutine is called as follows: * CopyCommanderToBuf calls ResetSaveBuffer * CopyCommanderToBuf calls via ResetSaveBuffer+1

Returns: A A is preserved
Other entry points: ResetSaveBuffer+1 Omit the initial PHA (so we can jump here if the value of the preserved A is already on the stack from another routine)
.ResetSaveBuffer PHA ; Store the value of A on the stack so we can restore it ; at the end of the subroutine LDX #78 ; We are going to copy 79 bytes, so set a counter in X .resb1 LDA NA2%,X ; Copy the X-th byte of the default commander in NA2% to STA BUF,X ; the X-th byte of BUF DEX ; Decrement the byte counter BPL resb1 ; Loop back until we have copied all 79 bytes PLA ; Restore the value of A that we stored on the stack, so ; A is preserved RTS ; Return from the subroutine
Name: CopyCommanderToBuf [Show more] Type: Subroutine Category: Save and load Summary: Copy a commander file in the BUF buffer, either from a save slot or from the currently active commander in-game
Context: See this subroutine on its own page References: This subroutine is called as follows: * CheckSaveSlots calls CopyCommanderToBuf * PrintSaveName calls CopyCommanderToBuf

Arguments: A The slot number to process: * 0 to 7 = copy the commander from save slot A into the buffer at BUF, combining all three parts to do so * 8 = load the default commander into BUF * 9 = copy the current commander from in-game, in which case we copy the commander from NAME to BUF without having to combine separate parts
Returns: A A is preserved
.CopyCommanderToBuf PHA ; Store the value of A on the stack so we can restore it ; at the end of the subroutine JSR SetupPPUForIconBar ; If the PPU has started drawing the icon bar, configure ; the PPU to use nametable 0 and pattern table 0 CMP #9 ; If A = 9 then this is the current commander in the BEQ ctob7 ; left column, so jump to ctob7 to copy the in-game ; commander to BUF CMP #8 ; If A = 8 then this is the middle column, so jump to BEQ ResetSaveBuffer+1 ; ResetSaveBuffer+1 to load the default commander into ; BUF ; If we get here then this is one of the save slots on ; the right of the screen and A is in the range 0 to 7, ; so now we load the contents of the save slot into the ; buffer at BUF ; ; Each save slot is split up into three parts, so we now ; need to combine them to get our commander file JSR GetSaveAddresses ; Set the following for save slot A: ; ; SC(1 0) = address of the first saved part ; ; Q(1 0) = address of the second saved part ; ; S(1 0) = address of the third saved part LDY #72 ; We work our way through 73 bytes in each saved part, ; so set an index counter in Y .ctob1 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 (Q),Y ; Set A to the Y-th byte of the second saved part in ; Q(1 0) IF _NTSC EOR #$F0 ; Set SC2+1 = A with the high nibble flipped STA SC2+1 LDA (S),Y ; Set SC2 to the Y-th byte from the third part in S(1 0) EOR #$0F ; with the low nibble flipped STA SC2 ELIF _PAL LSR A ; Rotate A to the right, in-place BCC ctob2 ORA #%10000000 .ctob2 LSR A ; Rotate A to the right again, in-place BCC ctob3 ORA #%10000000 .ctob3 STA SC2+1 ; Set SC2+1 to the newly rotated value of the byte from ; the second saved part LDA (S),Y ; Set SC2 to the Y-th byte from the third part in S(1 0) LSR A ; Rotate A to the right, in-place BCC ctob4 ORA #%10000000 .ctob4 STA SC2 ; Set SC2 to the newly rotated value of the byte from ; the third saved part ENDIF LDA (SC),Y ; Set A to the byte from the first part in SC(1 0) CMP SC2+1 ; If A = SC2+1 then jump to ctob5 to store A as our BEQ ctob5 ; commander file byte CMP SC2 ; If A = SC2 then jump to ctob5 to store A as our BEQ ctob5 ; commander file byte LDA SC2+1 ; Set A = SC2+1 CMP SC2 ; If A <> SC2 then the copy protection has failed, so BNE ctob9 ; jump to ctob9 to reset the save file ; Otherwise A = SC2, so we store A as our commander file ; byte .ctob5 STA BUF,Y ; Store A as the Y-th byte of our commander file in BUF STA (SC),Y ; Store A as the Y-th byte of the first part in SC(1 0) IF _NTSC EOR #$0F ; Flip the low nibble of A and store it in the third STA (S),Y ; part in S(1 0) EOR #$FF ; Flip the whole of A and store it in the second part in STA (Q),Y ; Q(1 0) ELIF _PAL ASL A ; Set the Y-th byte of the third saved part in S(1 0) to ADC #0 ; the commander file byte, rotated left in-place STA (S),Y ASL A ; Set the Y-th byte of the second saved part in Q(1 0) ADC #0 ; the commander file byte, rotated left in-place STA (Q),Y ENDIF DEY ; Decrement the byte counter in Y BPL ctob1 ; Loop back to ctob1 until we have fetched all 73 bytes ; of the commander file from the three separate parts ; If we get here then we have combined all three saved ; parts into one commander file in BUF, so now we need ; to set the galaxy seeds in bytes #65 to #70, as these ; are not saved in the three parts (as they can easily ; be reconstructed from the galaxy number in GCNT, which ; is what we do now) LDA BUF+17 ; Set A to byte #9 of the commander file, which contains ; the galaxy number (0 to 7) ASL A ; Set Y = A * 8 ASL A ; ASL A ; The galaxySeeds table has eight batches of seeds with TAY ; each one taking up eight bytes (the last two in each ; batch are zeroes), so we can use Y as an index into ; the table to fetch the seed bytes that we need LDX #0 ; We will put the first six galaxy seed bytes from the ; checksum table into our commander file, so set X = 0 ; to act as a commander file byte index .ctob6 LDA galaxySeeds,Y ; Set A to the next seed byte from batch Y STA BUF+73,X ; Store the seed byte in byte #65 + X INY ; Increment the seed byte index INX ; Increment the commander file byte index CPX #6 ; Loop back until we have copied all six seed bytes BNE ctob6 PLA ; Restore the value of A that we stored on the stack, so ; A is preserved RTS ; Return from the subroutine .ctob7 ; If we get here then A = 9, so this is the current ; commander on the left of the screen, so we load the ; currently active commander from NAME (which is where ; the game stores the commander we are currently ; playing) LDA SVC ; Clear bit 7 of the save counter so we can increment AND #%01111111 ; the save counter once again to record the next save STA SVC ; after this one LDX #78 ; We now copy the current commander file to the buffer ; in BUF, so set a counter in X to copy all 79 bytes of ; the file .ctob8 LDA NAME,X ; Copy the X-th byte of the current commander in NAME STA currentSlot,X ; to the X-th byte of BUF STA BUF,X ; ; This also copies the file to currentSlot, but this ; isn't used anywhere DEX ; Decrement the byte counter BPL ctob8 ; Loop back until we have copied all 79 bytes PLA ; Restore the value of A that we stored on the stack, so ; A is preserved RTS ; Return from the subroutine .ctob9 ; If we get here then the three parts of the save file ; have failed the checksums when being combined, so we ; reset the save file and its constituent parts as it ; looks like this file might have been tampered with JSR ResetSaveBuffer ; Reset the commander file in BUF to the default ; commander LDA #' ' ; We now fill the commander file name with spaces, so ; set A to the space character LDY #6 ; Set a counter in Y to fill the seven characters in the ; commander file name .ctob10 STA BUF,Y ; Set the Y-th byte of BUF to a space to blank out the ; name (which is seven characters long and at BUF) DEY ; Decrement the character counter BPL ctob10 ; Loop back until we have set the whole name to spaces LDA #0 ; Set the save count in byte #7 of the save file to 0 STA BUF+7 PLA ; Set A to the save slot number from the stack (leaving PHA ; the value on the stack) JSR SaveLoadCommander ; Save the commander into the chosen save slot by ; splitting it up and saving it into three parts in ; saveSlotPart1, saveSlotPart2 and saveSlotPart3, so the ; save slot gets reset to the default commander PLA ; Restore the value of A that we stored on the stack, so ; A is preserved RTS ; Return from the subroutine
Name: ResetSaveSlots [Show more] Type: Subroutine Category: Save and load Summary: Reset the save slots for all eight save slots, so they will fail their checksums and get reset when they are next checked
Context: See this subroutine on its own page References: This subroutine is called as follows: * ChooseLanguage calls ResetSaveSlots
.ResetSaveSlots LDX #7 ; There are eight save slots, so set a slot counter in X ; to loop through them all .rsav1 TXA ; Store the slot counter on the stack, copying the slot PHA ; number into A in the process JSR GetSaveAddresses ; Set the following for save slot A: ; ; SC(1 0) = address of the first saved part ; ; Q(1 0) = address of the second saved part ; ; S(1 0) = address of the third saved part ; We reset the save slot by writing to byte #10 in each ; of the three saved parts, so that this byte fails its ; checksum, meaning the save slot will be reset the next ; time it is checked in the CheckSaveSlots routine LDY #10 ; Set Y to use as an index to byte #10 LDA #1 ; Set byte #10 of the first saved part to 1 STA (SC),Y LDA #3 ; Set byte #10 of the second saved part to 3 STA (Q),Y LDA #7 ; Set byte #10 of the third saved part to 7 STA (S),Y PLA ; Retrieve the slot counter from the stack into X TAX DEX ; Decrement the slot counter BPL rsav1 ; Loop back until we have reset the three parts for all ; eight save slots RTS ; Return from the subroutine
Name: GetSaveAddresses [Show more] Type: Subroutine Category: Save and load Summary: Fetch the addresses of the three saved parts for a specific save slot
Context: See this subroutine on its own page References: This subroutine is called as follows: * CopyCommanderToBuf calls GetSaveAddresses * ResetSaveSlots calls GetSaveAddresses * SaveLoadCommander calls GetSaveAddresses

Arguments: A The number of the save slot
.GetSaveAddresses ASL A ; Set X = A * 2 TAX ; ; So we can use X as an index into the saveSlotAddr ; tables, which contain two-byte addresses LDA saveSlotAddr1,X ; Set the following: STA SC ; LDA saveSlotAddr2,X ; SC(1 0) = X-th address from saveSlotAddr1, i.e. the STA Q ; address of the first saved part for slot X LDA saveSlotAddr3,X ; STA S ; Q(1 0) = X-th address from saveSlotAddr2, i.e. the LDA saveSlotAddr1+1,X ; address of the second saved part for slot X STA SC+1 ; LDA saveSlotAddr2+1,X ; S(1 0) = X-th address from saveSlotAddr3, i.e. the STA Q+1 ; address of the third saved part for slot X LDA saveSlotAddr3+1,X STA S+1 RTS ; Return from the subroutine
Name: SaveLoadCommander [Show more] Type: Subroutine Category: Save and load Summary: Either save the commander from BUF into a save slot, or load the commander from BUF into the game and start the game
Context: See this subroutine on its own page References: This subroutine is called as follows: * CopyCommanderToBuf calls SaveLoadCommander * MoveInMiddleColumn calls SaveLoadCommander

Arguments: A The slot number to process: * 0 to 7 = save the current commander from BUF into save slot A * 9 = load the current commander from BUF into the game and start the game
Returns: A A is preserved
.SaveLoadCommander PHA ; Store the value of A on the stack so we can restore it ; at the end of the subroutine CMP #9 ; If A = 9 then this is the current commander in the BEQ scom2 ; left column, so jump to scom2 to load the commander ; in BUF into the game ; If we get here then this is one of the save slots on ; the right of the screen and A is in the range 0 to 7, ; so now we save the contents of BUF into the save slot ; ; Each save slot is split up into three parts, so we now ; need to split the commander file before saving them JSR GetSaveAddresses ; Set the following for save slot A: ; ; SC(1 0) = address of the first saved part ; ; Q(1 0) = address of the second saved part ; ; S(1 0) = address of the third saved part LDA BUF+7 ; Clear bit 7 of the save counter byte in the commander AND #%01111111 ; file at BUF so we can increment the save counter once STA BUF+7 ; again to record the next save after this one (the save ; counter is in the byte just after the commander name, ; which is seven characters long, so it's at BUF+7) LDY #72 ; We work our way through 73 bytes in each saved part, ; so set an index counter in Y .scom1 LDA BUF,Y ; Copy the Y-th byte of the commander file in BUF to the STA (SC),Y ; Y-th byte of the first saved part IF _NTSC EOR #$0F ; Set the Y-th byte of the third saved part in S(1 0) to STA (S),Y ; the commander file byte with the low nibble flipped EOR #$FF ; Set the Y-th byte of the second saved part in Q(1 0) STA (Q),Y ; to the commander file byte with both nibbles flipped ELIF _PAL ASL A ; Set the Y-th byte of the third saved part in S(1 0) to ADC #0 ; the commander file byte, rotated left in-place STA (S),Y ASL A ; Set the Y-th byte of the second saved part in Q(1 0) ADC #0 ; the commander file byte, rotated left in-place STA (Q),Y ENDIF DEY ; Decrement the byte counter in Y BPL scom1 ; Loop back to scom1 until we have split all 73 bytes ; of the commander file into the three separate parts PLA ; Restore the value of A that we stored on the stack, so ; A is preserved RTS ; Return from the subroutine PHA ; This instruction is never run, but it would allow this ; part of the subroutine to be called on its own by ; storing the value of A on the stack so we could ; restore it at the end of the subroutine .scom2 ; If we get here then A = 9, so this is the current ; commander on the left of the screen, so we set the ; currently active in-game commander in NAME to the ; commander in BUF LDX #78 ; Set a counter in X to copy all 79 bytes of the file .scom3 LDA BUF,X ; Copy the X-th byte of BUF to the X-th byte of the STA currentSlot,X ; current commander in NAME STA NAME,X ; ; This also copies the file to currentSlot, but this ; isn't used anywhere DEX ; Decrement the byte counter BPL scom3 ; Loop back until we have copied all 79 bytes JSR SetupAfterLoad_b0 ; Configure the game to use the newly loaded commander ; file PLA ; Restore the value of A that we stored on the stack, so ; A is preserved RTS ; Return from the subroutine
Name: CheckSaveSlots [Show more] Type: Subroutine Category: Save and load Summary: Load the commanders for all eight save slots, one after the other, to check their integrity and reset any that fail their checksums
Context: See this subroutine on its own page References: This subroutine is called as follows: * CheckSaveSlots_b6 calls CheckSaveSlots
.CheckSaveSlots LDA #7 ; There are eight save slots, so set a slot counter in ; A to loop through them all .sabf1 PHA ; Wait until the next NMI interrupt has passed (i.e. the JSR WaitForNMI ; next VBlank), preserving the value in A via the stack PLA JSR CopyCommanderToBuf ; Copy the commander file from save slot A into the ; buffer at BUF, resetting the save slot if the file ; fails its checksums SEC ; Decrement A to move on to the next save slot SBC #1 BPL sabf1 ; Loop back until we have loaded all eight save slots RTS ; Return from the subroutine
Name: NA2% [Show more] Type: Variable Category: Save and load Summary: The data block for the default commander
Context: See this variable on its own page References: This variable is used as follows: * JAMESON uses NA2% * ResetSaveBuffer uses NA2%
.NA2% EQUS "JAMESON" ; The current commander name, which defaults to JAMESON EQUB 1 ; SVC = Save count, which is stored in the terminator ; byte for the commander name EQUB 0 ; TP = Mission status, #0 EQUB 20 ; QQ0 = Current system X-coordinate (Lave), #1 EQUB 173 ; QQ1 = Current system Y-coordinate (Lave), #2 IF Q% EQUD &00CA9A3B ; CASH = Amount of cash (100,000,000 Cr), #3-6 ELSE EQUD &E8030000 ; CASH = Amount of cash (100 Cr), #3-6 ENDIF EQUB 70 ; QQ14 = Fuel level, #7 EQUB 0 ; COK = Competition flags, #8 EQUB 0 ; GCNT = Galaxy number, 0-7, #9 IF Q% EQUB Armlas ; LASER = Front laser, #10 ELSE EQUB POW+9 ; LASER = Front laser, #10 ENDIF EQUB (POW+9 AND Q%) ; LASER = Rear laser, #11 EQUB (POW+128) AND Q% ; LASER+2 = Left laser, #12 EQUB Mlas AND Q% ; LASER+3 = Right laser, #13 EQUB 22 + (15 AND Q%) ; CRGO = Cargo capacity, #14 EQUB 0 ; QQ20+0 = Amount of food in cargo hold, #15 EQUB 0 ; QQ20+1 = Amount of textiles in cargo hold, #16 EQUB 0 ; QQ20+2 = Amount of radioactives in cargo hold, #17 EQUB 0 ; QQ20+3 = Amount of slaves in cargo hold, #18 EQUB 0 ; QQ20+4 = Amount of liquor/Wines in cargo hold, #19 EQUB 0 ; QQ20+5 = Amount of luxuries in cargo hold, #20 EQUB 0 ; QQ20+6 = Amount of narcotics in cargo hold, #21 EQUB 0 ; QQ20+7 = Amount of computers in cargo hold, #22 EQUB 0 ; QQ20+8 = Amount of machinery in cargo hold, #23 EQUB 0 ; QQ20+9 = Amount of alloys in cargo hold, #24 EQUB 0 ; QQ20+10 = Amount of firearms in cargo hold, #25 EQUB 0 ; QQ20+11 = Amount of furs in cargo hold, #26 EQUB 0 ; QQ20+12 = Amount of minerals in cargo hold, #27 EQUB 0 ; QQ20+13 = Amount of gold in cargo hold, #28 EQUB 0 ; QQ20+14 = Amount of platinum in cargo hold, #29 EQUB 0 ; QQ20+15 = Amount of gem-stones in cargo hold, #30 EQUB 0 ; QQ20+16 = Amount of alien items in cargo hold, #31 EQUB Q% ; ECM = E.C.M. system, #32 EQUB Q% ; BST = Fuel scoops ("barrel status"), #33 EQUB Q% AND 127 ; BOMB = Energy bomb, #34 EQUB Q% AND 1 ; ENGY = Energy/shield level, #35 EQUB Q% ; DKCMP = Docking computer, #36 EQUB Q% ; GHYP = Galactic hyperdrive, #37 EQUB Q% ; ESCP = Escape pod, #38 EQUW 0 ; TRIBBLE = Number of Trumbles in the cargo hold, #39-40 EQUB 0 ; TALLYL = Combat rank fraction, #41 EQUB 3 + (Q% AND 1) ; NOMSL = Number of missiles, #42 EQUB 0 ; FIST = Legal status ("fugitive/innocent status"), #43 EQUB 16 ; AVL+0 = Market availability of food, #44 EQUB 15 ; AVL+1 = Market availability of textiles, #45 EQUB 17 ; AVL+2 = Market availability of radioactives, #46 EQUB 0 ; AVL+3 = Market availability of slaves, #47 EQUB 3 ; AVL+4 = Market availability of liquor/Wines, #48 EQUB 28 ; AVL+5 = Market availability of luxuries, #49 EQUB 14 ; AVL+6 = Market availability of narcotics, #50 EQUB 0 ; AVL+7 = Market availability of computers, #51 EQUB 0 ; AVL+8 = Market availability of machinery, #52 EQUB 10 ; AVL+9 = Market availability of alloys, #53 EQUB 0 ; AVL+10 = Market availability of firearms, #54 EQUB 17 ; AVL+11 = Market availability of furs, #55 EQUB 58 ; AVL+12 = Market availability of minerals, #56 EQUB 7 ; AVL+13 = Market availability of gold, #57 EQUB 9 ; AVL+14 = Market availability of platinum, #58 EQUB 8 ; AVL+15 = Market availability of gem-stones, #59 EQUB 0 ; AVL+16 = Market availability of alien items, #60 EQUB 0 ; QQ26 = Random byte that changes for each visit to a ; system, for randomising market prices, #61 EQUW 20000 AND Q% ; TALLY = Number of kills, #62-63 EQUB 128 ; This byte appears to be unused, #64 EQUW $5A4A ; QQ21 = Seed s0 for system 0, galaxy 0 (Tibedied), #65 EQUW $0248 ; QQ21 = Seed s1 for system 0, galaxy 0 (Tibedied), #67 EQUW $B753 ; QQ21 = Seed s2 for system 0, galaxy 0 (Tibedied), #69 EQUB $AA ; This byte appears to be unused, #71 EQUB $27 ; This byte appears to be unused, #72 EQUB $03 ; This byte appears to be unused, #73 EQUD 0 ; These bytes appear to be unused, #74-#85 EQUD 0 EQUD 0 EQUD 0
Name: ResetCommander [Show more] Type: Subroutine Category: Save and load Summary: Reset the current commander to the default "JAMESON" commander
Context: See this subroutine on its own page References: This subroutine is called as follows: * ResetCommander_b6 calls ResetCommander
.ResetCommander JSR JAMESON ; Copy the default "JAMESON" commander to the buffer at ; currentSlot LDX #79 ; We now want to copy 78 bytes from the buffer at ; currentSlot to the current commander at NAME, so ; set a byte counter in X (which counts down from 79 to ; 1 as we copy bytes 78 to 0) .resc1 LDA currentSlot-1,X ; Copy byte X-1 from currentSlot to byte X-1 of NAME STA NAME-1,X DEX ; Decrement the byte counter BNE resc1 ; Loop back until we have copied all 78 bytes RTS ; Return from the subroutine
Name: JAMESON [Show more] Type: Subroutine Category: Save and load Summary: Copy the default "JAMESON" commander to the buffer at currentSlot
Context: See this subroutine on its own page References: This subroutine is called as follows: * JAMESON_b6 calls JAMESON * ResetCommander calls JAMESON
.JAMESON LDY #94 ; We want to copy 94 bytes from the default commander ; at NA2% to the buffer at currentSlot, so set a byte ; counter in Y .jame1 LDA NA2%,Y ; Copy the Y-th byte of NA2% to the Y-th byte of STA currentSlot,Y ; currentSlot DEY ; Decrement the byte counter BPL jame1 ; Loop back until we have copied all 94 bytes RTS ; Return from the subroutine
Name: DrawLightning [Show more] Type: Subroutine Category: Flight Summary: Draw a lightning effect for the launch tunnel and E.C.M. that consists of two random lightning bolts, one above the other
Context: See this subroutine on its own page References: This subroutine is called as follows: * DrawLightning_b6 calls DrawLightning

Arguments: K Half the width of the rectangle containing the lightning K+1 Half the height of the rectangle containing the lightning K+2 The x-coordinate of the centre of the lightning K+3 The y-coordinate of the centre of the lightning
.DrawLightning ; The rectangle is split into a top half and a bottom ; half, with a bolt in the top half and a bolt in the ; bottom half, and we draw each bolt in turn LDA K+1 ; Set XX2+1 = K+1 / 2 LSR A ; STA XX2+1 ; So XX2+1 contains a quarter of the height of the ; rectangle containing the lightning LDA K+3 ; Set K3 = K+3 - XX2+1 + 1 SEC ; SBC XX2+1 ; So K3 contains the y-coordinate of the centre of the CLC ; top lightning bolt (i.e. the invisible horizontal line ADC #1 ; through the centre of the top bolt) STA K3 JSR lite1 ; Call lite1 below to draw the top lightning bolt along ; a centre line at y-coordinate K+3 LDA K+3 ; Set K3 = K+3 + XX2+1 CLC ; ADC XX2+1 ; So K3 contains the y-coordinate of the centre of the STA K3 ; bottom lightning bolt (i.e. the invisible horizontal ; line through the centre of the bottom bolt) ; Fall through into lite1 to draw the second lightning ; bolt along a centre line at y-coordinate K+3 .lite1 ; We now draw a lightning bolt along an invisible centre ; line at y-coordinate K+3 LDA K ; Set STP = K / 4 LSR A ; LSR A ; As K is the half-width of the rectangle containing the STA STP ; lightning, this means STP is 1/8 of the width of the ; lightning rectangle ; ; We use this value to step along the rectangle from ; left to right, so we can draw the lightning bolt in ; eight equal-width segments LDA K+2 ; Set X1 = K+2 - K SEC ; SBC K ; So X1 contains the x-coordinate of the left edge of STA X1 ; the rectangle containing the lightning bolt LDA K3 ; Set Y1 = K3 STA Y1 ; ; So Y1 contains the y-coordinate of the centre of the ; lightning bolt, and (X1, Y1) therefore contains the ; pixel coordinate of the left end of the lightning bolt LDY #7 ; We now draw eight segments of lightning, zig-zagging ; above and below the invisible centre line at ; y-coordinate K3 .lite2 JSR DORND ; Set Q to a random number in the range 0 to 255 STA Q LDA K+1 ; Set A to K+1, which is half the height of the ; rectangle containing the lightning, which is the same ; as the full height of the rectangle containing the ; lightning bolt we are drawing JSR FMLTU ; Set A = A * Q / 256 ; = K+1 * rand / 256 ; ; So A is a random number in the range 0 to the maximum ; height of the lightning bolt we are drawing CLC ; Set Y2 = K3 + A - XX2+1 ADC K3 ; SEC ; In the above, K3 is the y-coordinate of the centre of SBC XX2+1 ; the lightning bolt, XX2+1 contains half the height of STA Y2 ; the lightning bolt, and A is a random number between 0 ; and the height of the lightning bolt, so this sets Y2 ; to a y-coordinate that is centred on the centre line ; of the lightning bolt, and is a random distance above ; or below the line, and which fits within the height of ; the lightning bolt ; ; We can therefore use this as the y-coordinate of the ; next point along the zig-zag of the lightning bolt LDA X1 ; Set X2 = X1 + STP CLC ; ADC STP ; So X2 is the x-coordinate of the next point along the STA X2 ; lightning bolt, and (X2, Y2) is therefore the next ; point along the lightning bolt JSR LOIN ; Draw a line from (X1, Y1) to (X2, Y2) to draw the next ; segment of the bolt LDA SWAP ; If SWAP is non-zero then we already swapped the line BNE lite3 ; coordinates around during the drawing process, so we ; can jump to lite3 to skip the following coordinate ; swap LDA X2 ; Set (X1, Y1) to (X2, Y2), so (X1, Y1) contains the new STA X1 ; end coordinates of the lightning bolt, now that we LDA Y2 ; just drawn another segment of the bolt STA Y1 .lite3 DEY ; Decrement the segment counter in Y BNE lite2 ; Loop back to draw the next segment until we have drawn ; seven of them ; We finish off by drawing the final segment, which we ; draw from the current end of the zig-zag to the right ; end of the invisible horizontal line through the ; centre of the bolt, so the bolt starts and ends at ; this height LDA K+2 ; Set X2 = K+2 + K CLC ; ADC K ; So X2 contains the x-coordinate of the right edge of STA X2 ; the rectangle containing the lightning LDA K3 ; Set Y2 = K3 STA Y2 ; ; So Y2 contains the y-coordinate of the centre of the ; lightning bolt, and (X2, Y2) therefore contains the ; pixel coordinate of the right end of the lightning ; bolt JSR LOIN ; Draw a line from (X1, Y1) to (X2, Y2) to draw the ; final segment of the bolt RTS ; Return from the subroutine
Name: LL164 [Show more] Type: Subroutine Category: Flight Summary: Make the hyperspace sound and draw the hyperspace tunnel
Context: See this subroutine on its own page References: This subroutine is called as follows: * LL164_b6 calls LL164

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.
.LL164 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 JSR HideStardust ; Hide the stardust sprites JSR HideExplosionBurst ; Hide the four sprites that make up the explosion burst JSR MakeHyperSound ; Make the hyperspace sound LDA #128 ; This value is not used in the following, so this has STA K+2 ; no effect LDA #72 ; This value is not used in the following, so this has STA K+3 ; no effect LDA #64 ; Set XP to use as a counter for each frame of the STA XP ; hyperspace effect, so we run the following loop 64 ; times for an animation of 64 frames ; We now draw 64 frames of hyperspace effect, looping ; back to hype1 for each new frame .hype1 JSR CheckPauseButton ; Check whether the pause button has been pressed or an ; icon bar button has been chosen, and process pause or ; unpause if a pause-related button has been pressed JSR DORND ; Set X to a random number between 0 and 15 AND #15 TAX LDA hyperspaceColour,X ; Set the visible colour to entry number X from the STA visibleColour ; hyperspaceColour table, so this sets the hyperspace ; colour randomly to one of the colours in the table JSR FlipDrawingPlane ; Flip the drawing bitplane so we draw into the bitplane ; that isn't visible on-screen LDA XP ; Set STP = XP mod 32 AND #31 ; STA STP ; So over the course of the 64 iterations around the ; loop, STP starts at 0, then counts down from 31 to 0, ; and then counts down from 31 to 1 again ; ; The higher the value of STP, the closer together the ; lines in the hyperspace effect, so this makes the ; lines move further away as the effect progresses, ; giving a feeling of moving through hyperspace LDA #8 ; Set X1 = 8 so we draw horizontal lines from STA X1 ; x-coordinate 8 on the left of the screen LDA #248 ; Set X2 = 248 so we draw horizontal lines to STA X2 ; x-coordinate 248 on the right of the screen ; We now draw the lines in the hyperspace effect (with ; lines in the top half of the screen and the same ; lines, reflected, in the bottom half), looping back ; to hype2 for each new line ; ; STP gets incremented by 16 for each line, so STP is ; set to the starting point (in the range 0 to 31), plus ; 16 for the first line, plus 32 for the second line, ; and so on until we get to 90, at which point we stop ; drawing lines for this frame ; ; As STP increases, the lines get closer to the middle ; of the screen, so this loop draws the lines, starting ; with the lines furthest from the centre and working in ; towards the centre .hype2 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 STP ; Set STP = STP + 16 CLC ; ADC #16 ; And set A to the new value of STP STA STP CMP #90 ; If A >= 90, jump to hype3 to move on to the next frame BCS hype3 ; (so we stop drawing lines in this frame) STA Q ; Set Q to the new value of STP ; We now calculate how far this horizontal line is from ; the centre of the screen in a vertical direction, with ; the result being lines that are closer together, the ; closer they are to the centre ; ; We space out the lines using a reciprocal algorithm, ; where the distance of line n from the centre is ; proportional to 1/n, so the lines get spaced roughly ; in the proportions of 1/2, 1/3, 1/4, 1/5 and so on, so ; the lines bunch closer together as n increases ; ; STP also includes the iteration number, modded so it ; runs from 31 to 0, so over the course of the animation ; the lines move away from the centre line, as the ; iteration decreases and the value of R below increases LDA #8 ; Set A = 8 to use in the following division JSR LL28 ; Call LL28 to calculate: ; ; R = 256 * A / Q ; = 256 * 8 / STP ; ; So R is the vertical distance of the current line from ; the centre of the screen ; ; The minimum value of STP is 16 and the maximum is 89 ; (the latter being enforced by the comparison above), ; so R ranges from 128 to 23 LDA R ; Set K+1 = R - 20 SEC ; SBC #20 ; This sets the range of values in K+1 to 108 to 3 STA K+1 ; We can now use K+1 as the vertical distance of this ; line from the centre of the screen, to give us an ; effect where the horizontal lines spread out as they ; get away from the centre, and which move away from the ; centre as the animation progresses, with the movement ; being bigger the further away the line ; ; We now draw this line twice, once above the centre and ; once below the centre, so the lines in the top and ; bottom parts of the screen are mirrored, and the ; overall effect is of hyperspacing forwards, sandwiched ; between two horizontal planes, one above and one below LDA halfScreenHeight ; Set A = halfScreenHeight - K+1 SBC K+1 ; ; So A is the y-coordinate of the line in the top half ; of the screen BCC hype2 ; If A <= 0 then the line is off the top of the screen, BEQ hype2 ; so jump to hype2 to move on to the next line TAY ; Set Y = A, to use as the y-coordinate for this line ; in the hyperspace effect JSR HLOIN ; Draw a horizontal line from (X1, Y) to (X2, Y) INC X2 ; The HLOIN routine decrements X2, so increment it back ; to its original value LDA K+1 ; Set A = halfScreenHeight + K+1 CLC ; ADC halfScreenHeight ; So A is the y-coordinate of the line in the bottom ; half of the screen TAY ; Set Y = A, to use as the y-coordinate for this line ; in the hyperspace effect JSR HLOIN ; Draw a horizontal line from (X1, Y) to (X2, Y) INC X2 ; The HLOIN routine decrements X2, so increment it back ; to its original value JMP hype2 ; Loop back to hype2 to draw the next horizontal line ; in this iteration .hype3 JSR DrawBitplaneInNMI ; Configure the NMI to send the drawing bitplane to the ; PPU after drawing the box edges and setting the next ; free tile number DEC XP ; Decrement the frame counter in XP BNE hype1 ; Loop back to hype1 to draw the next frame of the ; animation, until the frame counter runs down to 0 JMP 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, ; and return from the subroutine using a tail call
Name: hyperspaceColour [Show more] Type: Variable Category: Flight Summary: The different colours that can be used for the hyperspace effect
Context: See this variable on its own page References: This variable is used as follows: * LL164 uses hyperspaceColour
.hyperspaceColour EQUB $06 ; Dark red EQUB $0F ; Black EQUB $38 ; Pale yellow EQUB $2A ; Light green EQUB $23 ; Light violet EQUB $25 ; Light rose EQUB $22 ; Light blue EQUB $11 ; Medium azure EQUB $1A ; Medium green EQUB $00 ; Dark grey EQUB $26 ; Light red EQUB $2C ; Light cyan EQUB $20 ; White EQUB $13 ; Medium violet EQUB $0F ; Black EQUB $00 ; Dark grey
Name: DrawLaunchBox [Show more] Type: Subroutine Category: Flight Summary: Draw a box as part of the launch tunnel animation
Context: See this subroutine on its own page References: This subroutine is called as follows: * DrawLaunchBox_b6 calls DrawLaunchBox

Arguments: K Half the width of the box K+1 Half the height of the box K+2 The x-coordinate of the centre of the box K+3 The y-coordinate of the centre of the box
.lbox1 RTS ; Return from the subroutine .DrawLaunchBox LDA K+2 ; Set A = K+2 + K CLC ; ADC K ; So A contains the x-coordinate of the right edge of ; the box (i.e. the centre plus half the width) BCS lbox1 ; If the addition overflowed, then the right edge of the ; box is past the right edge of the screen, so jump to ; lbox1 to return from the subroutine without drawing ; any lines STA X2 ; Set X2 to A, to the x-coordinate of the right edge of ; the box STA X1 ; Set X1 to A, to the x-coordinate of the right edge of ; the box LDA K+3 ; Set A = K+3 - K+1 SEC ; SBC K+1 ; So A contains the y-coordinate of the top edge of the ; box (i.e. the centre minus half the height) BCS lbox2 ; If the subtraction underflowed, then the top edge of ; the box is above the top edge of the screen, so jump ; to lbox2 to skip the following LDA #0 ; Set A = 0 to clip the result to the top of the space ; view .lbox2 STA Y1 ; Set Y1 to A, so (X1, Y1) is the coordinate of the ; top-right corner of the box LDA K+3 ; Set A = K+3 + K+1 CLC ; ADC K+1 ; So A contains the y-coordinate of the bottom edge of ; the box (i.e. the centre plus half the height) BCS lbox3 ; If the addition overflowed, then the y-coordinate is ; off the bottom of the screen, so jump to lbox3 to skip ; the following check (though this is slightly odd, as ; this leaves A set to the y-coordinate of the bottom ; edge, wrapped around with a mod 256, which is unlikely ; to be what we want, so should this be a jump to lbox1 ; to return from the subroutine instead?) CMP Yx2M1 ; If A < Yx2M1 then the y-coordinate is within the BCC lbox3 ; space view (as Yx2M1 is the y-coordinate of the bottom ; pixel row of the space view), so jump to lbox3 to skip ; the following instruction LDA Yx2M1 ; Set A = Yx2M1 to clip the result to the bottom of the ; space view .lbox3 STA Y2 ; Set Y2 to A, so (X1, Y2) is the coordinate of the ; bottom-right corner of the box ; By the time we get here, (X1, Y1) is the coordinate ; of the top-right corner of the box, and (X1, Y2) is ; the coordinate of the bottom-right corner of the box JSR DrawVerticalLine ; Draw a vertical line from (X1, Y1) to (X1, Y2), to ; draw the right edge of the box LDA K+2 ; Set A = K+2 - K SEC ; SBC K ; So A contains the x-coordinate of the left edge of ; the box (i.e. the centre minus half the width) BCC lbox1 ; If the subtraction underflowed, then the left edge of ; the box is past the left edge of the screen, so jump ; to lbox1 to return from the subroutine without drawing ; any more lines STA X1 ; Set X1 to A, to the x-coordinate of the left edge of ; the box ; By the time we get here, (X1, Y1) is the coordinate ; of the top-left corner of the box, and (X1, Y2) is ; the coordinate of the bottom-left corner of the box JSR DrawVerticalLine ; Draw a vertical line from (X1, Y1) to (X1, Y2), to ; draw the left edge of the box ; We now move on to drawing the top and bottom edges INC X1 ; Increment the x-coordinate in X1 so the top box edge ; starts with the pixel to the right of the left edge LDY Y1 ; Set Y to the y-coordinate in Y1, which is the ; y-coordinate of the top edge of the box BEQ lbox4 ; If Y = 0 then skip the following, so we don't draw ; the top edge if it's on the very top pixel line of ; the screen JSR HLOIN ; Draw a horizontal line from (X1, Y) to (X2, Y) to draw ; the top edge of the box INC X2 ; The HLOIN routine decrements X2, so increment it back ; to its original value .lbox4 DEC X1 ; Decrement the x-coordinate in X1 so the bottom edge ; starts at the same x-coordinate as the left edge INC X2 ; Increment the x-coordinate in X1 so the bottom edge ; ends with the pixel to the left of the right edge LDY Y2 ; Set Y to the y-coordinate in Y2, which is the ; y-coordinate of the bottom edge of the box CPY Yx2M1 ; If Y >= Yx2M1 then the y-coordinate is below the BCS lbox1 ; bottom of the space view (as Yx2M1 is the y-coordinate ; of the bottom pixel row of the space view), so jump to ; lbox1 to return from the subroutine without drawing ; the bottom edge JMP HLOIN ; Draw a horizontal line from (X1, Y) to (X2, Y) to draw ; the bottom edge of the box, returning from the ; subroutine using a tail call
Name: InputName [Show more] Type: Subroutine Category: Controllers Summary: Get a name from the controller for searching the galaxy or changing commander name
Context: See this subroutine on its own page References: This subroutine is called as follows: * ChangeCmdrName calls InputName * InputName_b6 calls InputName

Arguments: INWK+5 The current name inputNameSize The maximum size of the name to fetch - 1
Returns: INWK+5 The entered name, terminated by ASCII 13 C flag The status of the entered name: * Set = The name is empty * Clear = The name is not empty
.InputName LDY #0 ; Set an index in Y to point to the letter within the ; name that we are entering, starting with the first ; letter at index 0 ; The currently entered name is at INWK+5, so we use ; that to provide the starting point for each letter ; (or we start at "A" if there is no currently entered ; name) .name1 LDA INWK+5,Y ; Fetch the Y-th character of the currently entered ; name at INWK+5 CMP #'A' ; If the character is ASCII "A" or greater, jump to BCS name2 ; name2 to use this as the starting point for this ; letter LDA #'A' ; Otherwise set A to the letter "A" to use as the ; starting point .name2 PHA ; These instructions together have no effect PLA JSR ChangeLetter ; Call ChangeLetter to allow us to move up or down ; through the alphabet, returning with the letter ; selected in A BCS name4 ; If the C flag was set by ChangeLetter then the A ; button was pressed, so jump to name4 to finish the ; process as this means we have finished entering the ; name ; Otherwise we now check whether the chosen character ; is valid CMP #27 ; If ChangeLetter returned an ASCII ESC character, jump BEQ name5 ; to name5 to return from the subroutine with an empty ; name and the C flag set CMP #127 ; If ChangeLetter returned an ASCII DEL character, jump BEQ name6 ; to name6 to delete the character to the left CPY inputNameSize ; If Y >= inputNameSize then the entered name is too BCS name3 ; long, so jump to name3 to give an error beep and try ; again CMP #'!' ; If A < ASCII "!" then it is a control character, so BCC name3 ; jump to name3 to give an error beep and try again CMP #'{' ; If A >= ASCII "{" then it is not a valid character, so BCS name3 ; jump to name3 to give an error beep and try again ; If we get here then the chosen character is valid STA INWK+5,Y ; Store the chosen character in the Y-th position in the ; string at INWK+5 INY ; Increment the index in Y to point to the next letter INC XC ; Move the text cursor to the right by one place JMP name1 ; Loop back to name1 to fetch the next letter .name3 ; If we get here then there are too many characters in ; the string, or the entered character is not a valid ; letter JSR BEEP_b7 ; Call the BEEP subroutine to make a short, high beep to ; indicate an error LDY inputNameSize ; Set Y to the maximum length of the string, so when we ; loop back to name1, we ask for the last letter again JMP name1 ; Loop back to name1 to fetch the next letter .name4 ; If we get here then we have finished entering the name STA INWK+5,Y ; Store the chosen character in the Y-th position in the ; string at INWK+5 INY ; Increment the index in Y to point to the next letter LDA #13 ; Store the string terminator in the next letter, so the STA INWK+5,Y ; entered string is terminated properly LDA #12 ; Print a newline JSR CHPR_b2 JSR DrawMessageInNMI ; Configure the NMI to display the message that we just ; printed CLC ; Clear the C flag to indicate that a name has ; successfully been entered RTS ; Return from the subroutine .name5 LDA #13 ; Store the string terminator in the first letter, so STA INWK+5 ; the returned string is empty SEC ; Set the C flag to indicate that a valid name has not ; been entered RTS ; Return from the subroutine .name6 ; If we get here then we need to delete the character to ; the left of the current letter TYA ; If Y = 0 then we are still on the first letter, so BEQ name7 ; jump to name7 to given an error beep, as we can't ; delete past the start of the name DEY ; Decrement the length of the current name in Y, so the ; next character we enter replaces the one we are ; deleting LDA #127 ; Print a delete character to delete the letter to the JSR CHPR_b2 ; left LDA INWK+5,Y ; Set A to the character before the one we just deleted, ; as that's the current character now JMP name2 ; Loop back to name2 to keep scanning for button presses .name7 ; If we get here then we need to give an error beep, as ; we just tried to delete past the start of the name JSR BEEP_b7 ; Call the BEEP subroutine to make a short, high beep to ; indicate an error LDY #0 ; Set Y = 0 to set the current character to the start of ; the name BEQ name1 ; Loop back to name1 to fetch the next letter (this BEQ ; is effectively a JMP, as Y is always zero)
Name: ChangeLetter [Show more] Type: Subroutine Category: Controllers Summary: Choose a letter using the up and down buttons
Context: See this subroutine on its own page References: This subroutine is called as follows: * InputName calls ChangeLetter

Arguments: A The letter to start on
Returns: A The chosen letter C flag The status of the A button: * Set = the A button was pressed to finish entering the string * Clear = the A button was not pressed
.ChangeLetter TAX ; Set X to the starting letter STY YSAV ; Store Y in YSAV so we can retrieve it below LDA fontStyle ; Store the current font style on the stack, so we can PHA ; restore it when we return from the subroutine LDA QQ11 ; If bit 5 of the view type in QQ11 is clear, then the AND #%00100000 ; normal font is not loaded, so jump to lett1 to skip BEQ lett1 ; the following instruction LDA #1 ; Set the font style to print in the normal font STA fontStyle .lett1 TXA ; Set A to the starting letter .lett2 PHA ; Store the current letter in A on the stack so we can ; retrieve it below LDY #4 ; Wait until four NMI interrupts have passed (i.e. the JSR DELAY ; next four VBlanks) PLA ; Set A to the current letter, leaving a copy of it on PHA ; the stack JSR CHPR_b2 ; Print the character in A DEC XC ; Move the text cursor left by one character, so it is ; the correct column for the letter we just printed JSR DrawMessageInNMI ; Configure the NMI to display the message that we just ; printed SEC ; Set the C flag to return from the subroutine if the ; following check shows that the A button was pressed, ; in which case we have finished entering letters LDA controller1A ; If the A button on controller 1 is being pressed, jump BMI lett5 ; to lett5 to return from the subroutine with the C flag ; set and the current letter as the chosen letter CLC ; Clear the C flag to indicate that the A button was not ; pressed PLA ; Set A to the current letter, which we stored on the ; stack above LDX controller1B ; If the B button on controller 1 is being pressed, loop BMI lett2 ; back to lett2 to keep scanning for button presses, as ; the arrow buttons have a different meaning when the B ; button is also held down LDX iconBarChoice ; If an icon has been chosen from the icon bar, jump to BNE lett7 ; lett7 to return from the subroutine with a value of ; 27 (ESC, or escape) and the C flag clear LDX controller1Left03 ; If the left button on controller 1 was being held down BMI lett4 ; four VBlanks ago, jump to lett4 to return from the ; subroutine with a value of 127 (DEL, or delete) and ; the C flag clear LDX controller1Right03 ; If the right button on controller 1 was being held BMI lett6 ; down four VBlanks ago, jump to lett6 to return from ; the subroutine with the C flag clear LDX controller1Up ; If the up button on controller 1 is not being pressed, BPL lett3 ; jump to lett3 to move on to the next button ; If we get here then the up button is being pressed CLC ; Increment the current character in A ADC #1 CMP #'Z'+1 ; If A is still a letter in the range "A" to "Z", then BNE lett3 ; jump to lett3 to skip the following LDA #'A' ; Set A to ASCII "A" so we wrap round to the start of ; the alphabet .lett3 LDX controller1Down ; If the down button on controller 1 is not being BPL lett2 ; pressed, loop back to lett2 to keep scanning for ; button presses ; If we get here then the down button is being pressed SEC ; Decrement the current character in A SBC #1 CMP #'A'-1 ; If A is still a letter in the range "A" to "Z", then BNE lett2 ; look back to lett2 to keep scanning for button presses LDA #'Z' ; Set A to ASCII "Z" so we wrap round to the end of ; the alphabet BNE lett2 ; Loop back to lett2 to keep scanning for button presses ; (this BNE is effectively a JMP as A is never zero) .lett4 ; If we get here then the left button is being pressed LDA #127 ; Set A to the ASCII code for DEL, or delete BNE lett6 ; Jump to lett6 to return from the subroutine (this BNE ; is effectively a JMP as A is never zero) .lett5 PLA ; Set A to the current letter, which we stored on the ; stack above .lett6 TAX ; Store the chosen letter in X so we can retrieve it ; below PLA ; Restore the font style that we stored on the stack STA fontStyle ; so it's unchanged by the routine LDY YSAV ; Retrieve the value of Y we stored above TXA ; Restore the chosen letter from X into A so we can ; return it RTS ; Return from the subroutine .lett7 ; If we get here then an icon bar button has been ; chosen, so we need to abort the letter choosing ; process LDA #27 ; Set A to the ASCII code for ESC, or escape BNE lett6 ; Jump to lett6 to return from the subroutine (this BNE ; is effectively a JMP as A is never zero)
Name: ChangeCmdrName [Show more] Type: Subroutine Category: Save and load Summary: Process changing the commander name
Context: See this subroutine on its own page References: This subroutine is called as follows: * ChangeCmdrName_b6 calls ChangeCmdrName
.ChangeCmdrName 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 INC YC ; Move the text cursor to row 22 LDA #8 ; Print extended token 8 ("{single cap}NEW NAME: ") JSR DETOK_b2 LDY #6 ; We start by copying the current commander's name from ; NAME to the buffer at INWK+5, which is where the ; InputName routine expects to find the current name to ; edit, so set a counter in Y for seven characters STY inputNameSize ; Set inputNameSize = 6 so we fetch a name with a ; maximum size of 7 characters in the call to InputName ; below .cnme1 LDA NAME,Y ; Copy the Y-th character from NAME to the Y-th STA INWK+5,Y ; character of the buffer at INWK+5 DEY ; Decrement the loop counter BPL cnme1 ; Loop back until we have copied all seven characters ; of the name JSR InputName ; Get a new commander name from the controller into ; INWK+5, where the name will be terminated by ASCII 13 LDA INWK+5 ; If the first character of the entered name is ASCII 13 CMP #13 ; then no name was entered, so jump to cnme5 to return BEQ cnme5 ; from the subroutine LDY #0 ; Otherwise we now calculate the length of the entered ; name by working along the entered string until we find ; the ASCII 13 character, so set a length counter in Y ; to store the name length as we loop through the name .cnme2 LDA INWK+5,Y ; If the Y-th character of the name is ASCII 13 then we CMP #13 ; have found the end of the name, so jump to cnme6 to BEQ cnme6 ; pad out the rest of the name with spaces before ; returning to cnme3 below INY ; Otherwise increment the counter in Y to move along by ; one character CPY #7 ; If Y <> 7 then we haven't gone past the seventh BNE cnme2 ; character yet (the commander name has a maximum length ; of 7), so loop back to check the next character DEY ; Otherwise Y = 7 and we just went past the end of the ; name, so decrement Y to a value of 6 so we can use it ; as a counter in the following loop ; We now copy the name that was entered into the current ; commander file at NAME, to change the commander name .cnme3 LDA INWK+5,Y ; Copy the Y-th character from INWK+5 to the Y-th STA NAME,Y ; character of NAME DEY ; Decrement the loop counter BPL cnme3 ; Loop back until we have copied all seven characters ; of the name (leaving Y with a value of -1) ; We now check whether the entered name matches the ; cheat commander name for the chosen language, and if ; it does, we apply cheat mode LDA COK ; If bit 7 of COK is set, then cheat mode has already BMI cnme5 ; been applied, so jump to cnme5 INY ; Set Y = 0 so we can loop through the entered name, ; checking each character against the cheat name LDX languageIndex ; Set X to the index of the chosen language, so this is ; the index of the first character of the cheat name for ; the chosen language, as the table at cheatCmdrName ; interleaves the characters from each of the four ; languages so that the cheat name for language X starts ; at cheatCmdrName + X, with each character being four ; bytes on from the previous one ; ; Presumably this is an attempt to hide the cheat names ; from anyone casually browsing through the game binary .cnme4 LDA NAME,Y ; Set A to the Y-th character of the new commander name CMP cheatCmdrName,X ; If the character in A does not match the X-th BNE cnme5 ; character of the cheat name for the chosen language, ; jump to cnme5 to skip applying cheat mode INX ; Set X = X + 4 INX ; INX ; So X now points to the next character of the cheat INX ; name for the chosen language INY ; Increment Y to move on to the next character in the ; name CPY #7 ; Loop back to check the next character until we have BNE cnme4 ; checked all seven characters ; If we get here then the new commander name matches the ; cheat name for the chosen language (so if this is ; English, then the new name is "CHEATER", for example), ; so now we apply cheat mode LDA #%10000000 ; Set bit 7 of COK to record that cheat mode has been STA COK ; applied to this commander, so we can't apply it again, ; and we can't change our commander name either (so once ; you cheat, you have to own it) LDA #$A0 ; Set CASH(0 1 2 3) = CASH(0 1 2 3) + &000186A0 CLC ; ADC CASH+3 ; So this adds 100000 to our cash reserves, giving us STA CASH+3 ; an extra 10,000.0 credits LDA #$86 ADC CASH+2 STA CASH+2 LDA CASH+1 ADC #1 STA CASH+1 LDA CASH ADC #0 STA CASH .cnme5 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 JMP DrawMessageInNMI ; Configure the NMI to update the in-flight message part ; of the screen (which is the same as the part that the ; call to CLYNS just cleared), returning from the ; subroutine using a tail call .cnme6 ; If we get here then the entered name does not use all ; seven characters, so we pad the name out with spaces ; ; We get here with Y set to the index of the ASCII 13 ; string terminator, so we can simply fill from that ; position to the end of the string LDA #' ' ; Set the Y-th character of the name at INWK+5 to a STA INWK+5,Y ; space CPY #6 ; If Y = 6 then we have reached the end of the string, BEQ cnme3 ; so jump to cnme3 with Y = 6 to continue processing the ; new name INY ; Increment Y to point to the next character along BNE cnme6 ; Jump back to cnme6 to keep filling the name with ; spaces (this BNE is effectively a JMP as Y is never ; zero)
Name: cheatCmdrName [Show more] Type: Variable Category: Save and load Summary: The commander name that triggers cheat mode in each language
Context: See this variable on its own page References: This variable is used as follows: * ChangeCmdrName uses cheatCmdrName
.cheatCmdrName EQUS "CBTI" ; English = "CHEATER" (column 1) EQUS "HERN" ; EQUS "ETIG" ; German = "BETRUG" (column 2) EQUS "ARCA" ; EQUS "TUHN" ; French = "TRICHER" (column 3) EQUS "EGEN" ; EQUS "R RO" ; Italian = "INGANNO" (column 4) ; ; Italian does not appear anywhere else in the game, and ; a fourth language is not supported
Name: SetKeyLogger [Show more] Type: Subroutine Category: Controllers Summary: Populate the key logger table with the controller button presses Deep dive: Bolting NES controllers onto the key logger
Context: See this subroutine on its own page References: This subroutine is called as follows: * SetKeyLogger_b6 calls SetKeyLogger

Returns: X The button number of an icon bar button if an icon bar button has been chosen (0 if no icon bar button has been chosen) Y Y is preserved
.SetKeyLogger TYA ; Store Y on the stack so we can restore it at the end PHA ; of the subroutine ; We start by clearing the key logger table at KL LDX #5 ; We want to clear the 6 key logger locations from ; KY1 to KY6, so set a counter in X LDA #0 ; Set A = 0 to store in the key logger table to clear it STA iconBarKeyPress ; Set iconBarKeyPress = 0 as the default value to return ; if an icon bar button has not been chosen .klog1 STA KL,X ; Store 0 in the X-th byte of the key logger DEX ; Decrement the counter BPL klog1 ; Loop back for the next key, until we have cleared from ; KY1 through KY6 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 numberOfPilots ; If the game is configured for one pilot, jump to klog7 BEQ klog7 ; to skip setting the key logger for controller 2 LDX #$FF ; Set X to $FF to use as the non-zero value in the key ; logger to indicate that a key is being pressed LDA controller2Down ; If the down button is not being pressed on controller BPL klog2 ; 2, jump to klog2 to skip the following instruction STX KY5 ; The down button is being pressed on controller 2, so ; set KY5 = $FF .klog2 LDA controller2Up ; If the up button is not being pressed on controller 2, BPL klog3 ; jump to klog3 to skip the following instruction STX KY6 ; The up button is being pressed on controller 2, so ; set KY6 = $FF .klog3 LDA controller2Left ; If the left button is not being pressed on controller BPL klog4 ; 2, jump to klog4 to skip the following instruction STX KY3 ; The left button is being pressed on controller 2, so ; set KY3 = $FF .klog4 LDA controller2Right ; If the right button is not being pressed on controller BPL klog5 ; 2, jump to klog5 to skip the following instruction STX KY4 ; The right button is being pressed on controller 2, so ; set KY4 = $FF .klog5 LDA controller2A ; If the A button is not being pressed on controller 2, BPL klog6 ; jump to klog6 to skip the following instruction STX KY2 ; The A button is being pressed on controller 2, so ; set KY2 = $FF .klog6 LDA controller2B ; If the B button is not being pressed on controller 2, BPL klog13 ; 2, jump to klog13 to scan the A button on controller 1 ; and return from the subroutine STX KY1 ; The B button is being pressed on controller 2, so ; set KY1 = $FF BMI klog13 ; Jump to klog13 to scan the A button on controller 1 ; and return from the subroutine .klog7 LDX #$FF ; Set X to $FF to use as the non-zero value in the key ; logger to indicate that a key is being pressed LDA controller1B ; If the B button is being pressed on controller 1, jump BMI klog11 ; to klog11 to skip recording the direction keys in KY3 ; to KY4, and just record the up and down buttons in KY2 ; and KY3 LDA controller1Down ; If the down button is not being pressed on controller BPL klog8 ; 1, jump to klog8 to skip the following instruction STX KY5 ; The down button is being pressed on controller 1 (and ; the B button is not being pressed), so set KY5 = $FF .klog8 LDA controller1Up ; If the up button is not being pressed on controller 1, BPL klog9 ; jump to klog9 to skip the following instruction STX KY6 ; The up button is being pressed on controller 1 (and ; the B button is not being pressed), so set KY6 = $FF .klog9 LDA controller1Left ; If the left button is not being pressed on controller BPL klog10 ; 1, jump to klog10 to skip the following instruction STX KY3 ; The left button is being pressed on controller 1 (and ; the B button is not being pressed), so set KY3 = $FF .klog10 LDA controller1Right ; If the right button is not being pressed on controller BPL klog13 ; 1, jump to klog13 to skip the following instruction STX KY4 ; The right button is being pressed on controller 1 (and ; the B button is not being pressed), so set KY4 = $FF BMI klog13 ; Jump to klog13 to scan the A button on controller 1 ; and return from the subroutine .klog11 LDA controller1Up ; If the up button is not being pressed on controller 1, BPL klog12 ; jump to klog12 to skip the following instruction STX KY2 ; The up button is being pressed on controller 2, and so ; is the B button, so set KY2 = $FF .klog12 LDA controller1Down ; If the down button is not being pressed on controller BPL klog13 ; 1, jump to klog13 to skip the following instruction STX KY1 ; The down button is being pressed on controller 1, and ; so is the B button, so set KY1 = $FF .klog13 LDA controller1A ; If the A button is being pressed on controller 1 but CMP #%10000000 ; wasn't being pressed before, shift a 1 into bit 7 of ROR KY7 ; KY7 (as A = %10000000), otherwise shift a 0 LDX #0 ; Copy the value of iconBarChoice to iconBarKeyPress and LDA iconBarChoice ; set iconBarChoice = 0, so if an icon bar button is STX iconBarChoice ; chosen then the first time it is pressed we return the STA iconBarKeyPress ; button number, and if it is pressed again, we return 0 ; ; This lets us use the Start button to toggle the pause ; menu on and off, for example PLA ; Restore the value of Y that we stored on the stack, so TAY ; that Y is preserved LDA iconBarKeyPress ; Set X = iconBarKeyPress to return the icon bar button TAX ; number from the subroutine, if any RTS ; Return from the subroutine
Name: ChooseLanguage [Show more] Type: Subroutine Category: Start and end Summary: Draw the Start screen and process the language choice
Context: See this subroutine on its own page References: This subroutine is called as follows: * ChooseLanguage_b6 calls ChooseLanguage

Arguments: K% The number of the language to highlight K%+1 The value of the third counter (we start the demo on auto-play once all three counters have run down without a choice being made)
.ChooseLanguage LDA #HI(iconBarImage0) ; Set iconBarImageHi to the high byte of the image data STA iconBarImageHi ; for icon bar type 0 (Docked) LDY #0 ; Clear bit 7 of autoPlayDemo so we do not play the demo STY autoPlayDemo ; automatically (so the player plays the demo instead) JSR SetLanguage ; Set the language-related variables to language 0 ; (English) as Y = 0, so English is the default language LDA #$CF ; Clear the screen and set the view type in QQ11 to $CF JSR TT66_b0 ; (Start screen with no fonts loaded) LDA #HI(iconBarImage3) ; Set iconBarImageHi to the high byte of the image data STA iconBarImageHi ; for icon bar type 3 (Pause) LDA #0 ; Move the text cursor to row 0 STA YC LDA #7 ; Move the text cursor to column 7 STA XC LDA #3 ; Set A = 3 so the next instruction prints extended ; token 3 IF _PAL JSR DETOK_b2 ; Print extended token 3 ("{sentence case}{single cap} ; IMAGINEER {single cap}PRESENTS") ENDIF LDA #$DF ; Set the view type in QQ11 to $DF (Start screen with STA QQ11 ; the normal font loaded) JSR DrawBigLogo_b4 ; Set the pattern and nametable buffer entries for the ; big Elite logo LDA #36 ; Set asciiToPattern = 36, so we add 36 to an ASCII code STA asciiToPattern ; in the CHPR routine to get the pattern number in the ; PPU of the corresponding character image (as the font ; is at pattern 68 on the Start screen, and the font ; starts with a space character, which is ASCII 32, and ; 32 + 36 = 68) LDA #21 ; Move the text cursor to row 21 STA YC LDA #10 ; Move the text cursor to column 10 STA XC LDA #6 ; Set A = 6 so the next instruction prints extended ; token 6 IF _PAL JSR DETOK_b2 ; Print extended token 6 ("{single cap}LICENSED{cr} TO") ENDIF INC YC ; Move the text cursor to row 22 LDA #3 ; Move the text cursor to column 3 STA XC LDA #9 ; Set A = 9 so the next instruction prints extended ; token 9 IF _PAL JSR DETOK_b2 ; Print extended token 9 ("{single cap}IMAGINEER {single ; cap}CO. {single cap}LTD., {single cap}JAPAN") ENDIF LDA #25 ; Move the text cursor to row 25 STA YC LDA #3 ; Move the text cursor to column 3 STA XC LDA #12 ; Print extended token 12 ("({single cap}C) {single cap} JSR DETOK_b2 ; D.{single cap}BRABEN & {sentence case}I.{single cap} ; BELL 1991") LDA #26 ; Move the text cursor to row 26 STA YC LDA #6 ; Move the text cursor to column 6 STA XC LDA #7 ; Set A = 7 so the next instruction prints extended ; token 7 IF _PAL JSR DETOK_b2 ; Print extended token 7 ("{single cap}LICENSED BY ; {single cap}NINTENDO") ENDIF ; We now draw the bottom of the box that goes around the ; edge of the title screen, with the bottom line on tile ; row 28 and an edge on either side of row 27 LDY #2 ; First we draw the horizontal line from tile 2 to 31 on ; row 28, so set a tile index in Y LDA #229 ; Set A to the pattern to use for the bottom of the box, ; which is in pattern 229 .clan1 STA nameBuffer0+28*32,Y ; Set tile Y on row 28 to pattern 229 INY ; Increment the tile index CPY #32 ; Loop back until we have drawn from tile index 2 to 31 BNE clan1 ; Next we draw the corners and the tiles above the ; corners LDA #2 ; Draw the bottom-right box corner and the tile above STA nameBuffer0+27*32 STA nameBuffer0+28*32 LDA #1 ; Draw the bottom-left box corner and the tile above STA nameBuffer0+27*32+1 STA nameBuffer0+28*32+1 ; We now display the language names so the player can ; make their choice LDY #0 ; We now work our way through the available languages, ; starting with language 0, so set a language counter ; in Y .clan2 JSR SetLanguage ; Set the language-related variables to language Y LDA xLanguage,Y ; Move the text cursor to the correct column for the STA XC ; language Y button, taken from the xLanguage table LDA yLanguage,Y ; Move the text cursor to the correct row for the STA YC ; language Y button, taken from the yLanguage table LDA #%00000000 ; Set DTW8 = %00000000 (capitalise the next letter) STA DTW8 LDA #4 ; Print extended token 4, which is the language name, JSR DETOK_b2 ; so when Y = 0 it will be "{single cap}ENGLISH", for ; example INC XC ; Move the text cursor two characters to the right INC XC INY ; Increment the language counter in Y LDA languageIndexes,Y ; If the language index for language Y has bit 7 clear BPL clan2 ; then this is a valid language, so loop back to clan2 ; to print this language's name (language 3 has a value ; of $FF in the languageIndexes table, so we only print ; names for languages 0, 1 and 2) STY systemNumber ; Set the current system number in systemNumber to 3, ; though this doesn't appear to be used anywhere (this ; normally stores the current system number for use in ; the PDESC routine for printing extended system ; descriptions, but it gets reset before we get that ; far, so this appears to have no effect) LDA #HI(iconBarImage3) ; Set iconBarImageHi to the high byte of the image data STA iconBarImageHi ; for icon bar type 3 (Pause) JSR UpdateView_b0 ; Update the view LDA controller1Left ; If any of the left button, up button, Select or B are AND controller1Up ; not being pressed on the controller, jump to clan3 AND controller1Select AND controller1B BPL clan3 LDA controller1Right ; If any of the right button, down button, Start or A ORA controller1Down ; are being pressed on the controller, jump to clan3 ORA controller1Start ORA controller1A BMI clan3 ; If we get here then we are pressing the right button, ; down button, Start and A, and we are not pressing any ; of the other keys JSR ResetSaveSlots ; Reset all eight save slots so they fail their ; checksums, so the following call to CheckSaveSlots ; resets then all to the default commander .clan3 JSR CheckSaveSlots_b6 ; Load the commanders for all eight save slots, one ; after the other, to check their integrity and reset ; any that fail their checksums ; We now highlight the currently selected language name ; on-screen LDA #%10000000 ; Set bit 7 of S to indicate that the choice has not yet STA S ; been made (we will clear bit 7 when Start is pressed ; and release, which makes the choice) IF _NTSC LDA #25 ; Set T = 25 STA T ; ; This is the value of the first counter (we start the ; demo on auto-play once all three counters have run ; down without a choice being made) ELIF _PAL LDA #250 ; Set T = 250 STA T ; ; This is the value of the first counter (we start the ; demo on auto-play once all three counters have run ; down without a choice being made) ENDIF LDA K%+1 ; Set V+1 = K%+1 STA V+1 ; ; We set K%+1 to 60 in the BEGIN routine when the game ; first started ; ; We set K%+1 to 5 if we get here after waiting at the ; title screen for too long ; ; This is the value of the third counter (we start the ; demo on auto-play once all three counters have run ; down without a choice being made) LDA #0 ; Set V = 0 STA V ; ; This is the value of the second counter (we start the ; demo on auto-play once all three counters have run ; down without a choice being made) ; ; As the counter is decremented before checking whether ; it is zero, this means the second counter counts down ; 256 times STA Q ; Set Q = 0 (though this value is not read, so this has ; no effect) LDA K% ; Set LASCT = K% STA LASCT ; ; We set K% to 0 in the BEGIN routine when the game ; first started ; ; We set K% to languageIndex if we get here after ; waiting at the title screen for too long ; ; We use LASCT to keep a track of the currently ; highlighted language, so this sets the default ; highlight to English (language 0) .clan4 JSR WaitForNMI ; Wait until the next NMI interrupt has passed (i.e. the ; next VBlank) ; We now highlight the currently selected language name ; on-screen by creating eight sprites containing a white ; block, initially creating them off-screen, before ; moving the correct number of sprites behind the ; currently selected name, so each letter in the name ; is highlighted LDY LASCT ; Set Y to the currently highlighted language in LASCT LDA xLanguage,Y ; Set A to the column number of the button for language ; Y, taken from the xLanguage table ASL A ; Set X = A * 8 ASL A ; ASL A ; So X contains the pixel x-coordinate of the language ADC #0 ; button, as each tile is eight pixels wide TAX CLC ; Clear the C flag so the addition below will work LDY #0 ; We are about to set up the eight sprites that we use ; to highlight the current language choice, using ; sprites 5 to 12, so set an index counter in Y that we ; can use to point to each sprite in the sprite buffer .clan5 ; We now set the coordinates, tile and attributes for ; the Y-th sprite, starting from sprite 5 LDA #240 ; Set the sprite's y-coordinate to 240 to move it off STA ySprite5,Y ; the bottom of the screen (which hides it) LDA #255 ; Set the sprite to pattern 255, which is a full white STA pattSprite5,Y ; block LDA #%00100000 ; Set the attributes for this sprite as follows: STA attrSprite5,Y ; ; * Bits 0-1 = sprite palette 0 ; * Bit 5 set = show behind background ; * Bit 6 clear = do not flip horizontally ; * Bit 7 clear = do not flip vertically TXA ; Set the sprite's x-coordinate to X, which is the STA xSprite5,Y ; x-coordinate for the current letter in the ; language's button ADC #8 ; Set X = X + 8 TAX ; ; So X now contains the pixel x-coordinate of the next ; letter in the language's button INY ; Set Y = Y + 4 INY ; INY ; So Y now points to the next sprite in the sprite INY ; buffer, as each sprite has four bytes in the buffer CPY #32 ; Loop back until we have set up all eight sprites for BNE clan5 ; the currently highlighted language ; Now that we have created the eight sprites off-screen, ; we move the correct number of then on-screen so they ; display behind each letter of the currently ; highlighted language name LDX LASCT ; Set X to the currently highlighted language in LASCT LDA languageLength,X ; Set Y to the number of characters in the currently ; highlighted language's name, from the languageLength ; table ASL A ; Set Y = A * 4 ASL A ; TAY ; So Y contains an index into the sprite buffer for the ; last sprite that we need from the eight available (as ; we need one sprite for each character in the name) LDA yLanguage,X ; Set A to the row number of the button for language Y, ; taken from the yLanguage table ASL A ; Set A = A * 8 + 6 ASL A ; ASL A ; So A contains the pixel y-coordinate of the language ADC #6+YPAL ; button, as each tile row is eight pixels high, plus a ; margin of 6 .clan6 STA ySprite5,Y ; Set the sprite's y-coordinate to A DEY ; Decrement the sprite number by 4 to point to the DEY ; sprite for the previous letter in the language name DEY DEY BPL clan6 ; Loop back until we have moved the sprite on-screen for ; the first letter of the currently highlighted ; language's name LDA controller1Start ; If the Start button on controller 1 was being held AND #%11000000 ; down (bit 6 is set) but is no longer being held down CMP #%01000000 ; (bit 7 is clear) then keep going, otherwise jump to BNE clan7 ; clan7 LSR S ; The Start button has been pressed and release, so ; shift S right to clear bit 7 .clan7 LDX LASCT ; Set X to the currently highlighted language in LASCT LDA controller1Left ; If the left button on controller 1 was being held AND #%11000000 ; down (bit 6 is set) but is no longer being held down CMP #%01000000 ; (bit 7 is clear) then keep going, otherwise jump to BNE clan8 ; clan8 DEX ; Decrement the currently highlighted language to point ; to the next language to the left LDA K%+1 ; Set V+1 = K%+1 STA V+1 ; ; We already did this above, so this has no effect .clan8 LDA controller1Right ; If the right button on controller 1 was being held AND #%11000000 ; down (bit 6 is set) but is no longer being held down CMP #%01000000 ; (bit 7 is clear) then keep going, otherwise jump to BNE clan9 ; clan9 INX ; Increment the currently highlighted language to point ; to the next language to the right LDA K%+1 ; Set V+1 = K%+1 STA V+1 ; ; We already did this above, so this has no effect .clan9 TXA ; Set A to the currently selected language, which may or ; may not have changed BPL clan10 ; If A is positive, jump to clan10 to skip the following ; instruction LDA #0 ; Set A = 0, so the minimum value of A is 0 .clan10 CMP #3 ; If A < 3, then jump to clan11 to skip the following BCC clan11 ; instruction LDA #2 ; Set A = 2, so the maximum value of A is 2 .clan11 STA LASCT ; Set LASCT to the currently selected language DEC T ; Decrement the first counter in T BEQ clan13 ; If the counter in T has reached zero, jump to clan13 ; to check whether a choice has been made, and if not, ; to count down the second and third counters .clan12 JMP clan4 ; Loop back to clan4 keep checking for the selection and ; moving the highlight as required, until a choice is ; made .clan13 INC T ; Increment the first counter in T so we jump here again ; on the next run through the clan4 loop LDA S ; If bit 7 of S is clear then Start has been pressed and BPL SetChosenLanguage ; released, so jump to SetChosenLanguage to set the ; language-related variables according to the chosen ; language, returning from the subroutine using a tail ; call DEC V ; Decrement the second counter in V, and loop back to BNE clan12 ; repeat the clan4 loop until it is zero DEC V+1 ; Decrement the third counter in V+1, and loop back to BNE clan12 ; repeat the clan4 loop until it is zero ; If we get here then no choice has been made and we ; have run down the first, second and third counters, so ; we now start the demo, with the computer auto-playing ; it JSR SetChosenLanguage ; Call SetChosenLanguage to set the language-related ; variables according to the currently selected language ; on-screen JMP SetDemoAutoPlay_b5 ; Start the demo and auto-play it by "pressing" keys ; from the relevant key table (which will be different, ; depending on which language is currently highlighted) ; and return from the subroutine using a tail call
Name: SetChosenLanguage [Show more] Type: Subroutine Category: Start and end Summary: Set the language-related variables according to the language chosen on the Start screen
Context: See this subroutine on its own page References: This subroutine is called as follows: * ChooseLanguage calls SetChosenLanguage
.SetChosenLanguage LDY LASCT ; Set Y to the language choice, which gets stored in ; LASCT by the ChooseLanguage routine ; Fall through to set the language chosen in Y
Name: SetLanguage [Show more] Type: Subroutine Category: Start and end Summary: Set the language-related variables for a specific language
Context: See this subroutine on its own page References: This subroutine is called as follows: * ChooseLanguage calls SetLanguage

Arguments: Y The number of the language choice to set
.SetLanguage LDA tokensLo,Y ; Set (QQ18Hi QQ18Lo) to the language's entry from the STA QQ18Lo ; (tokensHi tokensLo) table LDA tokensHi,Y STA QQ18Hi LDA extendedTokensLo,Y ; Set (TKN1Hi TKN1Lo) to the language's entry from the STA TKN1Lo ; the (extendedTokensHi extendedTokensLo) table LDA extendedTokensHi,Y STA TKN1Hi LDA languageIndexes,Y ; Set languageIndex to the language's index from the STA languageIndex ; languageIndexes table LDA languageNumbers,Y ; Set languageNumber to the language's flags from the STA languageNumber ; languageNumbers table LDA characterEndLang,Y ; Set characterEnd to the end of the language's STA characterEnd ; character set from the characterEndLang table LDA decimalPointLang,Y ; Set decimalPoint to the language's decimal point STA decimalPoint ; character from the decimalPointLang table RTS ; Return from the subroutine
Name: xLanguage [Show more] Type: Variable Category: Start and end Summary: The text column for the language buttons on the Start screen Deep dive: Multi-language support in NES Elite
Context: See this variable on its own page References: This variable is used as follows: * ChooseLanguage uses xLanguage
.xLanguage EQUB 2 ; English EQUB 12 ; German EQUB 22 ; French EQUB 17 ; There is no fourth language, so this byte is ignored
Name: yLanguage [Show more] Type: Variable Category: Start and end Summary: The text row for the language buttons on the Start screen Deep dive: Multi-language support in NES Elite
Context: See this variable on its own page References: This variable is used as follows: * ChooseLanguage uses yLanguage
.yLanguage EQUB 23 ; English EQUB 24 ; German EQUB 23 ; French EQUB 24 ; There is no fourth language, so this byte is ignored
Name: characterEndLang [Show more] Type: Variable Category: Text Summary: The number of the character beyond the end of the printable character set in each language Deep dive: Multi-language support in NES Elite
Context: See this variable on its own page References: This variable is used as follows: * SetLanguage uses characterEndLang
.characterEndLang EQUB 91 ; English EQUB 96 ; German EQUB 96 ; French EQUB 96 ; There is no fourth language, so this byte is ignored
Name: decimalPointLang [Show more] Type: Variable Category: Text Summary: The decimal point character to use for each language Deep dive: Multi-language support in NES Elite
Context: See this variable on its own page References: This variable is used as follows: * SetLanguage uses decimalPointLang
.decimalPointLang EQUB '.' ; English EQUB '.' ; German EQUB ',' ; French EQUB '.' ; There is no fourth language, so this byte is ignored
Name: languageLength [Show more] Type: Variable Category: Text Summary: The length of each language name
Context: See this variable on its own page References: This variable is used as follows: * ChooseLanguage uses languageLength
.languageLength EQUB 6 ; English EQUB 6 ; German EQUB 7 ; French
Name: tokensLo [Show more] Type: Variable Category: Text Summary: Low byte of the text token table for each language Deep dive: Multi-language support in NES Elite
Context: See this variable on its own page References: This variable is used as follows: * SetLanguage uses tokensLo
.tokensLo EQUB LO(QQ18) ; English EQUB LO(QQ18_DE) ; German EQUB LO(QQ18_FR) ; French
Name: tokensHi [Show more] Type: Variable Category: Text Summary: High byte of the text token table for each language Deep dive: Multi-language support in NES Elite
Context: See this variable on its own page References: This variable is used as follows: * SetLanguage uses tokensHi
.tokensHi EQUB HI(QQ18) ; English EQUB HI(QQ18_DE) ; German EQUB HI(QQ18_FR) ; French
Name: extendedTokensLo [Show more] Type: Variable Category: Text Summary: Low byte of the extended text token table for each language Deep dive: Multi-language support in NES Elite
Context: See this variable on its own page References: This variable is used as follows: * SetLanguage uses extendedTokensLo
.extendedTokensLo EQUB LO(TKN1) ; English EQUB LO(TKN1_DE) ; German EQUB LO(TKN1_FR) ; French
Name: extendedTokensHi [Show more] Type: Variable Category: Text Summary: High byte of the extended text token table for each language Deep dive: Multi-language support in NES Elite
Context: See this variable on its own page References: This variable is used as follows: * SetLanguage uses extendedTokensHi
.extendedTokensHi EQUB HI(TKN1) ; English EQUB HI(TKN1_DE) ; German EQUB HI(TKN1_FR) ; French
Name: languageIndexes [Show more] Type: Variable Category: Text Summary: The index of the chosen language for looking up values from language-indexed tables Deep dive: Multi-language support in NES Elite
Context: See this variable on its own page References: This variable is used as follows: * ChooseLanguage uses languageIndexes * SetLanguage uses languageIndexes
.languageIndexes EQUB 0 ; English EQUB 1 ; German EQUB 2 ; French EQUB $FF ; There is no fourth language, so this byte is ignored
Name: languageNumbers [Show more] Type: Variable Category: Text Summary: The language number for each language, as a set bit within a flag byte Deep dive: Multi-language support in NES Elite
Context: See this variable on its own page References: This variable is used as follows: * SetLanguage uses languageNumbers
.languageNumbers EQUB %00000001 ; English EQUB %00000010 ; German EQUB %00000100 ; French
Name: TT24 [Show more] Type: Subroutine Category: Universe Summary: Calculate system data from the system seeds Deep dive: Generating system data Galaxy and system seeds
Context: See this subroutine on its own page References: This subroutine is called as follows: * TT24_b6 calls TT24

Calculate system data from the seeds in QQ15 and store them in the relevant locations. Specifically, this routine calculates the following from the three 16-bit seeds in QQ15 (using only s0_hi, s1_hi and s1_lo): QQ3 = economy (0-7) QQ4 = government (0-7) QQ5 = technology level (0-14) QQ6 = population * 10 (1-71) QQ7 = productivity (96-62480) The ranges of the various values are shown in brackets. Note that the radius and type of inhabitant are calculated on-the-fly in the TT25 routine when the system data gets displayed, so they aren't calculated here.
.TT24 LDA QQ15+1 ; Fetch s0_hi and extract bits 0-2 to determine the AND #%00000111 ; system's economy, and store in QQ3 STA QQ3 LDA QQ15+2 ; Fetch s1_lo and extract bits 3-5 to determine the LSR A ; system's government, and store in QQ4 LSR A LSR A AND #%00000111 STA QQ4 LSR A ; If government isn't anarchy or feudal, skip to TT77, BNE TT77 ; as we need to fix the economy of anarchy and feudal ; systems so they can't be rich LDA QQ3 ; Set bit 1 of the economy in QQ3 to fix the economy ORA #%00000010 ; for anarchy and feudal governments STA QQ3 .TT77 LDA QQ3 ; Now to work out the tech level, which we do like this: EOR #%00000111 ; CLC ; flipped_economy + (s1_hi AND %11) + (government / 2) STA QQ5 ; ; or, in terms of memory locations: ; ; QQ5 = (QQ3 EOR %111) + (QQ15+3 AND %11) + (QQ4 / 2) ; ; We start by setting QQ5 = QQ3 EOR %111 LDA QQ15+3 ; We then take the first 2 bits of s1_hi (QQ15+3) and AND #%00000011 ; add it into QQ5 ADC QQ5 STA QQ5 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 QQ4 ; And finally we add QQ4 / 2 and store the result in LSR A ; QQ5, using LSR then ADC to divide by 2, which rounds ADC QQ5 ; up the result for odd-numbered government types STA QQ5 ASL A ; Now to work out the population, like so: ASL A ; ADC QQ3 ; (tech level * 4) + economy + government + 1 ADC QQ4 ; ADC #1 ; or, in terms of memory locations: STA QQ6 ; ; QQ6 = (QQ5 * 4) + QQ3 + QQ4 + 1 LDA QQ3 ; Finally, we work out productivity, like this: EOR #%00000111 ; ADC #3 ; (flipped_economy + 3) * (government + 4) STA P ; * population LDA QQ4 ; * 8 ADC #4 ; STA Q ; or, in terms of memory locations: JSR MULTU ; ; QQ7 = (QQ3 EOR %111 + 3) * (QQ4 + 4) * QQ6 * 8 ; ; We do the first step by setting P to the first ; expression in brackets and Q to the second, and ; calling MULTU, so now (A P) = P * Q. The highest this ; can be is 10 * 11 (as the maximum values of economy ; and government are 7), so the high byte of the result ; will always be 0, so we actually have: ; ; P = P * Q ; = (flipped_economy + 3) * (government + 4) LDA QQ6 ; We now take the result in P and multiply by the STA Q ; population to get the productivity, by setting Q to JSR MULTU ; the population from QQ6 and calling MULTU again, so ; now we have: ; ; (A P) = P * population ASL P ; Next we multiply the result by 8, as a 16-bit number, ROL A ; so we shift both bytes to the left three times, using ASL P ; the C flag to carry bits from bit 7 of the low byte ROL A ; into bit 0 of the high byte ASL P ROL A STA QQ7+1 ; Finally, we store the productivity in two bytes, with LDA P ; the low byte in QQ7 and the high byte in QQ7+1 STA QQ7 RTS ; Return from the subroutine
Name: ClearDashEdge [Show more] Type: Subroutine Category: Drawing the screen Summary: Clear the right edge of the dashboard
Context: See this subroutine on its own page References: This subroutine is called as follows: * ClearDashEdge_b6 calls ClearDashEdge
.ClearDashEdge JSR SetupPPUForIconBar ; If the PPU has started drawing the icon bar, configure ; the PPU to use nametable 0 and pattern table 0 LDA #0 ; Clear the right edge of the box on rows 20 to 27 in STA nameBuffer0+20*32 ; nametable buffer 0 STA nameBuffer0+21*32 STA nameBuffer0+22*32 STA nameBuffer0+23*32 STA nameBuffer0+24*32 STA nameBuffer0+25*32 STA nameBuffer0+26*32 STA nameBuffer0+27*32 STA nameBuffer1+20*32 ; Clear the right edge of the box on rows 20 to 27 in STA nameBuffer1+21*32 ; nametable buffer 1 STA nameBuffer1+22*32 STA nameBuffer1+23*32 STA nameBuffer1+24*32 STA nameBuffer1+25*32 STA nameBuffer1+26*32 STA nameBuffer1+27*32 RTS ; Return from the subroutine
Name: Vectors_b6 [Show more] Type: Variable Category: Utility routines Summary: Vectors and padding at the end of ROM bank 6 Deep dive: Splitting NES Elite across multiple ROM banks
Context: See this variable on its own page References: No direct references to this variable in this source file
FOR I%, P%, $BFF9 EQUB $FF ; Pad out the rest of the ROM bank with $FF NEXT IF _NTSC EQUW Interrupts_b6+$4000 ; Vector to the NMI handler in case this bank is ; loaded into $C000 during start-up (the handler ; contains an RTI so the interrupt is processed but ; has no effect) EQUW ResetMMC1_b6+$4000 ; Vector to the RESET handler in case this bank is ; loaded into $C000 during start-up (the handler ; resets the MMC1 mapper to map bank 7 into $C000 ; instead) EQUW Interrupts_b6+$4000 ; Vector to the IRQ/BRK handler in case this bank is ; loaded into $C000 during start-up (the handler ; contains an RTI so the interrupt is processed but ; has no effect) ELIF _PAL EQUW NMI ; Vector to the NMI handler EQUW ResetMMC1_b6+$4000 ; Vector to the RESET handler in case this bank is ; loaded into $C000 during start-up (the handler ; resets the MMC1 mapper to map bank 7 into $C000 ; instead) EQUW IRQ ; Vector to the IRQ/BRK handler ENDIF
Save bank6.bin
PRINT "S.bank6.bin ", ~CODE%, " ", ~P%, " ", ~LOAD%, " ", ~LOAD% SAVE "3-assembled-output/bank6.bin", CODE%, P%, LOAD%