Skip to navigation

Elite on the BBC Micro and NES

Elite B docked source

[BBC Micro disc version]

ELITE B FILE
CODE_B% = P% LOAD_B% = LOAD% + P% - CODE%
Name: TWOS [Show more] Type: Variable Category: Drawing pixels Summary: Ready-made single-pixel character row bytes for mode 4 Deep dive: Drawing monochrome pixels in mode 4
Context: See this variable on its own page Variations: See code variations for this variable in the different versions References: This variable is used as follows: * LOIN (Part 2 of 7) uses TWOS * LOIN (Part 5 of 7) uses TWOS * PX3 uses TWOS

Ready-made bytes for plotting one-pixel points in mode 4 (the top part of the split screen). See the PIXEL routine for details.
.TWOS EQUB %10000000 EQUB %01000000 EQUB %00100000 EQUB %00010000 EQUB %00001000 EQUB %00000100 EQUB %00000010 EQUB %00000001
Name: TWOS2 [Show more] Type: Variable Category: Drawing pixels Summary: Ready-made double-pixel character row bytes for mode 4 Deep dive: Drawing monochrome pixels in mode 4
Context: See this variable on its own page Variations: See code variations for this variable in the different versions References: This variable is used as follows: * PIXEL uses TWOS2

Ready-made bytes for plotting two-pixel dashes in mode 4 (the top part of the split screen). See the PIXEL routine for details.
.TWOS2 EQUB %11000000 EQUB %01100000 EQUB %00110000 EQUB %00011000 EQUB %00001100 EQUB %00000110 EQUB %00000011 EQUB %00000011
Name: CTWOS [Show more] Type: Variable Category: Drawing pixels Summary: Ready-made single-pixel character row bytes for mode 5 Deep dive: Drawing colour pixels in mode 5
Context: See this variable on its own page Variations: See code variations for this variable in the different versions References: This variable is used as follows: * CPIX2 uses CTWOS * DIL2 uses CTWOS

Ready-made bytes for plotting one-pixel points in mode 5 (the bottom part of the split screen). See the dashboard routines SCAN, DIL2 and CPIX2 for details.
.CTWOS EQUB %10001000 EQUB %01000100 EQUB %00100010 EQUB %00010001
Name: LOIN (Part 1 of 7) [Show more] Type: Subroutine Category: Drawing lines Summary: Draw a line: Calculate the line gradient in the form of deltas Deep dive: Bresenham's line algorithm
Context: See this subroutine on its own page Variations: See code variations for this subroutine in the different versions References: This subroutine is called as follows: * BLINE calls LOIN * TTX66 calls LOIN * LL9 (Part 12 of 12) calls via LL30 * TT15 calls via LL30

This routine draws a line from (X1, Y1) to (X2, Y2). It has multiple stages. This stage calculates the line deltas.
Arguments: X1 The screen x-coordinate of the start of the line Y1 The screen y-coordinate of the start of the line X2 The screen x-coordinate of the end of the line Y2 The screen y-coordinate of the end of the line
Returns: Y Y is preserved
Other entry points: LL30 LL30 is a synonym for LOIN and draws a line from (X1, Y1) to (X2, Y2)
.LL30 SKIP 0 \ LL30 is a synonym for LOIN \ \ In the cassette and disc versions of Elite, LL30 and \ LOIN are synonyms for the same routine, presumably \ because the two developers each had their own line \ routines to start with, and then chose one of them for \ the final game .LOIN STY YSAV \ Store Y into YSAV, so we can preserve it across the \ call to this subroutine LDA #128 \ Set S = 128, which is the starting point for the STA S \ slope error (representing half a pixel) ASL A \ Set SWAP = 0, as %10000000 << 1 = 0 STA SWAP LDA X2 \ Set A = X2 - X1 SBC X1 \ = delta_x \ \ This subtraction works as the ASL A above sets the C \ flag BCS LI1 \ If X2 > X1 then A is already positive and we can skip \ the next three instructions EOR #%11111111 \ Negate the result in A by flipping all the bits and ADC #1 \ adding 1, i.e. using two's complement to make it \ positive SEC \ Set the C flag, ready for the subtraction below .LI1 STA P \ Store A in P, so P = |X2 - X1|, or |delta_x| LDA Y2 \ Set A = Y2 - Y1 SBC Y1 \ = delta_y \ \ This subtraction works as we either set the C flag \ above, or we skipped that SEC instruction with a BCS BCS LI2 \ If Y2 > Y1 then A is already positive and we can skip \ the next two instructions EOR #%11111111 \ Negate the result in A by flipping all the bits and ADC #1 \ adding 1, i.e. using two's complement to make it \ positive .LI2 STA Q \ Store A in Q, so Q = |Y2 - Y1|, or |delta_y| CMP P \ If Q < P, jump to STPX to step along the x-axis, as BCC STPX \ the line is closer to being horizontal than vertical JMP STPY \ Otherwise Q >= P so jump to STPY to step along the \ y-axis, as the line is closer to being vertical than \ horizontal
Name: LOIN (Part 2 of 7) [Show more] Type: Subroutine Category: Drawing lines Summary: Draw a line: Line has a shallow gradient, step right along x-axis Deep dive: Bresenham's line algorithm
Context: See this subroutine on its own page Variations: See code variations for this subroutine in the different versions References: No direct references to this subroutine in this source file

This routine draws a line from (X1, Y1) to (X2, Y2). It has multiple stages. If we get here, then: * |delta_y| < |delta_x| * The line is closer to being horizontal than vertical * We are going to step right along the x-axis * We potentially swap coordinates to make sure X1 < X2
.STPX LDX X1 \ Set X = X1 CPX X2 \ If X1 < X2, jump down to LI3, as the coordinates are BCC LI3 \ already in the order that we want DEC SWAP \ Otherwise decrement SWAP from 0 to &FF, to denote that \ we are swapping the coordinates around LDA X2 \ Swap the values of X1 and X2 STA X1 STX X2 TAX \ Set X = X1 LDA Y2 \ Swap the values of Y1 and Y2 LDY Y1 STA Y1 STY Y2 .LI3 \ By this point we know the line is horizontal-ish and \ X1 < X2, so we're going from left to right as we go \ from X1 to X2 LDA Y1 \ Set A = Y1 / 8, so A now contains the character row LSR A \ that will contain our horizontal line LSR A LSR A ORA #&60 \ As A < 32, this effectively adds &60 to A, which gives \ us the screen address of the character row (as each \ character row takes up 256 bytes, and the first \ character row is at screen address &6000, or page &60) STA SCH \ Store the page number of the character row in SCH, so \ the high byte of SC is set correctly for drawing the \ start of our line LDA Y1 \ Set Y = Y1 mod 8, which is the pixel row within the AND #7 \ character block at which we want to draw the start of TAY \ our line (as each character block has 8 rows) TXA \ Set A = bits 3-7 of X1 AND #%11111000 STA SC \ Store this value in SC, so SC(1 0) now contains the \ screen address of the far left end (x-coordinate = 0) \ of the horizontal pixel row that we want to draw the \ start of our line on TXA \ Set X = X1 mod 8, which is the horizontal pixel number AND #7 \ within the character block where the line starts (as TAX \ each pixel line in the character block is 8 pixels \ wide) LDA TWOS,X \ Fetch a 1-pixel byte from TWOS where pixel X is set, STA R \ and store it in R \ The following calculates: \ \ Q = Q / P \ = |delta_y| / |delta_x| \ \ using the same shift-and-subtract algorithm that's \ documented in TIS2 LDA Q \ Set A = |delta_y| LDX #%11111110 \ Set Q to have bits 1-7 set, so we can rotate through 7 STX Q \ loop iterations, getting a 1 each time, and then \ getting a 0 on the 8th iteration... and we can also \ use Q to catch our result bits into bit 0 each time .LIL1 ASL A \ Shift A to the left BCS LI4 \ If bit 7 of A was set, then jump straight to the \ subtraction CMP P \ If A < P, skip the following subtraction BCC LI5 .LI4 SBC P \ A >= P, so set A = A - P SEC \ Set the C flag to rotate into the result in Q .LI5 ROL Q \ Rotate the counter in Q to the left, and catch the \ result bit into bit 0 (which will be a 0 if we didn't \ do the subtraction, or 1 if we did) BCS LIL1 \ If we still have set bits in Q, loop back to TIL2 to \ do the next iteration of 7 \ We now have: \ \ Q = A / P \ = |delta_y| / |delta_x| \ \ and the C flag is clear LDX P \ Set X = P + 1 INX \ = |delta_x| + 1 \ \ We add 1 so we can skip the first pixel plot if the \ line is being drawn with swapped coordinates LDA Y2 \ Set A = Y2 - Y1 - 1 (as the C flag is clear following SBC Y1 \ the above division) BCS DOWN \ If Y2 >= Y1 - 1 then jump to DOWN, as we need to draw \ the line to the right and down
Name: LOIN (Part 3 of 7) [Show more] Type: Subroutine Category: Drawing lines Summary: Draw a shallow line going right and up or left and down Deep dive: Bresenham's line algorithm
Context: See this subroutine on its own page Variations: See code variations for this subroutine in the different versions References: No direct references to this subroutine in this source file

This routine draws a line from (X1, Y1) to (X2, Y2). It has multiple stages. If we get here, then: * The line is going right and up (no swap) or left and down (swap) * X1 < X2 and Y1-1 > Y2 * Draw from (X1, Y1) at bottom left to (X2, Y2) at top right, omitting the first pixel
LDA SWAP \ If SWAP > 0 then we swapped the coordinates above, so BNE LI6 \ jump down to LI6 to skip plotting the first pixel \ \ This appears to be a bug that omits the last pixel \ of this type of shallow line, rather than the first \ pixel, which makes the treatment of this kind of line \ different to the other kinds of slope (they all have a \ BEQ instruction at this point, rather than a BNE) \ \ The result is a rather messy line join when a shallow \ line that goes right and up or left and down joins a \ line with any of the other three types of slope \ \ This bug was fixed in the advanced versions of Elite, \ where the BNE is replaced by a BEQ to bring it in line \ with the other three slopes DEX \ Decrement the counter in X because we're about to plot \ the first pixel .LIL2 \ We now loop along the line from left to right, using X \ as a decreasing counter, and at each count we plot a \ single pixel using the pixel mask in R LDA R \ Fetch the pixel byte from R EOR (SC),Y \ Store R into screen memory at SC(1 0), using EOR STA (SC),Y \ logic so it merges with whatever is already on-screen .LI6 LSR R \ Shift the single pixel in R to the right to step along \ the x-axis, so the next pixel we plot will be at the \ next x-coordinate along BCC LI7 \ If the pixel didn't fall out of the right end of R \ into the C flag, then jump to LI7 ROR R \ Otherwise we need to move over to the next character \ block, so first rotate R right so the set C flag goes \ back into the left end, giving %10000000 LDA SC \ Add 8 to SC, so SC(1 0) now points to the next ADC #8 \ character along to the right STA SC .LI7 LDA S \ Set S = S + Q to update the slope error ADC Q STA S BCC LIC2 \ If the addition didn't overflow, jump to LIC2 DEY \ Otherwise we just overflowed, so decrement Y to move \ to the pixel line above BPL LIC2 \ If Y is positive we are still within the same \ character block, so skip to LIC2 DEC SCH \ Otherwise we need to move up into the character block LDY #7 \ above, so decrement the high byte of the screen \ address and set the pixel line to the last line in \ that character block .LIC2 DEX \ Decrement the counter in X BNE LIL2 \ If we haven't yet reached the right end of the line, \ loop back to LIL2 to plot the next pixel along LDY YSAV \ Restore Y from YSAV, so that it's preserved RTS \ Return from the subroutine
Name: LOIN (Part 4 of 7) [Show more] Type: Subroutine Category: Drawing lines Summary: Draw a shallow line going right and down or left and up Deep dive: Bresenham's line algorithm
Context: See this subroutine on its own page Variations: See code variations for this subroutine in the different versions References: No direct references to this subroutine in this source file

This routine draws a line from (X1, Y1) to (X2, Y2). It has multiple stages. If we get here, then: * The line is going right and down (no swap) or left and up (swap) * X1 < X2 and Y1-1 <= Y2 * Draw from (X1, Y1) at top left to (X2, Y2) at bottom right, omitting the first pixel
.DOWN LDA SWAP \ If SWAP = 0 then we didn't swap the coordinates above, BEQ LI9 \ so jump down to LI9 to skip plotting the first pixel DEX \ Decrement the counter in X because we're about to plot \ the first pixel .LIL3 \ We now loop along the line from left to right, using X \ as a decreasing counter, and at each count we plot a \ single pixel using the pixel mask in R LDA R \ Fetch the pixel byte from R EOR (SC),Y \ Store R into screen memory at SC(1 0), using EOR STA (SC),Y \ logic so it merges with whatever is already on-screen .LI9 LSR R \ Shift the single pixel in R to the right to step along \ the x-axis, so the next pixel we plot will be at the \ next x-coordinate along BCC LI10 \ If the pixel didn't fall out of the right end of R \ into the C flag, then jump to LI10 ROR R \ Otherwise we need to move over to the next character \ block, so first rotate R right so the set C flag goes \ back into the left end, giving %10000000 LDA SC \ Add 8 to SC, so SC(1 0) now points to the next ADC #8 \ character along to the right STA SC .LI10 LDA S \ Set S = S + Q to update the slope error ADC Q STA S BCC LIC3 \ If the addition didn't overflow, jump to LIC3 INY \ Otherwise we just overflowed, so increment Y to move \ to the pixel line below CPY #8 \ If Y < 8 we are still within the same character block, BNE LIC3 \ so skip to LIC3 INC SCH \ Otherwise we need to move down into the character LDY #0 \ block below, so increment the high byte of the screen \ address and set the pixel line to the first line in \ that character block .LIC3 DEX \ Decrement the counter in X BNE LIL3 \ If we haven't yet reached the right end of the line, \ loop back to LIL3 to plot the next pixel along LDY YSAV \ Restore Y from YSAV, so that it's preserved RTS \ Return from the subroutine
Name: LOIN (Part 5 of 7) [Show more] Type: Subroutine Category: Drawing lines Summary: Draw a line: Line has a steep gradient, step up along y-axis Deep dive: Bresenham's line algorithm
Context: See this subroutine on its own page Variations: See code variations for this subroutine in the different versions References: No direct references to this subroutine in this source file

