Skip to navigation

Elite on the BBC Micro

Elite B parasite source [Elite-A]

ELITE B FILE
CODE_B% = P% LOAD_B% = LOAD% + P% - CODE%
Name: LL30 [Show more] Type: Subroutine Category: Drawing lines Summary: Draw a one-segment line by sending a draw_line command to the I/O processor
Context: See this subroutine on its own page References: This subroutine is called as follows: * LL9 (Part 12 of 12) calls LL30 * TT15 calls LL30

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
.LOIN .LL30 LDA #&80 \ Send command &80 to the I/O processor: JSR tube_write \ \ draw_line(x1, y1, x2, y2) \ \ which will draw a line from (x1, y1) to (x2, y2) LDA X1 \ Send the first parameter to the I/O processor: JSR tube_write \ \ * x1 = X1 LDA Y1 \ Send the second parameter to the I/O processor: JSR tube_write \ \ * y1 = Y1 LDA X2 \ Send the first parameter to the I/O processor: JSR tube_write \ \ * x2 = X2 LDA Y2 \ Send the first parameter to the I/O processor: JMP tube_write \ \ * y2 = Y2 \ \ and return from the subroutine using a tail call
Name: FLKB [Show more] Type: Subroutine Category: Keyboard Summary: Flush the keyboard buffer
Context: See this subroutine on its own page 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 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 * sell_jump 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 * controls calls NLIN4 * cour_buy calls NLIN4 * equip_data calls NLIN4 * menu calls NLIN4 * ships_ag 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 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 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 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 by sending a draw_hline command to the I/O processor
Context: See this subroutine on its own page References: This subroutine is called as follows: * NLIN2 calls HLOIN * SUN (Part 3 of 4) calls HLOIN * TT15 calls HLOIN * TTX66 calls HLOIN