This routine draws a line from (X1, Y1) to (X2, Y2). It has multiple stages. If we get here, then: * |delta_y| >= |delta_x| * The line is closer to being vertical than horizontal * We are going to step up along the y-axis * We potentially swap coordinates to make sure Y1 >= Y2
.STPY LDY Y1 \ Set A = Y = Y1 TYA LDX X1 \ Set X = X1 CPY Y2 \ If Y1 >= Y2, jump down to LI15, as the coordinates are BCS LI15 \ already in the order that we want DEC SWAP \ Otherwise decrement SWAP from 0 to &FF, to denote that \ we are swapping the coordinates around LDA X2 \ Swap the values of X1 and X2 STA X1 STX X2 TAX \ Set X = X1 LDA Y2 \ Swap the values of Y1 and Y2 STA Y1 STY Y2 TAY \ Set Y = A = Y1 .LI15 \ By this point we know the line is vertical-ish and \ Y1 >= Y2, so we're going from top to bottom as we go \ from Y1 to Y2 LSR A \ Set A = Y1 / 8, so A now contains the character row LSR A \ that will contain our horizontal line LSR A ORA #&60 \ As A < 32, this effectively adds &60 to A, which gives \ us the screen address of the character row (as each \ character row takes up 256 bytes, and the first \ character row is at screen address &6000, or page &60) STA SCH \ Store the page number of the character row in SCH, so \ the high byte of SC is set correctly for drawing the \ start of our line TXA \ Set A = bits 3-7 of X1 AND #%11111000 STA SC \ Store this value in SC, so SC(1 0) now contains the \ screen address of the far left end (x-coordinate = 0) \ of the horizontal pixel row that we want to draw the \ start of our line on TXA \ Set X = X1 mod 8, which is the horizontal pixel number AND #7 \ within the character block where the line starts (as TAX \ each pixel line in the character block is 8 pixels \ wide) LDA TWOS,X \ Fetch a 1-pixel byte from TWOS where pixel X is set, STA R \ and store it in R LDA Y1 \ Set Y = Y1 mod 8, which is the pixel row within the AND #7 \ character block at which we want to draw the start of TAY \ our line (as each character block has 8 rows) \ The following calculates: \ \ P = P / Q \ = |delta_x| / |delta_y| \ \ using the same shift-and-subtract algorithm \ documented in TIS2 LDA P \ Set A = |delta_x| LDX #1 \ Set Q to have bits 1-7 clear, so we can rotate through STX P \ 7 loop iterations, getting a 1 each time, and then \ getting a 1 on the 8th iteration... and we can also \ use P to catch our result bits into bit 0 each time .LIL4 ASL A \ Shift A to the left BCS LI13 \ If bit 7 of A was set, then jump straight to the \ subtraction CMP Q \ If A < Q, skip the following subtraction BCC LI14 .LI13 SBC Q \ A >= Q, so set A = A - Q SEC \ Set the C flag to rotate into the result in Q .LI14 ROL P \ Rotate the counter in P to the left, and catch the \ result bit into bit 0 (which will be a 0 if we didn't \ do the subtraction, or 1 if we did) BCC LIL4 \ If we still have set bits in P, loop back to TIL2 to \ do the next iteration of 7 \ We now have: \ \ P = A / Q \ = |delta_x| / |delta_y| \ \ and the C flag is set LDX Q \ Set X = Q + 1 INX \ = |delta_y| + 1 \ \ We add 1 so we can skip the first pixel plot if the \ line is being drawn with swapped coordinates LDA X2 \ Set A = X2 - X1 (the C flag is set as we didn't take SBC X1 \ the above BCC) BCC LFT \ If X2 < X1 then jump to LFT, as we need to draw the \ line to the left and down
Name: LOIN (Part 6 of 7) [Show more] Type: Subroutine Category: Drawing lines Summary: Draw a steep line going up and left or down and right Deep dive: Bresenham's line algorithm
Context: See this subroutine on its own page Variations: See code variations for this subroutine in the different versions References: No direct references to this subroutine in this source file

This routine draws a line from (X1, Y1) to (X2, Y2). It has multiple stages. If we get here, then: * The line is going up and left (no swap) or down and right (swap) * X1 < X2 and Y1 >= Y2 * Draw from (X1, Y1) at top left to (X2, Y2) at bottom right, omitting the first pixel
CLC \ Clear the C flag LDA SWAP \ If SWAP = 0 then we didn't swap the coordinates above, BEQ LI17 \ so jump down to LI17 to skip plotting the first pixel DEX \ Decrement the counter in X because we're about to plot \ the first pixel .LIL5 \ We now loop along the line from left to right, using X \ as a decreasing counter, and at each count we plot a \ single pixel using the pixel mask in R LDA R \ Fetch the pixel byte from R EOR (SC),Y \ Store R into screen memory at SC(1 0), using EOR STA (SC),Y \ logic so it merges with whatever is already on-screen .LI17 DEY \ Decrement Y to step up along the y-axis BPL LI16 \ If Y is positive we are still within the same \ character block, so skip to LI16 DEC SCH \ Otherwise we need to move up into the character block LDY #7 \ above, so decrement the high byte of the screen \ address and set the pixel line to the last line in \ that character block .LI16 LDA S \ Set S = S + P to update the slope error ADC P STA S BCC LIC5 \ If the addition didn't overflow, jump to LIC5 LSR R \ Otherwise we just overflowed, so shift the single \ pixel in R to the right, so the next pixel we plot \ will be at the next x-coordinate along BCC LIC5 \ If the pixel didn't fall out of the right end of R \ into the C flag, then jump to LIC5 ROR R \ Otherwise we need to move over to the next character \ block, so first rotate R right so the set C flag goes \ back into the left end, giving %10000000 LDA SC \ Add 8 to SC, so SC(1 0) now points to the next ADC #8 \ character along to the right STA SC .LIC5 DEX \ Decrement the counter in X BNE LIL5 \ If we haven't yet reached the right end of the line, \ loop back to LIL5 to plot the next pixel along LDY YSAV \ Restore Y from YSAV, so that it's preserved RTS \ Return from the subroutine
Name: LOIN (Part 7 of 7) [Show more] Type: Subroutine Category: Drawing lines Summary: Draw a steep line going up and right or down and left Deep dive: Bresenham's line algorithm
Context: See this subroutine on its own page Variations: See code variations for this subroutine in the different versions References: This subroutine is called as follows: * HLOIN calls via HL6

This routine draws a line from (X1, Y1) to (X2, Y2). It has multiple stages. If we get here, then: * The line is going up and right (no swap) or down and left (swap) * X1 >= X2 and Y1 >= Y2 * Draw from (X1, Y1) at bottom left to (X2, Y2) at top right, omitting the first pixel
Other entry points: HL6 Contains an RTS
.LFT LDA SWAP \ If SWAP = 0 then we didn't swap the coordinates above, BEQ LI18 \ so jump down to LI18 to skip plotting the first pixel DEX \ Decrement the counter in X because we're about to plot \ the first pixel .LIL6 LDA R \ Fetch the pixel byte from R EOR (SC),Y \ Store R into screen memory at SC(1 0), using EOR STA (SC),Y \ logic so it merges with whatever is already on-screen .LI18 DEY \ Decrement Y to step up along the y-axis BPL LI19 \ If Y is positive we are still within the same \ character block, so skip to LI19 DEC SCH \ Otherwise we need to move up into the character block LDY #7 \ above, so decrement the high byte of the screen \ address and set the pixel line to the last line in \ that character block .LI19 LDA S \ Set S = S + P to update the slope error ADC P STA S BCC LIC6 \ If the addition didn't overflow, jump to LIC6 ASL R \ Otherwise we just overflowed, so shift the single \ pixel in R to the left, so the next pixel we plot \ will be at the previous x-coordinate BCC LIC6 \ If the pixel didn't fall out of the left end of R \ into the C flag, then jump to LIC6 ROL R \ Otherwise we need to move over to the next character \ block, so first rotate R left so the set C flag goes \ back into the right end, giving %0000001 LDA SC \ Subtract 7 from SC, so SC(1 0) now points to the SBC #7 \ previous character along to the left STA SC CLC \ Clear the C flag so it doesn't affect the additions \ below .LIC6 DEX \ Decrement the counter in X BNE LIL6 \ If we haven't yet reached the left end of the line, \ loop back to LIL6 to plot the next pixel along LDY YSAV \ Restore Y from YSAV, so that it's preserved .HL6 RTS \ Return from the subroutine
Name: FLKB [Show more] Type: Subroutine Category: Keyboard Summary: Flush the keyboard buffer
Context: See this subroutine on its own page Variations: See code variations for this subroutine in the different versions References: This subroutine is called as follows: * EQSHP calls FLKB * MT26 calls FLKB * TT208 calls FLKB * TT219 calls FLKB
.FLKB LDA #15 \ Call OSBYTE with A = 15 and Y <> 0 to flush the input TAX \ buffers (i.e. flush the operating system's keyboard JMP OSBYTE \ buffer) and return from the subroutine using a tail \ call
Name: NLIN3 [Show more] Type: Subroutine Category: Drawing lines Summary: Print a title and draw a horizontal line at row 19 to box it in
Context: See this subroutine on its own page References: This subroutine is called as follows: * EQSHP calls NLIN3 * STATUS calls NLIN3 * TT167 calls NLIN3 * TT208 calls NLIN3 * TT23 calls NLIN3 * TT25 calls NLIN3

This routine print a text token at the cursor position and draws a horizontal line at pixel row 19. It is used for the Status Mode screen, the Short-range Chart, the Market Price screen and the Equip Ship screen.
.NLIN3 JSR TT27 \ Print the text token in A \ Fall through into NLIN4 to draw a horizontal line at \ pixel row 19
Name: NLIN4 [Show more] Type: Subroutine Category: Drawing lines Summary: Draw a horizontal line at pixel row 19 to box in a title
Context: See this subroutine on its own page References: This subroutine is called as follows: * JMTB calls NLIN4 * TT213 calls NLIN4

This routine is used on the Inventory screen to draw a horizontal line at pixel row 19 to box in the title.
.NLIN4 LDA #19 \ Jump to NLIN2 to draw a horizontal line at pixel row BNE NLIN2 \ 19, returning from the subroutine with using a tail \ call (this BNE is effectively a JMP as A will never \ be zero)
Name: NLIN [Show more] Type: Subroutine Category: Drawing lines Summary: Draw a horizontal line at pixel row 23 to box in a title
Context: See this subroutine on its own page Variations: See code variations for this subroutine in the different versions References: This subroutine is called as follows: * TT22 calls NLIN

Draw a horizontal line at pixel row 23 and move the text cursor down one line.
.NLIN LDA #23 \ Set A = 23 so NLIN2 below draws a horizontal line at \ pixel row 23 INC YC \ Move the text cursor down one line \ Fall through into NLIN2 to draw the horizontal line \ at row 23
Name: NLIN2 [Show more] Type: Subroutine Category: Drawing lines Summary: Draw a screen-wide horizontal line at the pixel row in A
Context: See this subroutine on its own page Variations: See code variations for this subroutine in the different versions References: This subroutine is called as follows: * NLIN4 calls NLIN2 * TT22 calls NLIN2

This draws a line from (2, A) to (254, A), which is almost screen-wide and fits in nicely between the white borders without clashing with it.
Arguments: A The pixel row on which to draw the horizontal line
.NLIN2 STA Y1 \ Set Y1 = A LDX #2 \ Set X1 = 2, so (X1, Y1) = (2, A) STX X1 LDX #254 \ Set X2 = 254, so (X2, Y2) = (254, A) STX X2 BNE HLOIN \ Call HLOIN to draw a horizontal line from (2, A) to \ (254, A) and return from the subroutine (this BNE is \ effectively a JMP as A will never be zero)
Name: HLOIN2 [Show more] Type: Subroutine Category: Drawing lines Summary: Remove a line from the sun line heap and draw it on-screen
Context: See this subroutine on its own page Variations: See code variations for this subroutine in the different versions References: This subroutine is called as follows: * SUN (Part 2 of 4) calls HLOIN2 * SUN (Part 4 of 4) calls HLOIN2 * WPLS calls HLOIN2

Specifically, this does the following: * Set X1 and X2 to the x-coordinates of the ends of the horizontal line with centre YY(1 0) and length A to the left and right * Set the Y-th byte of the LSO block to 0 (i.e. remove this line from the sun line heap) * Draw a horizontal line from (X1, Y) to (X2, Y)
Arguments: YY(1 0) The x-coordinate of the centre point of the line A The half-width of the line, i.e. the contents of the Y-th byte of the sun line heap Y The number of the entry in the sun line heap (which is also the y-coordinate of the line)
Returns: Y Y is preserved
.HLOIN2 JSR EDGES \ Call EDGES to calculate X1 and X2 for the horizontal \ line centred on YY(1 0) and with half-width A STY Y1 \ Set Y1 = Y LDA #0 \ Set the Y-th byte of the LSO block to 0 STA LSO,Y \ Fall through into HLOIN to draw a horizontal line from \ (X1, Y) to (X2, Y)
Name: HLOIN [Show more] Type: Subroutine Category: Drawing lines Summary: Draw a horizontal line from (X1, Y1) to (X2, Y1) Deep dive: Drawing monochrome pixels in mode 4
Context: See this subroutine on its own page Variations: See code variations for this subroutine in the different versions References: This subroutine is called as follows: * NLIN2 calls HLOIN * SUN (Part 3 of 4) calls HLOIN * TT15 calls HLOIN * TTX66 calls HLOIN

We do not draw a pixel at the right end of the line. To understand how this routine works, you might find it helpful to read the deep dive on "Drawing monochrome pixels in mode 4".
Returns: Y Y is preserved
.HLOIN STY YSAV \ Store Y into YSAV, so we can preserve it across the \ call to this subroutine LDX X1 \ Set X = X1 CPX X2 \ If X1 = X2 then the start and end points are the same, BEQ HL6 \ so return from the subroutine (as HL6 contains an RTS) BCC HL5 \ If X1 < X2, jump to HL5 to skip the following code, as \ (X1, Y1) is already the left point LDA X2 \ Swap the values of X1 and X2, so we know that (X1, Y1) STA X1 \ is on the left and (X2, Y1) is on the right STX X2 TAX \ Set X = X1 .HL5 DEC X2 \ Decrement X2 so we do not draw a pixel at the end \ point LDA Y1 \ Set A = Y1 / 8, so A now contains the character row LSR A \ that will contain our horizontal line LSR A LSR A ORA #&60 \ As A < 32, this effectively adds &60 to A, which gives \ us the screen address of the character row (as each \ character row takes up 256 bytes, and the first \ character row is at screen address &6000, or page &60) STA SCH \ Store the page number of the character row in SCH, so \ the high byte of SC is set correctly for drawing our \ line LDA Y1 \ Set A = Y1 mod 8, which is the pixel row within the AND #7 \ character block at which we want to draw our line (as \ each character block has 8 rows) STA SC \ Store this value in SC, so SC(1 0) now contains the \ screen address of the far left end (x-coordinate = 0) \ of the horizontal pixel row that we want to draw our \ horizontal line on TXA \ Set Y = bits 3-7 of X1 AND #%11111000 TAY .HL1 TXA \ Set T = bits 3-7 of X1, which will contain the AND #%11111000 \ character number of the start of the line * 8 STA T LDA X2 \ Set A = bits 3-7 of X2, which will contain the AND #%11111000 \ character number of the end of the line * 8 SEC \ Set A = A - T, which will contain the number of SBC T \ character blocks we need to fill - 1 * 8 BEQ HL2 \ If A = 0 then the start and end character blocks are \ the same, so the whole line fits within one block, so \ jump down to HL2 to draw the line \ Otherwise the line spans multiple characters, so we \ start with the left character, then do any characters \ in the middle, and finish with the right character LSR A \ Set R = A / 8, so R now contains the number of LSR A \ character blocks we need to fill - 1 LSR A STA R LDA X1 \ Set X = X1 mod 8, which is the horizontal pixel number AND #7 \ within the character block where the line starts (as TAX \ each pixel line in the character block is 8 pixels \ wide) LDA TWFR,X \ Fetch a ready-made byte with X pixels filled in at the \ right end of the byte (so the filled pixels start at \ point X and go all the way to the end of the byte), \ which is the shape we want for the left end of the \ line EOR (SC),Y \ Store this into screen memory at SC(1 0), using EOR STA (SC),Y \ logic so it merges with whatever is already on-screen, \ so we have now drawn the line's left cap TYA \ Set Y = Y + 8 so (SC),Y points to the next character ADC #8 \ block along, on the same pixel row as before TAY LDX R \ Fetch the number of character blocks we need to fill \ from R DEX \ Decrement the number of character blocks in X BEQ HL3 \ If X = 0 then we only have the last block to do (i.e. \ the right cap), so jump down to HL3 to draw it CLC \ Otherwise clear the C flag so we can do some additions \ while we draw the character blocks with full-width \ lines in them .HLL1 LDA #%11111111 \ Store a full-width 8-pixel horizontal line in SC(1 0) EOR (SC),Y \ so that it draws the line on-screen, using EOR logic STA (SC),Y \ so it merges with whatever is already on-screen TYA \ Set Y = Y + 8 so (SC),Y points to the next character ADC #8 \ block along, on the same pixel row as before TAY DEX \ Decrement the number of character blocks in X BNE HLL1 \ Loop back to draw more full-width lines, if we have \ any more to draw .HL3 LDA X2 \ Now to draw the last character block at the right end AND #7 \ of the line, so set X = X2 mod 8, which is the TAX \ horizontal pixel number where the line ends LDA TWFL,X \ Fetch a ready-made byte with X pixels filled in at the \ left end of the byte (so the filled pixels start at \ the left edge and go up to point X), which is the \ shape we want for the right end of the line EOR (SC),Y \ Store this into screen memory at SC(1 0), using EOR STA (SC),Y \ logic so it merges with whatever is already on-screen, \ so we have now drawn the line's right cap LDY YSAV \ Restore Y from YSAV, so that it's preserved across the \ call to this subroutine RTS \ Return from the subroutine .HL2 \ If we get here then the entire horizontal line fits \ into one character block LDA X1 \ Set X = X1 mod 8, which is the horizontal pixel number AND #7 \ within the character block where the line starts (as TAX \ each pixel line in the character block is 8 pixels \ wide) LDA TWFR,X \ Fetch a ready-made byte with X pixels filled in at the STA T \ right end of the byte (so the filled pixels start at \ point X and go all the way to the end of the byte) LDA X2 \ Set X = X2 mod 8, which is the horizontal pixel number AND #7 \ where the line ends TAX LDA TWFL,X \ Fetch a ready-made byte with X pixels filled in at the \ left end of the byte (so the filled pixels start at \ the left edge and go up to point X) AND T \ We now have two bytes, one (T) containing pixels from \ the starting point X1 onwards, and the other (A) \ containing pixels up to the end point at X2, so we can \ get the actual line we want to draw by AND'ing them \ together. For example, if we want to draw a line from \ point 2 to point 5 (within the row of 8 pixels \ numbered from 0 to 7), we would have this: \ \ T = %00111111 \ A = %11111100 \ T AND A = %00111100 \ \ So we can stick T AND A in screen memory to get the \ line we want, which is what we do here by setting \ A = A AND T EOR (SC),Y \ Store our horizontal line byte into screen memory at STA (SC),Y \ SC(1 0), using EOR logic so it merges with whatever is \ already on-screen LDY YSAV \ Restore Y from YSAV, so that it's preserved RTS \ Return from the subroutine
Name: TWFL [Show more] Type: Variable Category: Drawing lines Summary: Ready-made character rows for the left end of a horizontal line in mode 4
Context: See this variable on its own page Variations: See code variations for this variable in the different versions References: This variable is used as follows: * HLOIN uses TWFL

Ready-made bytes for plotting horizontal line end caps in mode 4 (the top part of the split screen). This table provides a byte with pixels at the left end, which is used for the right end of the line. See the HLOIN routine for details.
.TWFL EQUB %10000000 EQUB %11000000 EQUB %11100000 EQUB %11110000 EQUB %11111000 EQUB %11111100 EQUB %11111110
Name: TWFR [Show more] Type: Variable Category: Drawing lines Summary: Ready-made character rows for the right end of a horizontal line in mode 4
Context: See this variable on its own page Variations: See code variations for this variable in the different versions References: This variable is used as follows: * HLOIN uses TWFR

Ready-made bytes for plotting horizontal line end caps in mode 4 (the top part of the split screen). This table provides a byte with pixels at the right end, which is used for the left end of the line. See the HLOIN routine for details.
.TWFR EQUB %11111111 EQUB %01111111 EQUB %00111111 EQUB %00011111 EQUB %00001111 EQUB %00000111 EQUB %00000011 EQUB %00000001
Name: PX3 [Show more] Type: Subroutine Category: Drawing pixels Summary: Plot a single pixel at (X, Y) within a character block
Context: See this subroutine on its own page References: This subroutine is called as follows: * PIXEL calls PX3

This routine is called from PIXEL to set 1 pixel within a character block for a distant point (i.e. where the distance ZZ >= &90). See the PIXEL routine for details, as this routine is effectively part of PIXEL.
Arguments: X The x-coordinate of the pixel within the character block Y The y-coordinate of the pixel within the character block SC(1 0) The screen address of the character block T1 The value of Y to restore on exit, so Y is preserved by the call to PIXEL
.PX3 LDA TWOS,X \ Fetch a 1-pixel byte from TWOS and EOR it into SC+Y EOR (SC),Y STA (SC),Y LDY T1 \ Restore Y from T1, so Y is preserved by the routine RTS \ Return from the subroutine
Name: PIX1 [Show more] Type: Subroutine Category: Maths (Arithmetic) Summary: Calculate (YY+1 SYL+Y) = (A P) + (S R) and draw stardust particle
Context: See this subroutine on its own page Variations: See code variations for this subroutine in the different versions References: No direct references to this subroutine in this source file

Calculate the following: (YY+1 SYL+Y) = (A P) + (S R) and draw a stardust particle at (X1,Y1) with distance ZZ.
Arguments: (A P) A is the angle ALPHA or BETA, P is always 0 (S R) YY(1 0) or YY(1 0) + Q * A Y Stardust particle number X1 The x-coordinate offset Y1 The y-coordinate offset ZZ The distance of the point (further away = smaller point)
.PIX1 JSR ADD \ Set (A X) = (A P) + (S R) STA YY+1 \ Set YY+1 to A, the high byte of the result TXA \ Set SYL+Y to X, the low byte of the result STA SYL,Y \ Fall through into PIX1 to draw the stardust particle \ at (X1,Y1)
Name: PIXEL2 [Show more] Type: Subroutine Category: Drawing pixels Summary: Draw a stardust particle relative to the screen centre
Context: See this subroutine on its own page Variations: See code variations for this subroutine in the different versions References: This subroutine is called as follows: * FLIP calls PIXEL2

Draw a point (X1, Y1) from the middle of the screen with a size determined by a distance value. Used to draw stardust particles.
Arguments: X1 The x-coordinate offset Y1 The y-coordinate offset (positive means up the screen from the centre, negative means down the screen) ZZ The distance of the point (further away = smaller point)
.PIXEL2 LDA X1 \ Fetch the x-coordinate offset into A BPL PX1 \ If the x-coordinate offset is positive, jump to PX1 \ to skip the following negation EOR #%01111111 \ The x-coordinate offset is negative, so flip all the CLC \ bits apart from the sign bit and add 1, to convert it ADC #1 \ from a sign-magnitude number to a signed number .PX1 EOR #%10000000 \ Set X = X1 + 128 TAX \ \ So X is now the offset converted to an x-coordinate, \ centred on x-coordinate 128 LDA Y1 \ Fetch the y-coordinate offset into A and clear the AND #%01111111 \ sign bit, so A = |Y1| CMP #96 \ If |Y1| >= 96 then it's off the screen (as 96 is half BCS PX4 \ the screen height), so return from the subroutine (as \ PX4 contains an RTS) LDA Y1 \ Fetch the y-coordinate offset into A BPL PX2 \ If the y-coordinate offset is positive, jump to PX2 \ to skip the following negation EOR #%01111111 \ The y-coordinate offset is negative, so flip all the ADC #1 \ bits apart from the sign bit and subtract 1, to negate \ it to a positive number, i.e. A is now |Y1| .PX2 STA T \ Set A = 97 - Y1 LDA #97 \ SBC T \ So if Y is positive we display the point up from the \ centre at y-coordinate 97, while a negative Y means \ down from the centre \ Fall through into PIXEL to draw the stardust at the \ screen coordinates in (X, A)
Name: PIXEL [Show more] Type: Subroutine Category: Drawing pixels Summary: Draw a 1-pixel dot, 2-pixel dash or 4-pixel square Deep dive: Drawing monochrome pixels in mode 4
Context: See this subroutine on its own page Variations: See code variations for this subroutine in the different versions References: This subroutine is called as follows: * TT22 calls PIXEL * PIXEL2 calls via PX4

Draw a point at screen coordinate (X, A) with the point size determined by the distance in ZZ. This applies to the top part of the screen (the monochrome mode 4 portion).
Arguments: X The screen x-coordinate of the point to draw A The screen y-coordinate of the point to draw ZZ The distance of the point (further away = smaller point)
Returns: Y Y is preserved
Other entry points: PX4 Contains an RTS
.PIXEL STY T1 \ Store Y in T1 TAY \ Copy A into Y, for use later LSR A \ Set SCH = &60 + A >> 3 LSR A LSR A ORA #&60 STA SCH TXA \ Set SC = (X >> 3) * 8 AND #%11111000 STA SC TYA \ Set Y = Y AND %111 AND #%00000111 TAY TXA \ Set X = X AND %111 AND #%00000111 TAX LDA ZZ \ If distance in ZZ >= 144, then this point is a very CMP #144 \ long way away, so jump to PX3 to fetch a 1-pixel point BCS PX3 \ from TWOS and EOR it into SC+Y LDA TWOS2,X \ Otherwise fetch a 2-pixel dash from TWOS2 and EOR it EOR (SC),Y \ into SC+Y STA (SC),Y LDA ZZ \ If distance in ZZ >= 80, then this point is a medium CMP #80 \ distance away, so jump to PX13 to stop drawing, as a BCS PX13 \ 2-pixel dash is enough \ Otherwise we keep going to draw another 2 pixel point \ either above or below the one we just drew, to make a \ 4-pixel square DEY \ Reduce Y by 1 to point to the pixel row above the one BPL PX14 \ we just plotted, and if it is still positive, jump to \ PX14 to draw our second 2-pixel dash LDY #1 \ Reducing Y by 1 made it negative, which means Y was \ 0 before we did the DEY above, so set Y to 1 to point \ to the pixel row after the one we just plotted .PX14 LDA TWOS2,X \ Fetch a 2-pixel dash from TWOS2 and EOR it into this EOR (SC),Y \ second row to make a 4-pixel square STA (SC),Y .PX13 LDY T1 \ Restore Y from T1, so Y is preserved by the routine .PX4 RTS \ Return from the subroutine
Name: BLINE [Show more] Type: Subroutine Category: Drawing circles Summary: Draw a circle segment and add it to the ball line heap Deep dive: The ball line heap Drawing circles
Context: See this subroutine on its own page Variations: See code variations for this subroutine in the different versions References: This subroutine is called as follows: * CIRCLE2 calls BLINE

Draw a single segment of a circle, adding the point to the ball line heap.
Arguments: CNT The number of this segment STP The step size for the circle K6(1 0) The x-coordinate of the new point on the circle, as a screen coordinate (T X) The y-coordinate of the new point on the circle, as an offset from the centre of the circle FLAG Set to &FF for the first call, so it sets up the first point in the heap but waits until the second call before drawing anything (as we need two points, i.e. two calls, before we can draw a line) K The circle's radius K3(1 0) Pixel x-coordinate of the centre of the circle K4(1 0) Pixel y-coordinate of the centre of the circle K5(1 0) Screen x-coordinate of the previous point added to the ball line heap (if this is not the first point) K5(3 2) Screen y-coordinate of the previous point added to the ball line heap (if this is not the first point) SWAP If non-zero, we swap (X1, Y1) and (X2, Y2)
Returns: CNT CNT is updated to CNT + STP A The new value of CNT K5(1 0) Screen x-coordinate of the point that we just added to the ball line heap K5(3 2) Screen y-coordinate of the point that we just added to the ball line heap FLAG Set to 0
.BLINE TXA \ Set K6(3 2) = (T X) + K4(1 0) ADC K4 \ = y-coord of centre + y-coord of new point STA K6+2 \ LDA K4+1 \ so K6(3 2) now contains the y-coordinate of the new ADC T \ point on the circle but as a screen coordinate, to go STA K6+3 \ along with the screen y-coordinate in K6(1 0) LDA FLAG \ If FLAG = 0, jump down to BL1 BEQ BL1 INC FLAG \ Flag is &FF so this is the first call to BLINE, so \ increment FLAG to set it to 0, as then the next time \ we call BLINE it can draw the first line, from this \ point to the next .BL5 \ The following inserts a &FF marker into the LSY2 line \ heap to indicate that the next call to BLINE should \ store both the (X1, Y1) and (X2, Y2) points. We do \ this on the very first call to BLINE (when FLAG is \ &FF), and on subsequent calls if the segment does not \ fit on-screen, in which case we don't draw or store \ that segment, and we start a new segment with the next \ call to BLINE that does fit on-screen LDY LSP \ If byte LSP-1 of LSY2 = &FF, jump to BL7 to tidy up LDA #&FF \ and return from the subroutine, as the point that has CMP LSY2-1,Y \ been passed to BLINE is the start of a segment, so all BEQ BL7 \ we need to do is save the coordinate in K5, without \ moving the pointer in LSP STA LSY2,Y \ Otherwise we just tried to plot a segment but it \ didn't fit on-screen, so put the &FF marker into the \ heap for this point, so the next call to BLINE starts \ a new segment INC LSP \ Increment LSP to point to the next point in the heap BNE BL7 \ Jump to BL7 to tidy up and return from the subroutine \ (this BNE is effectively a JMP, as LSP will never be \ zero) .BL1 LDA K5 \ Set XX15 = K5 = x_lo of previous point STA XX15 LDA K5+1 \ Set XX15+1 = K5+1 = x_hi of previous point STA XX15+1 LDA K5+2 \ Set XX15+2 = K5+2 = y_lo of previous point STA XX15+2 LDA K5+3 \ Set XX15+3 = K5+3 = y_hi of previous point STA XX15+3 LDA K6 \ Set XX15+4 = x_lo of new point STA XX15+4 LDA K6+1 \ Set XX15+5 = x_hi of new point STA XX15+5 LDA K6+2 \ Set XX12 = y_lo of new point STA XX12 LDA K6+3 \ Set XX12+1 = y_hi of new point STA XX12+1 JSR LL145 \ Call LL145 to see if the new line segment needs to be \ clipped to fit on-screen, returning the clipped line's \ end-points in (X1, Y1) and (X2, Y2) BCS BL5 \ If the C flag is set then the line is not visible on \ screen anyway, so jump to BL5, to avoid drawing and \ storing this line LDA SWAP \ If SWAP = 0, then we didn't have to swap the line BEQ BL9 \ coordinates around during the clipping process, so \ jump to BL9 to skip the following swap LDA X1 \ Otherwise the coordinates were swapped by the call to LDY X2 \ LL145 above, so we swap (X1, Y1) and (X2, Y2) back STA X2 \ again STY X1 LDA Y1 LDY Y2 STA Y2 STY Y1 .BL9 LDY LSP \ Set Y = LSP LDA LSY2-1,Y \ If byte LSP-1 of LSY2 is not &FF, jump down to BL8 CMP #&FF \ to skip the following (X1, Y1) code BNE BL8 \ Byte LSP-1 of LSY2 is &FF, which indicates that we \ need to store (X1, Y1) in the heap LDA X1 \ Store X1 in the LSP-th byte of LSX2 STA LSX2,Y LDA Y1 \ Store Y1 in the LSP-th byte of LSY2 STA LSY2,Y INY \ Increment Y to point to the next byte in LSX2/LSY2 .BL8 LDA X2 \ Store X2 in the LSP-th byte of LSX2 STA LSX2,Y LDA Y2 \ Store Y2 in the LSP-th byte of LSX2 STA LSY2,Y INY \ Increment Y to point to the next byte in LSX2/LSY2 STY LSP \ Update LSP to point to the same as Y JSR LOIN \ Draw a line from (X1, Y1) to (X2, Y2) LDA XX13 \ If XX13 is non-zero, jump up to BL5 to add a &FF BNE BL5 \ marker to the end of the line heap. XX13 is non-zero \ after the call to the clipping routine LL145 above if \ the end of the line was clipped, meaning the next line \ sent to BLINE can't join onto the end but has to start \ a new segment, and that's what inserting the &FF \ marker does .BL7 LDA K6 \ Copy the data for this step point from K6(3 2 1 0) STA K5 \ into K5(3 2 1 0), for use in the next call to BLINE: LDA K6+1 \ STA K5+1 \ * K5(1 0) = screen x-coordinate of this point LDA K6+2 \ STA K5+2 \ * K5(3 2) = screen y-coordinate of this point LDA K6+3 \ STA K5+3 \ They now become the "previous point" in the next call LDA CNT \ Set CNT = CNT + STP CLC ADC STP STA CNT RTS \ Return from the subroutine
Name: FLIP [Show more] Type: Subroutine Category: Stardust Summary: Reflect the stardust particles in the screen diagonal and redraw the stardust field
Context: See this subroutine on its own page Variations: See code variations for this subroutine in the different versions References: No direct references to this subroutine in this source file

Swap the x- and y-coordinates of all the stardust particles and draw the new set of particles. Called by LOOK1 when we switch views. This is a quick way of making the stardust field in the new view feel different without having to generate a whole new field. If you look carefully at the stardust field when you switch views, you can just about see that the new field is a reflection of the previous field in the screen diagonal, i.e. in the line from bottom left to top right. This is the line where x = y when the origin is in the middle of the screen, and positive x and y are right and up, which is the coordinate system we use for stardust).
.FLIP LDY NOSTM \ Set Y to the current number of stardust particles, so \ we can use it as a counter through all the stardust .FLL1 LDX SY,Y \ Copy the Y-th particle's y-coordinate from SY+Y into X LDA SX,Y \ Copy the Y-th particle's x-coordinate from SX+Y into STA Y1 \ both Y1 and the particle's y-coordinate STA SY,Y TXA \ Copy the Y-th particle's original y-coordinate into STA X1 \ both X1 and the particle's x-coordinate, so the x- and STA SX,Y \ y-coordinates are now swapped and (X1, Y1) contains \ the particle's new coordinates LDA SZ,Y \ Fetch the Y-th particle's distance from SZ+Y into ZZ STA ZZ JSR PIXEL2 \ Draw a stardust particle at (X1,Y1) with distance ZZ DEY \ Decrement the counter to point to the next particle of \ stardust BNE FLL1 \ Loop back to FLL1 until we have moved all the stardust \ particles RTS \ Return from the subroutine
Name: PRXS [Show more] Type: Variable Category: Equipment Summary: Equipment prices
Context: See this variable on its own page Variations: See code variations for this variable in the different versions References: This variable is used as follows: * EQSHP uses PRXS * prx uses PRXS

Equipment prices are stored as 10 * the actual value, so we can support prices with fractions of credits (0.1 Cr). This is used for the price of fuel only.
.PRXS EQUW 1 \ 0 Fuel, calculated in EQSHP 140.0 Cr (full tank) EQUW 300 \ 1 Missile 30.0 Cr EQUW 4000 \ 2 Large Cargo Bay 400.0 Cr EQUW 6000 \ 3 E.C.M. System 600.0 Cr EQUW 4000 \ 4 Extra Pulse Lasers 400.0 Cr EQUW 10000 \ 5 Extra Beam Lasers 1000.0 Cr EQUW 5250 \ 6 Fuel Scoops 525.0 Cr EQUW 10000 \ 7 Escape Pod 1000.0 Cr EQUW 9000 \ 8 Energy Bomb 900.0 Cr EQUW 15000 \ 9 Energy Unit 1500.0 Cr EQUW 10000 \ 10 Docking Computer 1000.0 Cr EQUW 50000 \ 11 Galactic Hyperspace 5000.0 Cr EQUW 60000 \ 12 Extra Military Lasers 6000.0 Cr EQUW 8000 \ 13 Extra Mining Lasers 800.0 Cr
Name: STATUS [Show more] Type: Subroutine Category: Status Summary: Show the Status Mode screen (red key f8) Deep dive: Combat rank
Context: See this subroutine on its own page Variations: See code variations for this subroutine in the different versions References: This subroutine is called as follows: * TT102 calls STATUS
.st4 \ We call this from st5 below with the high byte of the \ kill tally in A, which is non-zero, and want to return \ with the following in X, depending on our rating: \ \ Competent = 6 \ Dangerous = 7 \ Deadly = 8 \ Elite = 9 \ \ The high bytes of the top tier ratings are as follows, \ so this a relatively simple calculation: \ \ Competent = 1 to 2 \ Dangerous = 2 to 9 \ Deadly = 10 to 24 \ Elite = 25 and up LDX #9 \ Set X to 9 for an Elite rating CMP #25 \ If A >= 25, jump to st3 to print out our rating, as we BCS st3 \ are Elite DEX \ Decrement X to 8 for a Deadly rating CMP #10 \ If A >= 10, jump to st3 to print out our rating, as we BCS st3 \ are Deadly DEX \ Decrement X to 7 for a Dangerous rating CMP #2 \ If A >= 2, jump to st3 to print out our rating, as we BCS st3 \ are Dangerous DEX \ Decrement X to 6 for a Competent rating BNE st3 \ Jump to st3 to print out our rating, as we are \ Competent (this BNE is effectively a JMP as A will \ never be zero) .STATUS LDA #8 \ Clear the top part of the screen, draw a white border, JSR TT66 \ and set the current view type in QQ11 to 8 (Status \ Mode screen) JSR TT111 \ Select the system closest to galactic coordinates \ (QQ9, QQ10) LDA #7 \ Move the text cursor to column 7 STA XC LDA #126 \ Print recursive token 126, which prints the top JSR NLIN3 \ four lines of the Status Mode screen: \ \ COMMANDER {commander name} \ \ \ Present System : {current system name} \ Hyperspace System : {selected system name} \ Condition : \ \ and draw a horizontal line at pixel row 19 to box \ in the title LDA #205 \ Print extended token 205 ("DOCKED") JSR DETOK JSR TT67 \ Print a newline LDA #125 \ Print recursive token 125, which prints the next JSR spc \ three lines of the Status Mode screen: \ \ Fuel: {fuel level} Light Years \ Cash: {cash} Cr \ Legal Status: \ \ followed by a space LDA #19 \ Set A to token 133 ("CLEAN") LDY FIST \ Fetch our legal status, and if it is 0, we are clean, BEQ st5 \ so jump to st5 to print "Clean" CPY #50 \ Set the C flag if Y >= 50, so C is set if we have \ a legal status of 50+ (i.e. we are a fugitive) ADC #1 \ Add 1 + C to A, so if C is not set (i.e. we have a \ legal status between 1 and 49) then A is set to token \ 134 ("OFFENDER"), and if C is set (i.e. we have a \ legal status of 50+) then A is set to token 135 \ ("FUGITIVE") .st5 JSR plf \ Print the text token in A (which contains our legal \ status) followed by a newline LDA #16 \ Print recursive token 130 ("RATING:") followed by a JSR spc \ space LDA TALLY+1 \ Fetch the high byte of the kill tally, and if it is BNE st4 \ not zero, then we have more than 256 kills, so jump \ to st4 to work out whether we are Competent, \ Dangerous, Deadly or Elite \ Otherwise we have fewer than 256 kills, so we are one \ of Harmless, Mostly Harmless, Poor, Average or Above \ Average TAX \ Set X to 0 (as A is 0) LDA TALLY \ Set A = lower byte of tally / 4 LSR A LSR A .st5L \ We now loop through bits 2 to 7, shifting each of them \ off the end of A until there are no set bits left, and \ incrementing X for each shift, so at the end of the \ process, X contains the position of the leftmost 1 in \ A. Looking at the rank values in TALLY: \ \ Harmless = %00000000 to %00000011 \ Mostly Harmless = %00000100 to %00000111 \ Poor = %00001000 to %00001111 \ Average = %00010000 to %00011111 \ Above Average = %00100000 to %11111111 \ \ we can see that the values returned by this process \ are: \ \ Harmless = 1 \ Mostly Harmless = 2 \ Poor = 3 \ Average = 4 \ Above Average = 5 INX \ Increment X for each shift LSR A \ Shift A to the right BNE st5L \ Keep looping around until A = 0, which means there are \ no set bits left in A .st3 TXA \ A now contains our rating as a value of 1 to 9, so \ transfer X to A, so we can print it out CLC \ Print recursive token 135 + A, which will be in the ADC #21 \ range 136 ("HARMLESS") to 144 ("---- E L I T E ----") JSR plf \ followed by a newline LDA #18 \ Print recursive token 132, which prints the next bit JSR plf2 \ of the Status Mode screen: \ \ EQUIPMENT: \ \ followed by a newline and an indent of 6 characters LDA CRGO \ If our ship's cargo capacity is < 26 (i.e. we do not CMP #26 \ have a cargo bay extension), skip the following two BCC P%+7 \ instructions LDA #107 \ We do have a cargo bay extension, so print recursive JSR plf2 \ token 107 ("LARGE CARGO{sentence case} BAY"), followed \ by a newline and an indent of 6 characters LDA BST \ If we don't have fuel scoops fitted, skip the BEQ P%+7 \ following two instructions LDA #111 \ We do have fuel scoops fitted, so print recursive JSR plf2 \ token 111 ("FUEL SCOOPS"), followed by a newline and \ an indent of 6 characters LDA ECM \ If we don't have an E.C.M. fitted, skip the following BEQ P%+7 \ two instructions LDA #108 \ We do have an E.C.M. fitted, so print recursive token JSR plf2 \ 108 ("E.C.M.SYSTEM"), followed by a newline and an \ indent of 6 characters LDA #113 \ We now cover the four pieces of equipment whose flags STA XX4 \ are stored in BOMB through BOMB+3, and whose names \ correspond with text tokens 113 through 116: \ \ BOMB+0 = BOMB = token 113 = Energy bomb \ BOMB+1 = ENGY = token 114 = Energy unit \ BOMB+2 = DKCMP = token 115 = Docking computer \ BOMB+3 = GHYP = token 116 = Galactic hyperdrive \ \ We can print these out using a loop, so we set XX4 to \ 113 as a counter (and we also set A as well, to pass \ through to plf2) .stqv TAY \ Fetch byte BOMB+0 through BOMB+4 for values of XX4 LDX BOMB-113,Y \ from 113 through 117 BEQ P%+5 \ If it is zero then we do not own that piece of \ equipment, so skip the next instruction JSR plf2 \ Print the recursive token in A from 113 ("ENERGY \ BOMB") through 116 ("GALACTIC HYPERSPACE "), followed \ by a newline and an indent of 6 characters INC XX4 \ Increment the counter (and A as well) LDA XX4 CMP #117 \ If A < 117, loop back up to stqv to print the next BCC stqv \ piece of equipment LDX #0 \ Now to print our ship's lasers, so set a counter in X \ to count through the four views (0 = front, 1 = rear, \ 2 = left, 3 = right) .st STX CNT \ Store the view number in CNT LDY LASER,X \ Fetch the laser power for view X, and if we do not BEQ st1 \ have a laser fitted to that view, jump to st1 to move \ on to the next one TXA \ Print recursive token 96 + X, which will print from 96 CLC \ ("FRONT") through to 99 ("RIGHT"), followed by a space ADC #96 JSR spc LDA #103 \ Set A to token 103 ("PULSE LASER") LDX CNT \ Retrieve the view number from CNT that we stored above LDY LASER,X \ Set Y = the laser power for view X CPY #128+POW \ If the laser power for view X is not #POW+128 (beam BNE P%+4 \ laser), skip the next LDA instruction LDA #104 \ This sets A = 104 if the laser in view X is a beam \ laser (token 104 is "BEAM LASER") CPY #Armlas \ If the laser power for view X is not #Armlas (military BNE P%+4 \ laser), skip the next LDA instruction LDA #117 \ This sets A = 117 if the laser in view X is a military \ laser (token 117 is "MILITARY LASER") CPY #Mlas \ If the laser power for view X is not #Mlas (mining BNE P%+4 \ laser), skip the next LDA instruction LDA #118 \ This sets A = 118 if the laser in view X is a mining \ laser (token 118 is "MINING LASER") JSR plf2 \ Print the text token in A (which contains the laser \ type) followed by a newline and an indent of 6 \ characters .st1 LDX CNT \ Increment the counter in X and CNT to point to the INX \ next view CPX #4 \ If this isn't the last of the four views, jump back up BCC st \ to st to print out the next one RTS \ Return from the subroutine
Name: plf2 [Show more] Type: Subroutine Category: Text Summary: Print text followed by a newline and indent of 6 characters
Context: See this subroutine on its own page Variations: See code variations for this subroutine in the different versions References: This subroutine is called as follows: * STATUS calls plf2