Arguments: X1 The screen x-coordinate of the start of the line X2 The screen x-coordinate of the end of the line Y1 The screen y-coordinate of the line
.HLOIN LDA #&81 \ Send command &81 to the I/O processor: JSR tube_write \ \ draw_hline(x1, y1, x2) \ \ which will draw a horizontal line from (x1, y1) to \ (x2, y1) LDA X1 \ Send the first parameter to the I/O processor: JSR tube_write \ \ * x1 = X1 LDA Y1 \ Send the second parameter to the I/O processor: JSR tube_write \ \ * y1 = Y1 LDA X2 \ Send the first parameter to the I/O processor: JMP tube_write \ \ * x2 = X2 \ \ and return from the subroutine using a tail call
Name: PIXEL [Show more] Type: Subroutine Category: Drawing pixels Summary: Draw a 1-pixel dot, 2-pixel dash or 4-pixel square by sending a draw_pixel command to the I/O processor
Context: See this subroutine on its own page References: This subroutine is called as follows: * DOEXP calls PIXEL * PIXEL2 calls PIXEL * TT22 calls PIXEL

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)
.PIXEL PHA \ Store the y-coordinate on the stack LDA #&82 \ Send command &82 to the I/O processor: JSR tube_write \ \ draw_pixel(x, y, distance) \ \ which will draw a pixel at (x, y) with the size \ determined by the distance TXA \ Send the first parameter to the I/O processor: JSR tube_write \ \ * x = X PLA \ Send the second parameter to the I/O processor: JSR tube_write \ \ * y = A LDA ZZ \ Send the third parameter to the I/O processor: JMP tube_write \ \ * distance = ZZ \ \ and return from the subroutine using a tail call
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 References: This subroutine is called as follows: * CIRCLE2 calls BLINE * PLS22 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 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 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: PRXS [Show more] Type: Variable Category: Equipment Summary: Equipment prices
Context: See this variable on its own page References: This variable is used as follows: * EQSHP calls PRXS * prx calls 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. Different ships have different equipment prices (apart from fuel which is the same price for all ships). Each ship type has an offset that is used when accessing this table; the offset to the price table for our current ship is held in the new_costs variable, and the offset values for all the different ships we can buy are defined in the new_details table.
.PRXS EQUW 1 \ 0 Fuel, calculated in EQSHP 140.0 Cr (full tank) \ Offset 0 (PRXS+0): Boa, Cobra Mk III, Ghavial, Iguana EQUW 250 \ 1 Missile 25.0 Cr EQUW 4000 \ 2 I.F.F. System 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 3000 \ 7 Escape Pod 300.0 Cr EQUW 5500 \ 8 Hyperspace Unit 550.0 Cr EQUW 15000 \ 9 Energy Unit 1500.0 Cr EQUW 15000 \ 10 Docking Computer 1500.0 Cr EQUW 50000 \ 11 Galactic Hyperspace 5000.0 Cr EQUW 30000 \ 12 Extra Military Lasers 3000.0 Cr EQUW 2500 \ 13 Extra Mining Lasers 250.0 Cr \ Offset 1 (PRXS+26): Adder, Cobra Mk I, Gecko, Python EQUW 250 \ 1 Missile 25.0 Cr EQUW 2000 \ 2 I.F.F. System 200.0 Cr EQUW 4000 \ 3 E.C.M. System 400.0 Cr EQUW 2000 \ 4 Extra Pulse Lasers 200.0 Cr EQUW 4500 \ 5 Extra Beam Lasers 450.0 Cr EQUW 3750 \ 6 Fuel Scoops 375.0 Cr EQUW 2000 \ 7 Escape Pod 200.0 Cr EQUW 3750 \ 8 Hyperspace Unit 375.0 Cr EQUW 9000 \ 9 Energy Unit 900.0 Cr EQUW 8000 \ 10 Docking Computer 800.0 Cr EQUW 30000 \ 11 Galactic Hyperspace 3000.0 Cr EQUW 23000 \ 12 Extra Military Lasers 2300.0 Cr EQUW 2500 \ 13 Extra Mining Lasers 250.0 Cr \ Offset 2 (PRXS+52): Asp Mk II, Fer-de-Lance EQUW 250 \ 1 Missile 25.0 Cr EQUW 4000 \ 2 I.F.F. System 400.0 Cr EQUW 5000 \ 3 E.C.M. System 500.0 Cr EQUW 5000 \ 4 Extra Pulse Lasers 500.0 Cr EQUW 10000 \ 5 Extra Beam Lasers 1000.0 Cr EQUW 7000 \ 6 Fuel Scoops 700.0 Cr EQUW 6000 \ 7 Escape Pod 600.0 Cr EQUW 4000 \ 8 Hyperspace Unit 400.0 Cr EQUW 25000 \ 9 Energy Unit 2500.0 Cr EQUW 10000 \ 10 Docking Computer 1000.0 Cr EQUW 40000 \ 11 Galactic Hyperspace 4000.0 Cr EQUW 50000 \ 12 Extra Military Lasers 5000.0 Cr EQUW 2500 \ 13 Extra Mining Lasers 250.0 Cr \ Offset 3 (PRXS+78): Anaconda, Monitor EQUW 250 \ 1 Missile 25.0 Cr EQUW 3000 \ 2 I.F.F. System 300.0 Cr EQUW 8000 \ 3 E.C.M. System 800.0 Cr EQUW 6000 \ 4 Extra Pulse Lasers 600.0 Cr EQUW 8000 \ 5 Extra Beam Lasers 800.0 Cr EQUW 6500 \ 6 Fuel Scoops 650.0 Cr EQUW 4500 \ 7 Escape Pod 450.0 Cr EQUW 8000 \ 8 Hyperspace Unit 800.0 Cr EQUW 19000 \ 9 Energy Unit 1900.0 Cr EQUW 20000 \ 10 Docking Computer 2000.0 Cr EQUW 60000 \ 11 Galactic Hyperspace 6000.0 Cr EQUW 25000 \ 12 Extra Military Lasers 2500.0 Cr EQUW 2500 \ 13 Extra Mining Lasers 250.0 Cr \ Offset 4 (PRXS+104): Chameleon, Moray, Ophidian EQUW 250 \ 1 Missile 25.0 Cr EQUW 1500 \ 2 I.F.F. System 150.0 Cr EQUW 3000 \ 3 E.C.M. System 300.0 Cr EQUW 3500 \ 4 Extra Pulse Lasers 350.0 Cr EQUW 7000 \ 5 Extra Beam Lasers 700.0 Cr EQUW 4500 \ 6 Fuel Scoops 450.0 Cr EQUW 2500 \ 7 Escape Pod 250.0 Cr EQUW 4500 \ 8 Hyperspace Unit 450.0 Cr EQUW 7000 \ 9 Energy Unit 700.0 Cr EQUW 7000 \ 10 Docking Computer 700.0 Cr EQUW 30000 \ 11 Galactic Hyperspace 3000.0 Cr EQUW 19000 \ 12 Extra Military Lasers 1900.0 Cr EQUW 2500 \ 13 Extra Mining Lasers 250.0 Cr
Name: STATUS [Show more] Type: Subroutine Category: Status Summary: Show the Status Mode screen (red key f8) Deep dive: Combat rank Other entry points: sell_equip Show the Sell Equipment screen, i.e. show a "Sell(Y/N)?" prompt as we print each item of equipment
Context: See this subroutine on its own page References: This subroutine is called as follows: * TT102 calls STATUS * sell_jump calls entry point sell_equip
.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 BIT dockedp \ If bit 7 of dockedp is clear, then we are docked, so BPL stat_dock \ jump to stat_dock to print "Docked" for our ship's \ condition LDA #230 \ Otherwise we are in space, so start off by setting A \ to token 70 ("GREEN") LDY JUNK \ Set Y to the number of junk items in our local bubble \ of universe (where junk is asteroids, canisters, \ escape pods and so on) LDX FRIN+2,Y \ The ship slots at FRIN are ordered with the first two \ slots reserved for the planet and sun/space station, \ and then any ships, so if the slot at FRIN+2+Y is not \ empty (i.e is non-zero), then that means the number of \ non-asteroids in the vicinity is at least 1 BEQ st6 \ So if X = 0, there are no ships in the vicinity, so \ jump to st6 to print "Green" for our ship's condition LDY ENERGY \ Otherwise we have ships in the vicinity, so we load \ our energy levels into Y CPY #128 \ Set the C flag if Y >= 128, so C is set if we have \ more than half of our energy banks charged ADC #1 \ Add 1 + C to A, so if C is not set (i.e. we have low \ energy levels) then A is set to token 231 ("RED"), \ and if C is set (i.e. we have healthy energy levels) \ then A is set to token 232 ("YELLOW") .st6 JSR plf \ Print the text token in A (which contains our ship's \ condition) followed by a newline JMP stat_legal \ Jump to stat_legal to skip the following, as we are \ not docked and have already printed the correct \ in-flight status .stat_dock LDA #205 \ Print extended token 205 ("DOCKED") JSR DETOK JSR TT67 \ Print a newline .stat_legal 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:") JSR spc 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 \ Call status_equip with A set to recursive token 132 JSR status_equip \ to print the next bit of the Status Mode screen: \ \ {current ship type}: \ \ followed by a newline and an indent of 8 characters .sell_equip LDA CRGO \ If we don't have an I.F.F. system fitted (i.e. CRGO is BEQ P%+9 \ zero), skip the following three instructions LDA #107 \ We do have an I.F.F. system fitted, so print recursive LDX #6 \ token 107 ("I.F.F.SYSTEM"). If this is the Status Mode JSR status_equip \ or Inventory screen, print a newline and an indent of \ 8 characters, or if this is the Sell Equipment screen, \ show and process a sell prompt for the piece of \ equipment at LASER+X = LASER+6 = CRGO before printing \ a newline LDA BST \ If we don't have fuel scoops fitted, skip the BEQ P%+9 \ following three instructions LDA #111 \ We do have a fuel scoops fitted, so print recursive LDX #25 \ token 111 ("FUEL SCOOPS"). If this is the Status Mode JSR status_equip \ or Inventory screen, print a newline and an indent of \ 8 characters, or if this is the Sell Equipment screen, \ show and process a sell prompt for the piece of \ equipment at LASER+X = LASER+25 = BST before printing \ a newline LDA ECM \ If we don't have an E.C.M. fitted, skip the following BEQ P%+9 \ three instructions LDA #108 \ We do have an E.C.M. fitted, so print recursive token LDX #24 \ 108 ("E.C.M.SYSTEM"). If this is the Status Mode or JSR status_equip \ Inventory screen, print a newline and an indent of 8 \ characters, or if this is the Sell Equipment screen, \ show and process a sell prompt for the piece of \ equipment at LASER+X = LASER+24 = ECM before printing \ a newline \LDA #113 \ These instructions are commented out in the original \STA XX4 \ source LDX #26 \ Set X = 26 so we now process equipment from LASER+26 \ onwards (i.e. BOMB onwards), using X as a counter \ going from LASER+26 (BOMB) to LASER+29 (GHYP) .stqv STX CNT \ Store the X counter in CNT so we can retrieve it below \TAY \ These instructions are commented out in the original \LDX FRIN,Y \ source LDY LASER,X \ Fetch the equipment flag from LASER+X, and if we do BEQ P%+9 \ not have that equipment fitted, skip the following \ four instructions to move onto the next piece of \ equipment TXA \ Set A = X + 87 CLC \ ADC #87 \ so A is now a token number between 113 ("HYPERSPACE \ UNIT") and 116 ("GALACTIC HYPERSPACE ") JSR status_equip \ Print the recursive token in A. If this is the Status \ Mode or Inventory screen, print a newline and an \ indent of 8 characters, or if this is the Sell \ Equipment screen, show and process a sell prompt for \ the piece of equipment at LASER+X before printing a \ newline \INC XX4 \ These instructions are commented out in the original \LDA XX4 \ source \CMP #117 LDX CNT \ Retrieve the X counter from CNT that we stored above INX \ Increment the loop counter CPX #30 \ Loop back to print the next piece of equipment until BCC stqv \ we have done LASER+26 (BOMB) to LASER+29 (GHYP) 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 ORA #96 \ ("FRONT") through to 99 ("RIGHT"), followed by a space JSR spc \ (the ORA acts like an addition as 96 = %01100000) 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 new_beam \ If the laser power for view X is not that of a beam BNE P%+4 \ laser when fitted to our current ship type, 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 new_military \ If the laser power for view X is not that of a BNE P%+4 \ military laser when fitted to our current ship type, \ 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 new_mining \ If the laser power for view X is not that of a mining BNE P%+4 \ laser when fitted to our current ship type, 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 status_equip \ Print the recursive token in A. If this is the Status \ Mode or Inventory screen, print a newline and an \ indent of 8 characters, or if this is the Sell \ Equipment screen, show and process a sell prompt for \ the piece of equipment at LASER+X before printing a \ newline .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: status_equip [Show more] Type: Subroutine Category: Text Summary: Print equipment name, adding a sell prompt if appropriate
Context: See this subroutine on its own page References: This subroutine is called as follows: * STATUS calls status_equip * sell_jump calls status_equip

Print a text token containing the equipment name. Then: * If this is the Status Mode or Inventory screen, print a newline and move the text cursor to column 8 * If this is the Sell Equipment screen, show and process a "Sell(Y/N)?" prompt on the end of the same line as the equipment name, and move the text cursor to the start of the next line Arguments: A The text token to be printed X If this is the Sell Equipment screen, this contains the offset from LASER where this piece of equipment's flag is stored (e.g. X = 25 means LASER+25, which is BST, the flag for the fuel scoops)
.status_equip STX CNT \ Store the tab indent in CNT, so we can use it later STA XX4 \ Store the text token in XX4, so we can use it later JSR TT27 \ Print the text token in A LDX QQ11 \ If the current view is the Status Mode screen or the CPX #8 \ Inventory screen, jump to status_keep to print a tab BEQ status_keep \ to column 8 (as X = 8) and return from the subroutine, \ as we don't want to show a sell prompt LDA #21 \ Move the text cursor to column 21 STA XC JSR vdu_80 \ Call vdu_80 to switch to Sentence Case, with the next \ letter in capitals LDA #1 \ Set QQ25 to 1, which sets the maximum number of items STA QQ25 \ we can sell in the following call to sell_yn JSR sell_yn \ Call sell_yn to print a "Sell(Y/N)?" prompt and get a \ number from the keyboard BEQ status_no \ If no number was entered, jump to status_no to move to \ the next line and return from the subroutine BCS status_no \ If the number entered was too big, jump to status_no \ to move to the next line and return from the \ subroutine LDA XX4 \ If XX4 >= 107, then the token is a piece of equipment CMP #107 \ ("I.F.F.SYSTEM" onwards) rather a laser, so skip the BCS status_over \ following instruction to reach status_over with \ A >= 107 and the C flag set ADC #7 \ The token in A is < 107, so it must be a pulse laser \ (103) or beam laser (104), so add 7 to set A to 110 \ or 111 (as we know the C flag is clear), and fall \ through into status_over with the C flag clear .status_over \ We get here with one of the following: \ \ * A >= 107 and the C flag set, if this is not a \ pulse or beam laser \ \ * A = 110 or 111 with the C flag clear, if this is a \ pulse or beam laser SBC #104 \ Subtract 104 - (1 - C) from the token number, so \ either: \ \ * A is now 1 for fuel, 2 for missiles, 3 for the \ I.F.F. system, and so on \ \ * A = 5 or 6 for pulse or beam lasers \ \ In each case, A contains the equipment number from the \ PRXS table, plus 1 JSR prx-3 \ Call prx-3 to set (A X) to the price of the item with \ number A - 1 LSR A \ We now halve the price in (A X) and put the result TAY \ into (Y X), starting with the high byte in A TXA \ And then halving the low byte in X ROR A TAX JSR MCASH \ Call MCASH to add (Y X) to the cash pot, so we get \ half of the original price back when selling equipment INC new_hold \ We just sold a piece of equipment, so increment the \ amount of free space in the hold LDX CNT \ Set X to the value we stored in CNT above, so it now \ contains the equipment flag's offset from LASER LDA #0 \ We just sold this pieve of equipment, so set the flag STA LASER,X \ to zero to indicate we no longer have the equipment \ fitted JSR update_pod \ Update the dashboard colours to reflect whether we \ have an escape pod .status_no LDX #1 \ Set X = 1 so we move the text cursor to column 1 in \ in the next instruction .status_keep STX XC \ Move the text cursor to the column specified in X LDA #10 \ Print a line feed to move the text cursor down a line JMP TT27 \ and return from the subroutine using a tail call
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 calls 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 * TT210 calls pr2 * TT213 calls pr2 * TT25 calls pr2 * cour_count calls pr2 * fwl calls pr2 * menu calls pr2 * n_buyship calls pr2 * tal calls pr2 * TT151 calls entry point 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-1 Print X without a decimal point
CLC \ Clear the C flag so the routine doesn't print a \ decimal point if called via pr2-1 .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 * cour_count calls TT11 * cour_dock 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 References: This subroutine is called as follows: * csh calls BPRNT * n_buyship 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 calls DTW1 * MT13 calls DTW1 * MT2 calls 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 calls DTW2 * DETOK2 calls DTW2 * MT8 calls DTW2 * TT26 calls DTW2 * TTX66 calls 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 calls DTW3 * MT5 calls 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 calls DTW4 * TT26 calls 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 printe 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 calls DTW5 * MT15 calls DTW5 * MT17 calls DTW5 * TT26 calls 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 calls DTW6 * MT13 calls DTW6 * MT2 calls 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 1, {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 calls DTW8 * MT19 calls DTW8 * TT26 calls 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 * confirm 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 References: This subroutine is called as follows: * BPRNT calls TT26 * TT160 calls TT26 * TT161 calls TT26 * TT16a calls TT26 * TT25 calls TT26 * TT42 calls TT26 * TT74 calls TT26 * cmn calls TT26 * gnum calls TT26 * DETOK2 calls entry point DASC * JMTB calls entry point DASC * menu calls entry point 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 then 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 .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 References: This subroutine is called as follows: * DKS3 calls BELL