Print a text token followed by a newline, and indent the next line to text column 6.
Arguments: A The text token to be printed
.plf2 JSR plf \ Print the text token in A followed by a newline LDX #6 \ Move the text cursor to column 6 STX XC RTS \ Return from the subroutine
Name: TENS [Show more] Type: Variable Category: Text Summary: A constant used when printing large numbers in BPRNT Deep dive: Printing decimal numbers
Context: See this variable on its own page References: This variable is used as follows: * BPRNT uses TENS

Contains the four low bytes of the value 100,000,000,000 (100 billion). The maximum number of digits that we can print with the BPRNT routine is 11, so the biggest number we can print is 99,999,999,999. This maximum number plus 1 is 100,000,000,000, which in hexadecimal is: & 17 48 76 E8 00 The TENS variable contains the lowest four bytes in this number, with the most significant byte first, i.e. 48 76 E8 00. This value is used in the BPRNT routine when working out which decimal digits to print when printing a number.
.TENS EQUD &00E87648
Name: pr2 [Show more] Type: Subroutine Category: Text Summary: Print an 8-bit number, left-padded to 3 digits, and optional point
Context: See this subroutine on its own page References: This subroutine is called as follows: * EQSHP calls pr2 * fwl calls pr2 * tal calls pr2 * TT210 calls pr2 * TT25 calls pr2 * TT151 calls via pr2+2

Print the 8-bit number in X to 3 digits, left-padding with spaces for numbers with fewer than 3 digits (so numbers < 100 are right-aligned). Optionally include a decimal point.
Arguments: X The number to print C flag If set, include a decimal point
Other entry points: pr2+2 Print the 8-bit number in X to the number of digits in A
.pr2 LDA #3 \ Set A to the number of digits (3) LDY #0 \ Zero the Y register, so we can fall through into TT11 \ to print the 16-bit number (Y X) to 3 digits, which \ effectively prints X to 3 digits as the high byte is \ zero
Name: TT11 [Show more] Type: Subroutine Category: Text Summary: Print a 16-bit number, left-padded to n digits, and optional point
Context: See this subroutine on its own page References: This subroutine is called as follows: * EQSHP calls TT11 * pr5 calls TT11

Print the 16-bit number in (Y X) to a specific number of digits, left-padding with spaces for numbers with fewer digits (so lower numbers will be right- aligned). Optionally include a decimal point.
Arguments: X The low byte of the number to print Y The high byte of the number to print A The number of digits C flag If set, include a decimal point
.TT11 STA U \ We are going to use the BPRNT routine (below) to \ print this number, so we store the number of digits \ in U, as that's what BPRNT takes as an argument LDA #0 \ BPRNT takes a 32-bit number in K to K+3, with the STA K \ most significant byte first (big-endian), so we set STA K+1 \ the two most significant bytes to zero (K and K+1) STY K+2 \ and store (Y X) in the least two significant bytes STX K+3 \ (K+2 and K+3), so we are going to print the 32-bit \ number (0 0 Y X) \ Finally we fall through into BPRNT to print out the \ number in K to K+3, which now contains (Y X), to 3 \ digits (as U = 3), using the same C flag as when pr2 \ was called to control the decimal point
Name: BPRNT [Show more] Type: Subroutine Category: Text Summary: Print a 32-bit number, left-padded to a specific number of digits, with an optional decimal point Deep dive: Printing decimal numbers
Context: See this subroutine on its own page Variations: See code variations for this subroutine in the different versions References: This subroutine is called as follows: * csh calls BPRNT * SVE calls BPRNT