This is the standard system beep as made by the VDU 7 statement in BBC BASIC.
.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 sending a write_xyc command to the I/O processor Deep dive: Drawing text
Context: See this subroutine on its own page References: This subroutine is called as follows: * GTDRV calls CHPR * TT26 calls CHPR * confirm calls CHPR

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: RR3+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 LDA YC \ Fetch YC, the y-coordinate (row) of the text cursor CMP #24 \ If the text cursor is on the screen (i.e. YC < 24, so BCC RR3 \ we are on rows 1-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 LDA #&8E \ Send command &8E to the I/O processor: JSR tube_write \ \ write_xyc(x, y, char) \ \ which will draw the text character in char at column x \ and row y LDA XC \ Send the first parameter to the I/O processor: JSR tube_write \ \ * x = XC LDA YC \ Send the second parameter to the I/O processor: JSR tube_write \ \ * y = YC TYA \ Send the third parameter to the I/O processor: JSR tube_write \ \ * char = the character in Y 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 .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 References: This subroutine is called as follows: * EQSHP calls DIALS * Main game loop for flight (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 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%+5 \ is 0 (i.e. we are not pitching), skip the next two \ instructions SEC \ The C flag is set by the call to DIL2 above, so this \ instruction has no effect SBC #1 \ The pitch angle beta is non-zero, so set A = A - 1. \ 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 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 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 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 by sending a draw_bar command to the I/O processor Deep dive: The dashboard indicators
Context: See this subroutine on its own page References: This subroutine is called as follows: * DIALS (Part 4 of 4) calls DILX * DIALS (Part 1 of 4) calls entry point DIL-1 * DIALS (Part 3 of 4) calls entry point DIL * DIALS (Part 4 of 4) calls entry point DILX+2

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 PHA \ Store the indicator value on the stack LDA #&86 \ Send command &86 to the I/O processor: JSR tube_write \ \ draw_bar(value, colour, screen_low, screen_high) \ \ which will update the bar-based dashboard indicator at \ the specified screen address to a given value and \ colour PLA \ Send the first parameter to the I/O processor: JSR tube_write \ \ * value = A 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 EQUB &2C \ Skip the next instruction by turning it into \ &2C &A5 &40, or BIT &40A5, which does nothing apart \ from affect the flags .DL30 LDA K \ Set A to K, the "high value" colour to use .DL31 JSR tube_write \ Send the second parameter to the I/O processor: \ \ * colour = A LDA SC \ Send the third parameter to the I/O processor: JSR tube_write \ \ * screen_low = SC LDA SC+1 \ Send the fourth parameter to the I/O processor: JSR tube_write \ \ * sch = SC+1 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 by sending a draw_angle command to the I/O processor
Context: See this subroutine on its own page References: This subroutine is called as follows: * DIALS (Part 2 of 4) calls DIL2

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 PHA \ Store the new value of the indicator on the stack LDA #&87 \ Send command &87 to the I/O processor: JSR tube_write \ \ draw_angle(value, screen_low, screen_high) \ \ which will update the roll or pitch dashboard \ indicator to the specified value PLA \ Send the first parameter to the I/O processor: JSR tube_write \ \ * value = A LDA SC \ Send the second parameter to the I/O processor: JSR tube_write \ \ * screen_low = SC LDA SC+1 \ Send the third parameter to the I/O processor: JSR tube_write \ \ * screen_high = SC+1 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 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 \ Incrememt 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-screem 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.2.ELTB ", ~CODE_B%, " ", ~P%, " ", ~LOAD%, " ", ~LOAD_B% SAVE "3-assembled-output/2.ELTB.bin", CODE_B%, P%, LOAD%