Print the 32-bit number stored in K(0 1 2 3) to a specific number of digits, left-padding with spaces for numbers with fewer digits (so lower numbers are right-aligned). Optionally include a decimal point. See the deep dive on "Printing decimal numbers" for details of the algorithm used in this routine.
Arguments: K(0 1 2 3) The number to print, stored with the most significant byte in K and the least significant in K+3 (i.e. as a big-endian number, which is the opposite way to how the 6502 assembler stores addresses, for example) U The maximum number of digits to print, including the decimal point (spaces will be used on the left to pad out the result to this width, so the number is right- aligned to this width). U must be 11 or less C flag If set, include a decimal point followed by one fractional digit (i.e. show the number to 1 decimal place). In this case, the number in K(0 1 2 3) contains 10 * the number we end up printing, so to print 123.4, we would pass 1234 in K(0 1 2 3) and would set the C flag to include the decimal point
.BPRNT LDX #11 \ Set T to the maximum number of digits allowed (11 STX T \ characters, which is the number of digits in 10 \ billion). We will use this as a flag when printing \ characters in TT37 below PHP \ Make a copy of the status register (in particular \ the C flag) so we can retrieve it later BCC TT30 \ If the C flag is clear, we do not want to print a \ decimal point, so skip the next two instructions DEC T \ As we are going to show a decimal point, decrement DEC U \ both the number of characters and the number of \ digits (as one of them is now a decimal point) .TT30 LDA #11 \ Set A to 11, the maximum number of digits allowed SEC \ Set the C flag so we can do subtraction without the \ C flag affecting the result STA XX17 \ Store the maximum number of digits allowed (11) in \ XX17 SBC U \ Set U = 11 - U + 1, so U now contains the maximum STA U \ number of digits minus the number of digits we want INC U \ to display, plus 1 (so this is the number of digits \ we should skip before starting to print the number \ itself, and the plus 1 is there to ensure we print at \ least one digit) LDY #0 \ In the main loop below, we use Y to count the number \ of times we subtract 10 billion to get the leftmost \ digit, so set this to zero STY S \ In the main loop below, we use location S as an \ 8-bit overflow for the 32-bit calculations, so \ we need to set this to 0 before joining the loop JMP TT36 \ Jump to TT36 to start the process of printing this \ number's digits .TT35 \ This subroutine multiplies K(S 0 1 2 3) by 10 and \ stores the result back in K(S 0 1 2 3), using the fact \ that K * 10 = (K * 2) + (K * 2 * 2 * 2) ASL K+3 \ Set K(S 0 1 2 3) = K(S 0 1 2 3) * 2 by rotating left ROL K+2 ROL K+1 ROL K ROL S LDX #3 \ Now we want to make a copy of the newly doubled K in \ XX15, so we can use it for the first (K * 2) in the \ equation above, so set up a counter in X for copying \ four bytes, starting with the last byte in memory \ (i.e. the least significant) .tt35 LDA K,X \ Copy the X-th byte of K(0 1 2 3) to the X-th byte of STA XX15,X \ XX15(0 1 2 3), so that XX15 will contain a copy of \ K(0 1 2 3) once we've copied all four bytes DEX \ Decrement the loop counter BPL tt35 \ Loop back to copy the next byte until we have copied \ all four LDA S \ Store the value of location S, our overflow byte, in STA XX15+4 \ XX15+4, so now XX15(4 0 1 2 3) contains a copy of \ K(S 0 1 2 3), which is the value of (K * 2) that we \ want to use in our calculation ASL K+3 \ Now to calculate the (K * 2 * 2 * 2) part. We still ROL K+2 \ have (K * 2) in K(S 0 1 2 3), so we just need to shift ROL K+1 \ it twice. This is the first one, so we do this: ROL K \ ROL S \ K(S 0 1 2 3) = K(S 0 1 2 3) * 2 = K * 4 ASL K+3 \ And then we do it again, so that means: ROL K+2 \ ROL K+1 \ K(S 0 1 2 3) = K(S 0 1 2 3) * 2 = K * 8 ROL K ROL S CLC \ Clear the C flag so we can do addition without the \ C flag affecting the result LDX #3 \ By now we've got (K * 2) in XX15(4 0 1 2 3) and \ (K * 8) in K(S 0 1 2 3), so the final step is to add \ these two 32-bit numbers together to get K * 10. \ So we set a counter in X for four bytes, starting \ with the last byte in memory (i.e. the least \ significant) .tt36 LDA K,X \ Fetch the X-th byte of K into A ADC XX15,X \ Add the X-th byte of XX15 to A, with carry STA K,X \ Store the result in the X-th byte of K DEX \ Decrement the loop counter BPL tt36 \ Loop back to add the next byte, moving from the least \ significant byte to the most significant, until we \ have added all four LDA XX15+4 \ Finally, fetch the overflow byte from XX15(4 0 1 2 3) ADC S \ And add it to the overflow byte from K(S 0 1 2 3), \ with carry STA S \ And store the result in the overflow byte from \ K(S 0 1 2 3), so now we have our desired result, i.e. \ \ K(S 0 1 2 3) = K(S 0 1 2 3) * 10 LDY #0 \ In the main loop below, we use Y to count the number \ of times we subtract 10 billion to get the leftmost \ digit, so set this to zero so we can rejoin the main \ loop for another subtraction process .TT36 \ This is the main loop of our digit-printing routine. \ In the following loop, we are going to count the \ number of times that we can subtract 10 million and \ store that count in Y, which we have already set to 0 LDX #3 \ Our first calculation concerns 32-bit numbers, so \ set up a counter for a four-byte loop SEC \ Set the C flag so we can do subtraction without the \ C flag affecting the result .tt37 \ We now loop through each byte in turn to do this: \ \ XX15(4 0 1 2 3) = K(S 0 1 2 3) - 100,000,000,000 LDA K,X \ Subtract the X-th byte of TENS (i.e. 10 billion) from SBC TENS,X \ the X-th byte of K STA XX15,X \ Store the result in the X-th byte of XX15 DEX \ Decrement the loop counter BPL tt37 \ Loop back to subtract the next byte, moving from the \ least significant byte to the most significant, until \ we have subtracted all four LDA S \ Subtract the fifth byte of 10 billion (i.e. &17) from SBC #&17 \ the fifth (overflow) byte of K, which is S STA XX15+4 \ Store the result in the overflow byte of XX15 BCC TT37 \ If subtracting 10 billion took us below zero, jump to \ TT37 to print out this digit, which is now in Y LDX #3 \ We now want to copy XX15(4 0 1 2 3) back into \ K(S 0 1 2 3), so we can loop back up to do the next \ subtraction, so set up a counter for a four-byte loop .tt38 LDA XX15,X \ Copy the X-th byte of XX15(0 1 2 3) to the X-th byte STA K,X \ of K(0 1 2 3), so that K(0 1 2 3) will contain a copy \ of XX15(0 1 2 3) once we've copied all four bytes DEX \ Decrement the loop counter BPL tt38 \ Loop back to copy the next byte, until we have copied \ all four LDA XX15+4 \ Store the value of location XX15+4, our overflow STA S \ byte in S, so now K(S 0 1 2 3) contains a copy of \ XX15(4 0 1 2 3) INY \ We have now managed to subtract 10 billion from our \ number, so increment Y, which is where we are keeping \ a count of the number of subtractions so far JMP TT36 \ Jump back to TT36 to subtract the next 10 billion .TT37 TYA \ If we get here then Y contains the digit that we want \ to print (as Y has now counted the total number of \ subtractions of 10 billion), so transfer Y into A BNE TT32 \ If the digit is non-zero, jump to TT32 to print it LDA T \ Otherwise the digit is zero. If we are already \ printing the number then we will want to print a 0, \ but if we haven't started printing the number yet, \ then we probably don't, as we don't want to print \ leading zeroes unless this is the only digit before \ the decimal point \ \ To help with this, we are going to use T as a flag \ that tells us whether we have already started \ printing digits: \ \ * If T <> 0 we haven't printed anything yet \ \ * If T = 0 then we have started printing digits \ \ We initially set T above to the maximum number of \ characters allowed, less 1 if we are printing a \ decimal point, so the first time we enter the digit \ printing routine at TT37, it is definitely non-zero BEQ TT32 \ If T = 0, jump straight to the print routine at TT32, \ as we have already started printing the number, so we \ definitely want to print this digit too DEC U \ We initially set U to the number of digits we want to BPL TT34 \ skip before starting to print the number. If we get \ here then we haven't printed any digits yet, so \ decrement U to see if we have reached the point where \ we should start printing the number, and if not, jump \ to TT34 to set up things for the next digit LDA #' ' \ We haven't started printing any digits yet, but we BNE tt34 \ have reached the point where we should start printing \ our number, so call TT26 (via tt34) to print a space \ so that the number is left-padded with spaces (this \ BNE is effectively a JMP as A will never be zero) .TT32 LDY #0 \ We are printing an actual digit, so first set T to 0, STY T \ to denote that we have now started printing digits as \ opposed to spaces CLC \ The digit value is in A, so add ASCII "0" to get the ADC #'0' \ ASCII character number to print .tt34 JSR TT26 \ Call TT26 to print the character in A and fall through \ into TT34 to get things ready for the next digit .TT34 DEC T \ Decrement T but keep T >= 0 (by incrementing it BPL P%+4 \ again if the above decrement made T negative) INC T DEC XX17 \ Decrement the total number of characters left to \ print, which we stored in XX17 BMI rT10 \ If the result is negative, we have printed all the \ characters, so jump down to rT10 to return from the \ subroutine BNE P%+10 \ If the result is positive (> 0) then we still have \ characters left to print, so loop back to TT35 (via \ the JMP TT35 instruction below) to print the next \ digit PLP \ If we get here then we have printed the exact number \ of digits that we wanted to, so restore the C flag \ that we stored at the start of the routine BCC P%+7 \ If the C flag is clear, we don't want a decimal point, \ so loop back to TT35 (via the JMP TT35 instruction \ below) to print the next digit LDA #'.' \ Otherwise the C flag is set, so print the decimal JSR TT26 \ point JMP TT35 \ Loop back to TT35 to print the next digit .rT10 RTS \ Return from the subroutine
Name: DTW1 [Show more] Type: Variable Category: Text Summary: A mask for applying the lower case part of Sentence Case to extended text tokens Deep dive: Extended text tokens
Context: See this variable on its own page References: This variable is used as follows: * DETOK2 uses DTW1 * MT13 uses DTW1 * MT2 uses DTW1

This variable is used to change characters to lower case as part of applying Sentence Case to extended text tokens. It has two values: * %00100000 = apply lower case to the second letter of a word onwards * %00000000 = do not change case to lower case The default value is %00100000 (apply lower case). The flag is set to %00100000 (apply lower case) by jump token 2, {sentence case}, which calls routine MT2 to change the value of DTW1. The flag is set to %00000000 (do not change case to lower case) by jump token 1, {all caps}, which calls routine MT1 to change the value of DTW1. The letter to print is OR'd with DTW1 in DETOK2, which lower-cases the letter by setting bit 5 (if DTW1 is %00100000). However, this OR is only done if bit 7 of DTW2 is clear, i.e. we are printing a word, so this doesn't affect the first letter of the word, which remains capitalised.
.DTW1 EQUB %00100000
Name: DTW2 [Show more] Type: Variable Category: Text Summary: A flag that indicates whether we are currently printing a word Deep dive: Extended text tokens
Context: See this variable on its own page References: This variable is used as follows: * CLYNS uses DTW2 * DETOK2 uses DTW2 * MT8 uses DTW2 * TT26 uses DTW2 * TTX66 uses DTW2

This variable is used to indicate whether we are currently printing a word. It has two values: * 0 = we are currently printing a word * Non-zero = we are not currently printing a word The default value is %11111111 (we are not currently printing a word). The flag is set to %00000000 (we are currently printing a word) whenever a non-terminator character is passed to DASC for printing. The flag is set to %11111111 (we are not currently printing a word) whenever a terminator character (full stop, colon, carriage return, line feed, space) is passed to DASC for printing. It is also set to %11111111 by jump token 8, {tab 6}, which calls routine MT8 to change the value of DTW2, and to %10000000 by TTX66 when we clear the screen.
.DTW2 EQUB %11111111
Name: DTW3 [Show more] Type: Variable Category: Text Summary: A flag for switching between standard and extended text tokens Deep dive: Extended text tokens
Context: See this variable on its own page References: This variable is used as follows: * DETOK2 uses DTW3 * MT5 uses DTW3

This variable is used to indicate whether standard or extended text tokens should be printed by calls to DETOK. It allows us to mix standard tokens in with extended tokens. It has two values: * %00000000 = print extended tokens (i.e. those in TKN1 and RUTOK) * %11111111 = print standard tokens (i.e. those in QQ18) The default value is %00000000 (extended tokens). Standard tokens are set by jump token {6}, which calls routine MT6 to change the value of DTW3 to %11111111. Extended tokens are set by jump token {5}, which calls routine MT5 to change the value of DTW3 to %00000000.
.DTW3 EQUB %00000000
Name: DTW4 [Show more] Type: Variable Category: Text Summary: Flags that govern how justified extended text tokens are printed Deep dive: Extended text tokens
Context: See this variable on its own page References: This variable is used as follows: * MT15 uses DTW4 * TT26 uses DTW4

This variable is used to control how justified text tokens are printed as part of the extended text token system. There are two bits that affect justified text: * Bit 7: 1 = justify text 0 = do not justify text * Bit 6: 1 = buffer the entire token before printing, including carriage returns (used for in-flight messages only) 0 = print the contents of the buffer whenever a carriage return appears in the token The default value is %00000000 (do not justify text, print buffer on carriage return). The flag is set to %10000000 (justify text, print buffer on carriage return) by jump token 14, {justify}, which calls routine MT14 to change the value of DTW4. The flag is set to %11000000 (justify text, buffer entire token) by routine MESS, which prints in-flight messages. The flag is set to %00000000 (do not justify text, print buffer on carriage return) by jump token 15, {left align}, which calls routine MT1 to change the value of DTW4.
.DTW4 EQUB 0
Name: DTW5 [Show more] Type: Variable Category: Text Summary: The size of the justified text buffer at BUF Deep dive: Extended text tokens
Context: See this variable on its own page References: This variable is used as follows: * HME2 uses DTW5 * MT15 uses DTW5 * MT17 uses DTW5 * TT26 uses DTW5

When justified text is enabled by jump token 14, {justify}, during printing of extended text tokens, text is fed into a buffer at BUF instead of being printed straight away, so it can be padded out with spaces to justify the text. DTW5 contains the size of the buffer, so BUF + DTW5 points to the first free byte after the end of the buffer.
.DTW5 EQUB 0
Name: DTW6 [Show more] Type: Variable Category: Text Summary: A flag to denote whether printing in lower case is enabled for extended text tokens Deep dive: Extended text tokens
Context: See this variable on its own page References: This variable is used as follows: * DETOK2 uses DTW6 * MT13 uses DTW6 * MT2 uses DTW6

This variable is used to indicate whether lower case is currently enabled. It has two values: * %10000000 = lower case is enabled * %00000000 = lower case is not enabled The default value is %00000000 (lower case is not enabled). The flag is set to %10000000 (lower case is enabled) by jump token 13 {lower case}, which calls routine MT10 to change the value of DTW6. The flag is set to %00000000 (lower case is not enabled) by jump token 1, {all caps}, and jump token 2, {sentence case}, which call routines MT1 and MT2 to change the value of DTW6.
.DTW6 EQUB %00000000
Name: DTW8 [Show more] Type: Variable Category: Text Summary: A mask for capitalising the next letter in an extended text token Deep dive: Extended text tokens
Context: See this variable on its own page References: This variable is used as follows: * DETOK2 uses DTW8 * MT19 uses DTW8 * TT26 uses DTW8

This variable is only used by one specific extended token, the {single cap} jump token, which capitalises the next letter only. It has two values: * %11011111 = capitalise the next letter * %11111111 = do not change case The default value is %11111111 (do not change case). The flag is set to %11011111 (capitalise the next letter) by jump token 19, {single cap}, which calls routine MT19 to change the value of DTW. The flag is set to %11111111 (do not change case) at the start of DASC, after the letter has been capitalised in DETOK2, so the effect is to capitalise one letter only. The letter to print is AND'd with DTW8 in DETOK2, which capitalises the letter by clearing bit 5 (if DTW8 is %11011111). However, this AND is only done if at least one of the following is true: * Bit 7 of DTW2 is set (we are not currently printing a word) * Bit 7 of DTW6 is set (lower case has been enabled by jump token 13, {lower case} In other words, we only capitalise the next letter if it's the first letter in a word, or we are printing in lower case.
.DTW8 EQUB %11111111
Name: FEED [Show more] Type: Subroutine Category: Text Summary: Print a newline
Context: See this subroutine on its own page References: This subroutine is called as follows: * GTDRV calls FEED * MT26 calls FEED
.FEED LDA #12 \ Set A = 12, so when we skip MT16 and fall through into \ TT26, we print character 12, which is a newline EQUB &2C \ Skip the next instruction by turning it into \ &2C &A9 &41, or BIT &41A9, which does nothing apart \ from affect the flags \ Fall through into TT26 (skipping MT16) to print the \ newline character
Name: MT16 [Show more] Type: Subroutine Category: Text Summary: Print the character in variable DTW7 Deep dive: Extended text tokens
Context: See this subroutine on its own page References: This subroutine is called as follows: * JMTB calls MT16
.MT16 LDA #'A' \ Set A to the contents of DTW7, as DTW7 points to the \ second byte of this instruction, so updating DTW7 will \ modify this instruction (the default value of DTW7 is \ an "A") DTW7 = MT16 + 1 \ Point DTW7 to the second byte of the instruction above \ so that modifying DTW7 changes the value loaded into A \ Fall through into TT26 to print the character in A
Name: TT26 [Show more] Type: Subroutine Category: Text Summary: Print a character at the text cursor, with support for verified text in extended tokens Deep dive: Extended text tokens
Context: See this subroutine on its own page Variations: See code variations for this subroutine in the different versions References: This subroutine is called as follows: * BPRNT calls TT26 * cmn calls TT26 * gnum calls TT26 * TT160 calls TT26 * TT161 calls TT26 * TT16a calls TT26 * TT214 calls TT26 * TT25 calls TT26 * TT42 calls TT26 * TT74 calls TT26 * DETOK2 calls via DASC * JMTB calls via DASC

Arguments: A The character to print
Returns: X X is preserved C flag The C flag is cleared
Other entry points: DASC DASC does exactly the same as TT26 and prints a character at the text cursor, with support for verified text in extended tokens rT9 Contains an RTS
.DASC .TT26 STX SC \ Store X in SC, so we can retrieve it below LDX #%11111111 \ Set DTW8 = %11111111, to disable the effect of {19} if STX DTW8 \ it was set (as {19} capitalises one character only) CMP #'.' \ If the character in A is a word terminator: BEQ DA8 \ CMP #':' \ * Full stop BEQ DA8 \ * Colon CMP #10 \ * Line feed BEQ DA8 \ * Carriage return CMP #12 \ * Space BEQ DA8 \ CMP #' ' \ then skip the following instruction BEQ DA8 INX \ Increment X to 0, so DTW2 gets set to %00000000 below .DA8 STX DTW2 \ Store X in DTW2, so DTW2 is now: \ \ * %00000000 if this character is a word terminator \ \ * %11111111 if it isn't \ \ so DTW2 indicates whether or not we are currently \ printing a word LDX SC \ Retrieve the original value of X from SC BIT DTW4 \ If bit 7 of DTW4 is set then we are currently printing BMI P%+5 \ justified text, so skip the next instruction JMP CHPR \ Bit 7 of DTW4 is clear, so jump down to CHPR to print \ this character, as we are not printing justified text \ If we get here then we are printing justified text, so \ we need to buffer the text until we reach the end of \ the paragraph, so we can then pad it out with spaces CMP #12 \ If the character in A is a carriage return, then we BEQ DA1 \ have reached the end of the paragraph, so jump down to \ DA1 to print out the contents of the buffer, \ justifying it as we go \ If we get here then we need to buffer this character \ in the line buffer at BUF LDX DTW5 \ DTW5 contains the current size of the buffer, so this STA BUF,X \ stores the character in A at BUF + DTW5, the next free \ space in the buffer LDX SC \ Retrieve the original value of X from SC so we can \ preserve it through this subroutine call INC DTW5 \ Increment the size of the BUF buffer that is stored in \ DTW5 CLC \ Clear the C flag RTS \ Return from the subroutine .DA1 \ If we get here then we are justifying text and we have \ reached the end of the paragraph, so we need to print \ out the contents of the buffer, justifying it as we go TXA \ Store X and Y on the stack PHA TYA PHA .DA5 LDX DTW5 \ Set X = DTW5, which contains the size of the buffer BEQ DA6+3 \ If X = 0 then the buffer is empty, so jump down to \ DA6+3 to print a newline CPX #(LL+1) \ If X < LL+1, i.e. X <= LL, then the buffer contains BCC DA6 \ fewer than LL characters, which is less than a line \ length, so jump down to DA6 to print the contents of \ BUF followed by a newline, as we don't justify the \ last line of the paragraph \ Otherwise X > LL, so the buffer does not fit into one \ line, and we therefore need to justify the text, which \ we do one line at a time LSR SC+1 \ Shift SC+1 to the right, which clears bit 7 of SC+1, \ so we pass through the following comparison on the \ first iteration of the loop and set SC+1 to %01000000 .DA11 LDA SC+1 \ If bit 7 of SC+1 is set, skip the following two BMI P%+6 \ instructions LDA #%01000000 \ Set SC+1 = %01000000 STA SC+1 LDY #(LL-1) \ Set Y = line length, so we can loop backwards from the \ end of the first line in the buffer using Y as the \ loop counter .DAL1 LDA BUF+LL \ If the LL-th byte in BUF is a space, jump down to DA2 CMP #' ' \ to print out the first line from the buffer, as it BEQ DA2 \ fits the line width exactly (i.e. it's justified) \ We now want to find the last space character in the \ first line in the buffer, so we loop through the line \ using Y as a counter .DAL2 DEY \ Decrement the loop counter in Y BMI DA11 \ If Y <= 0, loop back to DA11, as we have now looped BEQ DA11 \ through the whole line LDA BUF,Y \ If the Y-th byte in BUF is not a space, loop back up CMP #' ' \ to DAL2 to check the next character BNE DAL2 \ Y now points to a space character in the line buffer ASL SC+1 \ Shift SC+1 to the left BMI DAL2 \ If bit 7 of SC+1 is set, jump to DAL2 to find the next \ space character \ We now want to insert a space into the line buffer at \ position Y, which we do by shifting every character \ after position Y along by 1, and then inserting the \ space STY SC \ Store Y in SC, so we want to insert the space at \ position SC LDY DTW5 \ Fetch the buffer size from DTW5 into Y, to act as a \ loop counter for moving the line buffer along by 1 .DAL6 LDA BUF,Y \ Copy the Y-th character from BUF into the Y+1-th STA BUF+1,Y \ position DEY \ Decrement the loop counter in Y CPY SC \ Loop back to shift the next character along, until we BCS DAL6 \ have moved the SC-th character (i.e. Y < SC) INC DTW5 \ Increment the buffer size in DTW5 \ We've now shifted the line to the right by 1 from \ position SC onwards, so SC and SC+1 both contain \ spaces, and Y is now SC-1 as we did a DEY just before \ the end of the loop - in other words, we have inserted \ a space at position SC, and Y points to the character \ before the newly inserted space \ We now want to move the pointer Y left to find the \ next space in the line buffer, before looping back to \ check whether we are done, and if not, insert another \ space .DAL3 CMP BUF,Y \ If the character at position Y is not a space, jump to BNE DAL1 \ DAL1 to see whether we have now justified the line DEY \ Decrement the loop counter in Y BPL DAL3 \ Loop back to check the next character to the left, \ until we have found a space BMI DA11 \ Jump back to DA11 (this BMI is effectively a JMP as \ we already passed through a BPL to get here) .DA2 \ This subroutine prints out a full line of characters \ from the start of the line buffer in BUF, followed by \ a newline. It then removes that line from the buffer, \ shuffling the rest of the buffer contents down LDX #LL \ Call DAS1 to print out the first LL characters from JSR DAS1 \ the line buffer in BUF LDA #12 \ Print a newline JSR CHPR LDA DTW5 \ Subtract #LL from the end-of-buffer pointer in DTW5 SBC #LL \ STA DTW5 \ The subtraction works as CHPR clears the C flag TAX \ Copy the new value of DTW5 into X BEQ DA6+3 \ If DTW5 = 0 then jump down to DA6+3 to print a newline \ as the buffer is now empty \ If we get here then we have printed our line but there \ is more in the buffer, so we now want to remove the \ line we just printed from the start of BUF LDY #0 \ Set Y = 0 to count through the characters in BUF INX \ Increment X, so it now contains the number of \ characters in the buffer (as DTW5 is a zero-based \ pointer and is therefore equal to the number of \ characters minus 1) .DAL4 LDA BUF+LL+1,Y \ Copy the Y-th character from BUF+LL to BUF STA BUF,Y INY \ Increment the character pointer DEX \ Decrement the character count BNE DAL4 \ Loop back to copy the next character until we have \ shuffled down the whole buffer BEQ DA5 \ Jump back to DA5 (this BEQ is effectively a JMP as we \ have already passed through the BNE above) .DAS1 \ This subroutine prints out X characters from BUF, \ returning with X = 0 LDY #0 \ Set Y = 0 to point to the first character in BUF .DAL5 LDA BUF,Y \ Print the Y-th character in BUF using CHPR, which also JSR CHPR \ clears the C flag for when we return from the \ subroutine below INY \ Increment Y to point to the next character DEX \ Decrement the loop counter BNE DAL5 \ Loop back for the next character until we have printed \ X characters from BUF .rT9 RTS \ Return from the subroutine .DA6 JSR DAS1 \ Call DAS1 to print X characters from BUF, returning \ with X = 0 STX DTW5 \ Set the buffer size in DTW5 to 0, as the buffer is now \ empty PLA \ Restore Y and X from the stack TAY PLA TAX LDA #12 \ Set A = 12, so when we skip BELL and fall through into \ CHPR, we print character 12, which is a newline .DA7 EQUB &2C \ Skip the next instruction by turning it into \ &2C &A9 &07, or BIT &07A9, which does nothing apart \ from affect the flags \ Fall through into CHPR (skipping BELL) to print the \ character and return with the C flag cleared
Name: BELL [Show more] Type: Subroutine Category: Sound Summary: Make a standard system beep
Context: See this subroutine on its own page Variations: See code variations for this subroutine in the different versions References: This subroutine is called as follows: * DKS3 calls BELL

This is the standard system beep, as made by the ASCII 7 "BELL" control code.
.BELL LDA #7 \ Control code 7 makes a beep, so load this into A \ Fall through into the TT26 print routine to \ actually make the sound
Name: CHPR [Show more] Type: Subroutine Category: Text Summary: Print a character at the text cursor by poking into screen memory Deep dive: Drawing text
Context: See this subroutine on its own page Variations: See code variations for this subroutine in the different versions References: This subroutine is called as follows: * GTDRV calls CHPR * S% calls CHPR * TT26 calls CHPR * BULB calls via RREN * DIALS (Part 3 of 4) calls via R5-1

Print a character at the text cursor (XC, YC), do a beep, print a newline, or delete left (backspace). WRCHV is set to point here by the loading process.
Arguments: A The character to be printed. Can be one of the following: * 7 (beep) * 10-13 (line feeds and carriage returns) * 32-95 (ASCII capital letters, numbers and punctuation) * 127 (delete the character to the left of the text cursor and move the cursor to the left) XC Contains the text column to print at (the x-coordinate) YC Contains the line number to print on (the y-coordinate)
Returns: A A is preserved X X is preserved Y Y is preserved C flag The C flag is cleared
Other entry points: RREN Prints the character definition pointed to by P(2 1) at the screen address pointed to by (A SC). Used by the BULB routine R5-1 Contains an RTS
.CHPR STA K3 \ Store the A, X and Y registers, so we can restore STY YSAV2 \ them at the end (so they don't get changed by this STX XSAV2 \ routine) .RRNEW LDY QQ17 \ Load the QQ17 flag, which contains the text printing \ flags INY \ If QQ17 = 255 then printing is disabled, so jump to BEQ RR4 \ RR4, which doesn't print anything, it just restores \ the registers and returns from the subroutine TAY \ Set Y = the character to be printed BEQ RR4 \ If the character is zero, which is typically a string \ terminator character, jump down to RR4 to restore the \ registers and return from the subroutine BMI RR4 \ If A > 127 then there is nothing to print, so jump to \ RR4 to restore the registers and return from the \ subroutine CMP #7 \ If this is a beep character (A = 7), jump to R5, BEQ R5 \ which will emit the beep, restore the registers and \ return from the subroutine CMP #32 \ If this is an ASCII character (A >= 32), jump to RR1 BCS RR1 \ below, which will print the character, restore the \ registers and return from the subroutine CMP #10 \ If this is control code 10 (line feed) then jump to BEQ RRX1 \ RRX1, which will move down a line, restore the \ registers and return from the subroutine LDX #1 \ If we get here, then this is control code 11-13, of STX XC \ which only 13 is used. This code prints a newline, \ which we can achieve by moving the text cursor \ to the start of the line (carriage return) and down \ one line (line feed). These two lines do the first \ bit by setting XC = 1, and we then fall through into \ the line feed routine that's used by control code 10 CMP #13 \ If this is control code 13 (carriage return) then jump BEQ RR4 \ RR4 to restore the registers and return from the \ subroutine .RRX1 INC YC \ Print a line feed, simply by incrementing the row \ number (y-coordinate) of the text cursor, which is \ stored in YC BNE RR4 \ Jump to RR4 to restore the registers and return from \ the subroutine (this BNE is effectively a JMP as Y \ will never be zero) .RR1 \ If we get here, then the character to print is an \ ASCII character in the range 32-95. The quickest way \ to display text on-screen is to poke the character \ pixel by pixel, directly into screen memory, so \ that's what the rest of this routine does \ \ The first step, then, is to get hold of the bitmap \ definition for the character we want to draw on the \ screen (i.e. we need the pixel shape of this \ character). The MOS ROM contains bitmap definitions \ of the system's ASCII characters, starting from &C000 \ for space (ASCII 32) and ending with the £ symbol \ (ASCII 126) \ \ There are definitions for 32 characters in each of the \ three pages of MOS memory, as each definition takes up \ 8 bytes (8 rows of 8 pixels) and 32 * 8 = 256 bytes = \ 1 page. So: \ \ ASCII 32-63 are defined in &C000-&C0FF (page 0) \ ASCII 64-95 are defined in &C100-&C1FF (page 1) \ ASCII 96-126 are defined in &C200-&C2F0 (page 2) \ \ The following code reads the relevant character \ bitmap from the above locations in ROM and pokes \ those values into the correct position in screen \ memory, thus printing the character on-screen \ \ It's a long way from 10 PRINT "Hello world!":GOTO 10 \ Now we want to set X to point to the relevant page \ number for this character - i.e. &C0, &C1 or &C2. \ The following logic is easier to follow if we look \ at the three character number ranges in binary: \ \ Bit # 76543210 \ \ 32 = %00100000 Page 0 of bitmap definitions \ 63 = %00111111 \ \ 64 = %01000000 Page 1 of bitmap definitions \ 95 = %01011111 \ \ 96 = %01100000 Page 2 of bitmap definitions \ 125 = %01111101 \ \ We'll refer to this below LDX #&BF \ Set X to point to the first font page in ROM minus 1, \ which is &C0 - 1, or &BF ASL A \ If bit 6 of the character is clear (A is 32-63) ASL A \ then skip the following instruction BCC P%+4 LDX #&C1 \ A is 64-126, so set X to point to page &C1 ASL A \ If bit 5 of the character is clear (A is 64-95) BCC P%+3 \ then skip the following instruction INX \ Increment X \ \ By this point, we started with X = &BF, and then \ we did the following: \ \ If A = 32-63: skip then INX so X = &C0 \ If A = 64-95: X = &C1 then skip so X = &C1 \ If A = 96-126: X = &C1 then INX so X = &C2 \ \ In other words, X points to the relevant page. But \ what about the value of A? That gets shifted to the \ left three times during the above code, which \ multiplies the number by 8 but also drops bits 7, 6 \ and 5 in the process. Look at the above binary \ figures and you can see that if we cleared bits 5-7, \ then that would change 32-53 to 0-31... but it would \ do exactly the same to 64-95 and 96-125. And because \ we also multiply this figure by 8, A now points to \ the start of the character's definition within its \ page (because there are 8 bytes per character \ definition) \ \ Or, to put it another way, X contains the high byte \ (the page) of the address of the definition that we \ want, while A contains the low byte (the offset into \ the page) of the address STA P+1 \ Store the address of this character's definition in STX P+2 \ P(2 1) LDA XC \ Fetch XC, the x-coordinate (column) of the text cursor \ into A LDX CATF \ If CATF = 0, jump to RR5, otherwise we are printing a BEQ RR5 \ disc catalogue CPY #' ' \ If the character we want to print in Y is a space, BNE RR5 \ jump to RR5 \ If we get here, then CATF is non-zero, so we are \ printing a disc catalogue and we are not printing a \ space, so we drop column 17 from the output so the \ catalogue will fit on-screen (column 17 is a blank \ column in the middle of the catalogue, between the \ two lists of filenames, so it can be dropped without \ affecting the layout). Without this, the catalogue \ would be one character too wide for the square screen \ mode (it's 34 characters wide, while the screen mode \ is only 33 characters across) CMP #17 \ If A = 17, i.e. the text cursor is in column 17, jump BEQ RR4 \ to RR4 to restore the registers and return from the \ subroutine, thus omitting this column .RR5 ASL A \ Multiply A by 8, and store in SC. As each character is ASL A \ 8 pixels wide, and the special screen mode Elite uses ASL A \ for the top part of the screen is 256 pixels across STA SC \ with one bit per pixel, this value is not only the \ screen address offset of the text cursor from the left \ side of the screen, it's also the least significant \ byte of the screen address where we want to print this \ character, as each row of on-screen pixels corresponds \ to one page. To put this more explicitly, the screen \ starts at &6000, so the text rows are stored in screen \ memory like this: \ \ Row 1: &6000 - &60FF YC = 1, XC = 0 to 31 \ Row 2: &6100 - &61FF YC = 2, XC = 0 to 31 \ Row 3: &6200 - &62FF YC = 3, XC = 0 to 31 \ \ and so on LDA YC \ Fetch YC, the y-coordinate (row) of the text cursor CPY #127 \ If the character number (which is in Y) <> 127, then BNE RR2 \ skip to RR2 to print that character, otherwise this is \ the delete character, so continue on DEC XC \ We want to delete the character to the left of the \ text cursor and move the cursor back one, so let's \ do that by decrementing YC. Note that this doesn't \ have anything to do with the actual deletion below, \ we're just updating the cursor so it's in the right \ position following the deletion ADC #&5E \ A contains YC (from above) and the C flag is set (from TAX \ the CPY #127 above), so these instructions do this: \ \ X = YC + &5E + 1 \ = YC + &5F \ Because YC starts at 0 for the first text row, this \ means that X will be &5F for row 0, &60 for row 1 and \ so on. In other words, X is now set to the page number \ for the row before the one containing the text cursor, \ and given that we set SC above to point to the offset \ in memory of the text cursor within the row's page, \ this means that (X SC) now points to the character \ above the text cursor LDY #&F8 \ Set Y = &F8, so the following call to ZES2 will count \ Y upwards from &F8 to &FF JSR ZES2 \ Call ZES2, which zero-fills from address (X SC) + Y to \ (X SC) + &FF. (X SC) points to the character above the \ text cursor, and adding &FF to this would point to the \ cursor, so adding &F8 points to the character before \ the cursor, which is the one we want to delete. So \ this call zero-fills the character to the left of the \ cursor, which erases it from the screen BEQ RR4 \ We are done deleting, so restore the registers and \ return from the subroutine (this BNE is effectively \ a JMP as ZES2 always returns with the Z flag set) .RR2 \ Now to actually print the character INC XC \ Once we print the character, we want to move the text \ cursor to the right, so we do this by incrementing \ XC. Note that this doesn't have anything to do \ with the actual printing below, we're just updating \ the cursor so it's in the right position following \ the print CMP #24 \ If the text cursor is on the screen (i.e. YC < 24, so BCC RR3 \ we are on rows 0-23), then jump to RR3 to print the \ character PHA \ Store A on the stack so we can retrieve it below JSR TTX66 \ Otherwise we are off the bottom of the screen, so \ clear the screen and draw a white border PLA \ Retrieve A from the stack... only to overwrite it with \ the next instruction, so presumably we didn't need to \ preserve it and this and the PHA above have no effect LDA K3 \ Set A to the character to be printed JMP RRNEW \ Jump back to RRNEW to print the character .RR3 \ A contains the value of YC - the screen row where we \ want to print this character - so now we need to \ convert this into a screen address, so we can poke \ the character data to the right place in screen \ memory ORA #&60 \ We already stored the least significant byte \ of this screen address in SC above (see the STA SC \ instruction above), so all we need is the most \ significant byte. As mentioned above, in Elite's \ square mode 4 screen, each row of text on-screen \ takes up exactly one page, so the first row is page \ &60xx, the second row is page &61xx, so we can get \ the page for character (XC, YC) by OR'ing with &60. \ To see this in action, consider that our two values \ are, in binary: \ \ YC is between: %00000000 \ and: %00010111 \ &60 is: %01100000 \ \ so YC OR &60 effectively adds &60 to YC, giving us \ the page number that we want .RREN STA SC+1 \ Store the page number of the destination screen \ location in SC+1, so SC now points to the full screen \ location where this character should go LDY #7 \ We want to print the 8 bytes of character data to the \ screen (one byte per row), so set up a counter in Y \ to count these bytes .RRL1 LDA (P+1),Y \ The character definition is at P(2 1) - we set this up \ above - so load the Y-th byte from P(2 1), which will \ contain the bitmap for the Y-th row of the character ORA (SC),Y \ OR this value with the current contents of screen \ memory, so the pixels we want to draw are set STA (SC),Y \ Store the Y-th byte at the screen address for this \ character location DEY \ Decrement the loop counter BPL RRL1 \ Loop back for the next byte to print to the screen .RR4 LDY YSAV2 \ We're done printing, so restore the values of the LDX XSAV2 \ A, X and Y registers that we saved above and clear LDA K3 \ the C flag, so everything is back to how it was CLC RTS \ Return from the subroutine .R5 JSR BEEP \ Call the BEEP subroutine to make a short, high beep JMP RR4 \ Jump to RR4 to restore the registers and return from \ the subroutine using a tail call
Name: DIALS (Part 1 of 4) [Show more] Type: Subroutine Category: Dashboard Summary: Update the dashboard: speed indicator Deep dive: The dashboard indicators
Context: See this subroutine on its own page Variations: See code variations for this subroutine in the different versions References: This subroutine is called as follows: * Main game loop (Part 5 of 6) calls DIALS * RES2 calls DIALS

This routine updates the dashboard. First we draw all the indicators in the right part of the dashboard, from top (speed) to bottom (energy banks), and then we move on to the left part, again drawing from top (forward shield) to bottom (altitude). This first section starts us off with the speedometer in the top right.
.DIALS LDA #&D0 \ Set SC(1 0) = &78D0, which is the screen address for STA SC \ the character block containing the left end of the LDA #&78 \ top indicator in the right part of the dashboard, the STA SC+1 \ one showing our speed JSR PZW \ Call PZW to set A to the colour for dangerous values \ and X to the colour for safe values STX K+1 \ Set K+1 (the colour we should show for low values) to \ X (the colour to use for safe values) STA K \ Set K (the colour we should show for high values) to \ A (the colour to use for dangerous values) \ The above sets the following indicators to show red \ for high values and yellow/white for low values LDA #14 \ Set T1 to 14, the threshold at which we change the STA T1 \ indicator's colour LDA DELTA \ Fetch our ship's speed into A, in the range 0-40 JSR DIL-1 \ Draw the speed indicator using a range of 0-31, and \ increment SC to point to the next indicator (the roll \ indicator)
Name: DIALS (Part 2 of 4) [Show more] Type: Subroutine Category: Dashboard Summary: Update the dashboard: pitch and roll indicators Deep dive: The dashboard indicators
Context: See this subroutine on its own page Variations: See code variations for this subroutine in the different versions References: No direct references to this subroutine in this source file
LDA #0 \ Set R = P = 0 for the low bytes in the call to the ADD STA R \ routine below STA P LDA #8 \ Set S = 8, which is the value of the centre of the STA S \ roll indicator LDA ALP1 \ Fetch the roll angle alpha as a value between 0 and LSR A \ 31, and divide by 4 to get a value of 0 to 7 LSR A ORA ALP2 \ Apply the roll sign to the value, and flip the sign, EOR #%10000000 \ so it's now in the range -7 to +7, with a positive \ roll angle alpha giving a negative value in A JSR ADD \ We now add A to S to give us a value in the range 1 to \ 15, which we can pass to DIL2 to draw the vertical \ bar on the indicator at this position. We use the ADD \ routine like this: \ \ (A X) = (A 0) + (S 0) \ \ and just take the high byte of the result. We use ADD \ rather than a normal ADC because ADD separates out the \ sign bit and does the arithmetic using absolute values \ and separate sign bits, which we want here rather than \ the two's complement that ADC uses JSR DIL2 \ Draw a vertical bar on the roll indicator at offset A \ and increment SC to point to the next indicator (the \ pitch indicator) LDA BETA \ Fetch the pitch angle beta as a value between -8 and \ +8 LDX BET1 \ Fetch the magnitude of the pitch angle beta, and if it BEQ P%+4 \ is 0 (i.e. we are not pitching), skip the next \ instruction SBC #1 \ The pitch angle beta is non-zero, so set A = A - 1 \ (the C flag is set by the call to DIL2 above, so we \ don't need to do a SEC). This gives us a value of A \ from -7 to +7 because these are magnitude-based \ numbers with sign bits, rather than two's complement \ numbers JSR ADD \ We now add A to S to give us a value in the range 1 to \ 15, which we can pass to DIL2 to draw the vertical \ bar on the indicator at this position (see the JSR ADD \ above for more on this) JSR DIL2 \ Draw a vertical bar on the pitch indicator at offset A \ and increment SC to point to the next indicator (the \ four energy banks)
Name: DIALS (Part 3 of 4) [Show more] Type: Subroutine Category: Dashboard Summary: Update the dashboard: four energy banks Deep dive: The dashboard indicators
Context: See this subroutine on its own page Variations: See code variations for this subroutine in the different versions References: No direct references to this subroutine in this source file

This and the next section only run once every four iterations of the main loop, so while the speed, pitch and roll indicators update every iteration, the other indicators update less often.
LDA MCNT \ Fetch the main loop counter and calculate MCNT mod 4, AND #3 \ jumping to R5-1 if it is non-zero. R5-1 contains an BNE R5-1 \ RTS, so the following code only runs every 4 \ iterations of the main loop, otherwise we return from \ the subroutine LDY #0 \ Set Y = 0, for use in various places below JSR PZW \ Call PZW to set A to the colour for dangerous values \ and X to the colour for safe values STX K \ Set K (the colour we should show for high values) to X \ (the colour to use for safe values) STA K+1 \ Set K+1 (the colour we should show for low values) to \ A (the colour to use for dangerous values) \ The above sets the following indicators to show red \ for low values and yellow/white for high values, which \ we use not only for the energy banks, but also for the \ shield levels and current fuel LDX #3 \ Set up a counter in X so we can zero the four bytes at \ XX12, so we can then calculate each of the four energy \ banks' values before drawing them later STX T1 \ Set T1 to 3, the threshold at which we change the \ indicator's colour .DLL23 STY XX12,X \ Set the X-th byte of XX12 to 0 DEX \ Decrement the counter BPL DLL23 \ Loop back for the next byte until the four bytes at \ XX12 are all zeroed LDX #3 \ Set up a counter in X to loop through the 4 energy \ bank indicators, so we can calculate each of the four \ energy banks' values and store them in XX12 LDA ENERGY \ Set A = Q = ENERGY / 4, so they are both now in the LSR A \ range 0-63 (so that's a maximum of 16 in each of the LSR A \ banks, and a maximum of 15 in the top bank) STA Q \ Set Q to A, so we can use Q to hold the remaining \ energy as we work our way through each bank, from the \ full ones at the bottom to the empty ones at the top .DLL24 SEC \ Set A = A - 16 to reduce the energy count by a full SBC #16 \ bank BCC DLL26 \ If the C flag is clear then A < 16, so this bank is \ not full to the brim, and is therefore the last one \ with any energy in it, so jump to DLL26 STA Q \ This bank is full, so update Q with the energy of the \ remaining banks LDA #16 \ Store this bank's level in XX12 as 16, as it is full, STA XX12,X \ with XX12+3 for the bottom bank and XX12+0 for the top LDA Q \ Set A to the remaining energy level again DEX \ Decrement X to point to the next bank, i.e. the one \ above the bank we just processed BPL DLL24 \ Loop back to DLL24 until we have either processed all \ four banks, or jumped out early to DLL26 if the top \ banks have no charge BMI DLL9 \ Jump to DLL9 as we have processed all four banks (this \ BMI is effectively a JMP as A will never be positive) .DLL26 LDA Q \ If we get here then the bank we just checked is not STA XX12,X \ fully charged, so store its value in XX12 (using Q, \ which contains the energy of the remaining banks - \ i.e. this one) \ Now that we have the four energy bank values in XX12, \ we can draw them, starting with the top bank in XX12 \ and looping down to the bottom bank in XX12+3, using Y \ as a loop counter, which was set to 0 above .DLL9 LDA XX12,Y \ Fetch the value of the Y-th indicator, starting from \ the top STY P \ Store the indicator number in P for retrieval later JSR DIL \ Draw the energy bank using a range of 0-15, and \ increment SC to point to the next indicator (the \ next energy bank down) LDY P \ Restore the indicator number into Y INY \ Increment the indicator number CPY #4 \ Check to see if we have drawn the last energy bank BNE DLL9 \ Loop back to DLL9 if we have more banks to draw, \ otherwise we are done
Name: DIALS (Part 4 of 4) [Show more] Type: Subroutine Category: Dashboard Summary: Update the dashboard: shields, fuel, laser & cabin temp, altitude Deep dive: The dashboard indicators
Context: See this subroutine on its own page Variations: See code variations for this subroutine in the different versions References: No direct references to this subroutine in this source file
LDA #&78 \ Set SC(1 0) = &7810, which is the screen address for STA SC+1 \ the character block containing the left end of the LDA #&10 \ top indicator in the left part of the dashboard, the STA SC \ one showing the forward shield LDA FSH \ Draw the forward shield indicator using a range of JSR DILX \ 0-255, and increment SC to point to the next indicator \ (the aft shield) LDA ASH \ Draw the aft shield indicator using a range of 0-255, JSR DILX \ and increment SC to point to the next indicator (the \ fuel level) LDA QQ14 \ Draw the fuel level indicator using a range of 0-63, JSR DILX+2 \ and increment SC to point to the next indicator (the \ cabin temperature) JSR PZW \ Call PZW to set A to the colour for dangerous values \ and X to the colour for safe values STX K+1 \ Set K+1 (the colour we should show for low values) to \ X (the colour to use for safe values) STA K \ Set K (the colour we should show for high values) to \ A (the colour to use for dangerous values) \ The above sets the following indicators to show red \ for high values and yellow/white for low values, which \ we use for the cabin and laser temperature bars LDX #11 \ Set T1 to 11, the threshold at which we change the STX T1 \ cabin and laser temperature indicators' colours LDA CABTMP \ Draw the cabin temperature indicator using a range of JSR DILX \ 0-255, and increment SC to point to the next indicator \ (the laser temperature) LDA GNTMP \ Draw the laser temperature indicator using a range of JSR DILX \ 0-255, and increment SC to point to the next indicator \ (the altitude) LDA #240 \ Set T1 to 240, the threshold at which we change the STA T1 \ altitude indicator's colour. As the altitude has a \ range of 0-255, pixel 16 will not be filled in, and \ 240 would change the colour when moving between pixels \ 15 and 16, so this effectively switches off the colour \ change for the altitude indicator STA K+1 \ Set K+1 (the colour we should show for low values) to \ 240, or &F0 (dashboard colour 2, yellow/white), so the \ altitude indicator always shows in this colour LDA ALTIT \ Draw the altitude indicator using a range of 0-255, JMP DILX \ returning from the subroutine using a tail call
Name: PZW [Show more] Type: Subroutine Category: Dashboard Summary: Fetch the current dashboard colours, to support flashing
Context: See this subroutine on its own page Variations: See code variations for this subroutine in the different versions References: This subroutine is called as follows: * DIALS (Part 1 of 4) calls PZW * DIALS (Part 3 of 4) calls PZW * DIALS (Part 4 of 4) calls PZW

Set A and X to the colours we should use for indicators showing dangerous and safe values respectively. This enables us to implement flashing indicators, which is one of the game's configurable options. If flashing is enabled, the colour returned in A (dangerous values) will be red for 8 iterations of the main loop, and yellow/white for the next 8, before going back to red. If we always use PZW to decide which colours we should use when updating indicators, flashing colours will be automatically taken care of for us. The values returned are &F0 for yellow/white and &0F for red. These are mode 5 bytes that contain 4 pixels, with the colour of each pixel given in two bits, the high bit from the first nibble (bits 4-7) and the low bit from the second nibble (bits 0-3). So in &F0 each pixel is %10, or colour 2 (yellow or white, depending on the dashboard palette), while in &0F each pixel is %01, or colour 1 (red).
Returns: A The colour to use for indicators with dangerous values X The colour to use for indicators with safe values
.PZW LDX #&F0 \ Set X to dashboard colour 2 (yellow/white) LDA MCNT \ A will be non-zero for 8 out of every 16 main loop AND #%00001000 \ counts, when bit 4 is set, so this is what we use to \ flash the "danger" colour AND FLH \ A will be zeroed if flashing colours are disabled BEQ P%+4 \ If A is zero, skip to the LDA instruction below TXA \ Otherwise flashing colours are enabled and it's the \ main loop iteration where we flash them, so set A to \ colour 2 (yellow/white) and use the BIT trick below to \ return from the subroutine EQUB &2C \ Skip the next instruction by turning it into \ &2C &A9 &0F, or BIT &0FA9, which does nothing apart \ from affect the flags LDA #&0F \ Set A to dashboard colour 1 (red) RTS \ Return from the subroutine
Name: DILX [Show more] Type: Subroutine Category: Dashboard Summary: Update a bar-based indicator on the dashboard Deep dive: The dashboard indicators
Context: See this subroutine on its own page Variations: See code variations for this subroutine in the different versions References: This subroutine is called as follows: * DIALS (Part 4 of 4) calls DILX * DIALS (Part 4 of 4) calls via DILX+2 * DIALS (Part 1 of 4) calls via DIL-1 * DIALS (Part 3 of 4) calls via DIL

The range of values shown on the indicator depends on which entry point is called. For the default entry point of DILX, the range is 0-255 (as the value passed in A is one byte). The other entry points are shown below.
Arguments: A The value to be shown on the indicator (so the larger the value, the longer the bar) T1 The threshold at which we change the indicator's colour from the low value colour to the high value colour. The threshold is in pixels, so it should have a value from 0-16, as each bar indicator is 16 pixels wide K The colour to use when A is a high value, as a 4-pixel mode 5 character row byte K+1 The colour to use when A is a low value, as a 4-pixel mode 5 character row byte SC(1 0) The screen address of the first character block in the indicator
Other entry points: DILX+2 The range of the indicator is 0-64 (for the fuel indicator) DIL-1 The range of the indicator is 0-32 (for the speed indicator) DIL The range of the indicator is 0-16 (for the energy banks)
.DILX LSR A \ If we call DILX, we set A = A / 16, so A is 0-15 LSR A LSR A \ If we call DILX+2, we set A = A / 4, so A is 0-15 LSR A \ If we call DIL-1, we set A = A / 2, so A is 0-15 .DIL \ If we call DIL, we leave A alone, so A is 0-15 STA Q \ Store the indicator value in Q, now reduced to 0-15, \ which is the length of the indicator to draw in pixels LDX #&FF \ Set R = &FF, to use as a mask for drawing each row of STX R \ each character block of the bar, starting with a full \ character's width of 4 pixels CMP T1 \ If A >= T1 then we have passed the threshold where we BCS DL30 \ change bar colour, so jump to DL30 to set A to the \ "high value" colour LDA K+1 \ Set A to K+1, the "low value" colour to use BNE DL31 \ Jump down to DL31 (this BNE is effectively a JMP as A \ will never be zero) .DL30 LDA K \ Set A to K, the "high value" colour to use .DL31 STA COL \ Store the colour of the indicator in COL LDY #2 \ We want to start drawing the indicator on the third \ line in this character row, so set Y to point to that \ row's offset LDX #3 \ Set up a counter in X for the width of the indicator, \ which is 4 characters (each of which is 4 pixels wide, \ to give a total width of 16 pixels) .DL1 LDA Q \ Fetch the indicator value (0-15) from Q into A CMP #4 \ If Q < 4, then we need to draw the end cap of the BCC DL2 \ indicator, which is less than a full character's \ width, so jump down to DL2 to do this SBC #4 \ Otherwise we can draw a 4-pixel wide block, so STA Q \ subtract 4 from Q so it contains the amount of the \ indicator that's left to draw after this character LDA R \ Fetch the shape of the indicator row that we need to \ display from R, so we can use it as a mask when \ painting the indicator. It will be &FF at this point \ (i.e. a full 4-pixel row) .DL5 AND COL \ Fetch the 4-pixel mode 5 colour byte from COL, and \ only keep pixels that have their equivalent bits set \ in the mask byte in A STA (SC),Y \ Draw the shape of the mask on pixel row Y of the \ character block we are processing INY \ Draw the next pixel row, incrementing Y STA (SC),Y INY \ And draw the third pixel row, incrementing Y STA (SC),Y TYA \ Add 6 to Y, so Y is now 8 more than when we started CLC \ this loop iteration, so Y now points to the address ADC #6 \ of the first line of the indicator bar in the next TAY \ character block (as each character is 8 bytes of \ screen memory) DEX \ Decrement the loop counter for the next character \ block along in the indicator BMI DL6 \ If we just drew the last character block then we are \ done drawing, so jump down to DL6 to finish off BPL DL1 \ Loop back to DL1 to draw the next character block of \ the indicator (this BPL is effectively a JMP as A will \ never be negative following the previous BMI) .DL2 EOR #3 \ If we get here then we are drawing the indicator's STA Q \ end cap, so Q is < 4, and this EOR flips the bits, so \ instead of containing the number of indicator columns \ we need to fill in on the left side of the cap's \ character block, Q now contains the number of blank \ columns there should be on the right side of the cap's \ character block LDA R \ Fetch the current mask from R, which will be &FF at \ this point, so we need to turn Q of the columns on the \ right side of the mask to black to get the correct end \ cap shape for the indicator .DL3 ASL A \ Shift the mask left so bit 0 is cleared, and then AND #%11101111 \ clear bit 4, which has the effect of shifting zeroes \ from the left into each nibble (i.e. xxxx xxxx becomes \ xxx0 xxx0, which blanks out the last column in the \ 4-pixel mode 5 character block) DEC Q \ Decrement the counter for the number of columns to \ blank out BPL DL3 \ If we still have columns to blank out in the mask, \ loop back to DL3 until the mask is correct for the \ end cap PHA \ Store the mask byte on the stack while we use the \ accumulator for a bit LDA #0 \ Change the mask so no bits are set, so the characters STA R \ after the one we're about to draw will be all blank LDA #99 \ Set Q to a high number (99, why not) so we will keep STA Q \ drawing blank characters until we reach the end of \ the indicator row PLA \ Restore the mask byte from the stack so we can use it \ to draw the end cap of the indicator JMP DL5 \ Jump back up to DL5 to draw the mask byte on-screen .DL6 INC SC+1 \ Increment the high byte of SC to point to the next \ character row on-screen (as each row takes up exactly \ one page of 256 bytes) - so this sets up SC to point \ to the next indicator, i.e. the one below the one we \ just drew .DL9 RTS \ Return from the subroutine
Name: DIL2 [Show more] Type: Subroutine Category: Dashboard Summary: Update the roll or pitch indicator on the dashboard Deep dive: The dashboard indicators
Context: See this subroutine on its own page Variations: See code variations for this subroutine in the different versions References: This subroutine is called as follows: * DIALS (Part 2 of 4) calls DIL2

The indicator can show a vertical bar in 16 positions, with a value of 8 showing the bar in the middle of the indicator. In practice this routine is only ever called with A in the range 1 to 15, so the vertical bar never appears in the leftmost position (though it does appear in the rightmost).
Arguments: A The offset of the vertical bar to show in the indicator, from 0 at the far left, to 8 in the middle, and 15 at the far right
Returns: C flag The C flag is set
.DIL2 LDY #1 \ We want to start drawing the vertical indicator bar on \ the second line in the indicator's character block, so \ set Y to point to that row's offset STA Q \ Store the offset of the vertical bar to draw in Q \ We are now going to work our way along the indicator \ on the dashboard, from left to right, working our way \ along one character block at a time. Y will be used as \ a pixel row counter to work our way through the \ character blocks, so each time we draw a character \ block, we will increment Y by 8 to move on to the next \ block (as each character block contains 8 rows) .DLL10 SEC \ Set A = Q - 4, so that A contains the offset of the LDA Q \ vertical bar from the start of this character block SBC #4 BCS DLL11 \ If Q >= 4 then the character block we are drawing does \ not contain the vertical indicator bar, so jump to \ DLL11 to draw a blank character block LDA #&FF \ Set A to a high number (and &FF is as high as they go) LDX Q \ Set X to the offset of the vertical bar, which we know \ is within this character block STA Q \ Set Q to a high number (&FF, why not) so we will keep \ drawing blank characters after this one until we reach \ the end of the indicator row LDA CTWOS,X \ CTWOS is a table of ready-made 1-pixel mode 5 bytes, \ just like the TWOS and TWOS2 tables for mode 4 (see \ the PIXEL routine for details of how they work). This \ fetches a mode 5 1-pixel byte with the pixel position \ at X, so the pixel is at the offset that we want for \ our vertical bar AND #&F0 \ The 4-pixel mode 5 colour byte &F0 represents four \ pixels of colour %10 (3), which is yellow in the \ normal dashboard palette and white if we have an \ escape pod fitted. We AND this with A so that we only \ keep the pixel that matches the position of the \ vertical bar (i.e. A is acting as a mask on the \ 4-pixel colour byte) JMP DLL12 \ Jump to DLL12 to skip the code for drawing a blank, \ and move on to drawing the indicator .DLL11 \ If we get here then we want to draw a blank for this \ character block STA Q \ Update Q with the new offset of the vertical bar, so \ it becomes the offset after the character block we \ are about to draw LDA #0 \ Change the mask so no bits are set, so all of the \ character blocks we display from now on will be blank .DLL12 STA (SC),Y \ Draw the shape of the mask on pixel row Y of the \ character block we are processing INY \ Draw the next pixel row, incrementing Y STA (SC),Y INY \ And draw the third pixel row, incrementing Y STA (SC),Y INY \ And draw the fourth pixel row, incrementing Y STA (SC),Y TYA \ Add 5 to Y, so Y is now 8 more than when we started CLC \ this loop iteration, so Y now points to the address ADC #5 \ of the first line of the indicator bar in the next TAY \ character block (as each character is 8 bytes of \ screen memory) CPY #30 \ If Y < 30 then we still have some more character BCC DLL10 \ blocks to draw, so loop back to DLL10 to display the \ next one along INC SC+1 \ Increment the high byte of SC to point to the next \ character row on-screen (as each row takes up exactly \ one page of 256 bytes) - so this sets up SC to point \ to the next indicator, i.e. the one below the one we \ just drew RTS \ Return from the subroutine
Name: HME2 [Show more] Type: Subroutine Category: Charts Summary: Search the galaxy for a system
Context: See this subroutine on its own page Variations: See code variations for this subroutine in the different versions References: This subroutine is called as follows: * TT102 calls HME2
.HME2 LDA #14 \ Print extended token 14 ("{clear bottom of screen} JSR DETOK \ PLANET NAME?{fetch line input from keyboard}"). The \ last token calls MT26, which puts the entered search \ term in INWK+5 and the term length in Y JSR TT103 \ Draw small crosshairs at coordinates (QQ9, QQ10), \ which will erase the crosshairs currently there JSR TT81 \ Set the seeds in QQ15 (the selected system) to those \ of system 0 in the current galaxy (i.e. copy the seeds \ from QQ21 to QQ15) LDA #0 \ We now loop through the galaxy's systems in order, STA XX20 \ until we find a match, so set XX20 to act as a system \ counter, starting with system 0 .HME3 JSR MT14 \ Switch to justified text when printing extended \ tokens, so the call to cpl prints into the justified \ text buffer at BUF instead of the screen, and DTW5 \ gets set to the length of the system name JSR cpl \ Print the selected system name into the justified text \ buffer LDX DTW5 \ Fetch DTW5 into X, so X is now equal to the length of \ the selected system name LDA INWK+5,X \ Fetch the X-th character from the entered search term CMP #13 \ If the X-th character is not a carriage return, then BNE HME6 \ the selected system name and the entered search term \ are different lengths, so jump to HME6 to move on to \ the next system .HME4 DEX \ Decrement X so it points to the last letter of the \ selected system name (and, when we loop back here, it \ points to the next letter to the left) LDA INWK+5,X \ Set A to the X-th character of the entered search term ORA #%00100000 \ Set bit 5 of the character to make it lower case CMP BUF,X \ If the character in A matches the X-th character of BEQ HME4 \ the selected system name in BUF, loop back to HME4 to \ check the next letter to the left TXA \ The last comparison didn't match, so copy the letter BMI HME5 \ number into A, and if it's negative, that means we \ managed to go past the first letters of each term \ before we failed to get a match, so the terms are the \ same, so jump to HME5 to process a successful search .HME6 \ If we get here then the selected system name and the \ entered search term did not match JSR TT20 \ We want to move on to the next system, so call TT20 \ to twist the three 16-bit seeds in QQ15 INC XX20 \ Increment the system counter in XX20 BNE HME3 \ If we haven't yet checked all 256 systems in the \ current galaxy, loop back to HME3 to check the next \ system \ If we get here then the entered search term did not \ match any systems in the current galaxy JSR TT111 \ Select the system closest to galactic coordinates \ (QQ9, QQ10), so we can put the crosshairs back where \ they were before the search JSR TT103 \ Draw small crosshairs at coordinates (QQ9, QQ10) LDA #40 \ Call the NOISE routine with A = 40 to make a low, JSR NOISE \ long beep to indicate a failed search LDA #215 \ Print extended token 215 ("{left align} UNKNOWN JMP DETOK \ PLANET"), which will print on-screen as the left align \ code disables justified text, and return from the \ subroutine using a tail call .HME5 \ If we get here then we have found a match for the \ entered search LDA QQ15+3 \ The x-coordinate of the system described by the seeds STA QQ9 \ in QQ15 is in QQ15+3 (s1_hi), so we copy this to QQ9 \ as the x-coordinate of the search result LDA QQ15+1 \ The y-coordinate of the system described by the seeds STA QQ10 \ in QQ15 is in QQ15+1 (s0_hi), so we copy this to QQ10 \ as the y-coordinate of the search result JSR TT111 \ Select the system closest to galactic coordinates \ (QQ9, QQ10) JSR TT103 \ Draw small crosshairs at coordinates (QQ9, QQ10) JSR MT15 \ Switch to left-aligned text when printing extended \ tokens so future tokens will print to the screen (as \ this disables justified text) JMP T95 \ Jump to T95 to print the distance to the selected \ system and return from the subroutine using a tail \ call
Save ELTB.bin
PRINT "ELITE B" PRINT "Assembled at ", ~CODE_B% PRINT "Ends at ", ~P% PRINT "Code size is ", ~(P% - CODE_B%) PRINT "Execute at ", ~LOAD% PRINT "Reload at ", ~LOAD_B% PRINT "S.ELTB ", ~CODE_B%, " ", ~P%, " ", ~LOAD%, " ", ~LOAD_B% \SAVE "3-assembled-output/T.ELTB.bin", CODE_B%, P%, LOAD%