Skip to navigation

Elite on the BBC Micro

Elite C parasite source [Elite-A]

ELITE C FILE
CODE_C% = P% LOAD_C% = LOAD% +P% - CODE%
Name: HATB [Show more] Type: Variable Category: Ship hanger Summary: Ship hanger group table
Context: See this variable on its own page References: This variable is used as follows: * HALL calls HATB

This table contains groups of ships to show in the ship hanger. A group of ships is shown half the time (the other half shows a solo ship), and each of the four groups is equally likely. The bytes for each ship in the group contain the following information: Byte #0 Non-zero = Ship type to draw 0 = don't draw anything Byte #1 Bits 0-7 = Ship's x_hi Bit 0 = Ship's z_hi (1 if clear, or 2 if set) Byte #2 Bits 0-7 = Ship's z_lo Bit 0 = Ship's x_sign Ths ship's y-coordinate is calculated in the has1 routine from the size of its targetable area. Ships of type 0 are not shown. Note that ship numbers are for the ship hanger blueprints at XX21 in the docked code, rather than the full set of ships in the flight code. They are: 1 = Cargo canister 2 = Shuttle 3 = Transporter 4 = Cobra Mk III 5 = Python 6 = Viper 7 = Krait 8 = Constrictor
.HATB \ Hanger group for X = 0 \ \ Shuttle (left) and Transporter (right) EQUB 2 \ Ship type in the hanger = 2 = Shuttle EQUB %01010100 \ x_hi = %01010100 = 84, z_hi = 1 -> x = -84 EQUB %00111011 \ z_lo = %00111011 = 59, x_sign = 1 z = +315 EQUB 3 \ Ship type in the hanger = 3 = Transporter EQUB %10000010 \ x_hi = %10000010 = 130, z_hi = 1 -> x = +130 EQUB %10110000 \ z_lo = %10110000 = 176, x_sign = 0 z = +432 EQUB 0 \ No third ship EQUB 0 EQUB 0 \ Hanger group for X = 9 \ \ Three cargo canisters (left, far right and forward, \ right) EQUB 1 \ Ship type in the hanger = 1 = Cargo canister EQUB %01010000 \ x_hi = %01010000 = 80, z_hi = 1 -> x = -80 EQUB %00010001 \ z_lo = %00010001 = 17, x_sign = 1 z = +273 EQUB 1 \ Ship type in the hanger = 1 = Cargo canister EQUB %11010001 \ x_hi = %11010001 = 209, z_hi = 2 -> x = +209 EQUB %00101000 \ z_lo = %00101000 = 40, x_sign = 0 z = +552 EQUB 1 \ Ship type in the hanger = 1 = Cargo canister EQUB %01000000 \ x_hi = %01000000 = 64, z_hi = 1 -> x = +64 EQUB %00000110 \ z_lo = %00000110 = 6, x_sign = 0 z = +262 \ Hanger group for X = 18 \ \ Transporter (right) and Cobra Mk III (left) EQUB 3 \ Ship type in the hanger = 3 = Transporter EQUB %01100000 \ x_hi = %01100000 = 96, z_hi = 1 -> x = +96 EQUB %10010000 \ z_lo = %10010000 = 144, x_sign = 0 z = +400 EQUB 4 \ Ship type in the hanger = 4 = Cobra Mk III EQUB %00010000 \ x_hi = %00010000 = 16, z_hi = 1 -> x = -16 EQUB %11010001 \ z_lo = %11010001 = 209, x_sign = 1 z = +465 EQUB 0 \ No third ship EQUB 0 EQUB 0 \ Hanger group for X = 27 \ \ Viper (right and forward) and Krait (left) EQUB 6 \ Ship type in the hanger = 6 = Viper EQUB %01010001 \ x_hi = %01010001 = 81, z_hi = 2 -> x = +81 EQUB %11111000 \ z_lo = %11111000 = 248, x_sign = 0 z = +760 EQUB 7 \ Ship type in the hanger = 7 = Krait EQUB %01100000 \ x_hi = %01100000 = 96, z_hi = 1 -> x = -96 EQUB %01110101 \ z_lo = %01110101 = 117, x_sign = 1 z = +373 EQUB 0 \ No third ship EQUB 0 EQUB 0
Name: HALL [Show more] Type: Subroutine Category: Ship hanger Summary: Draw the ships in the ship hanger, then draw the hanger
Context: See this subroutine on its own page References: This subroutine is called as follows: * DOENTRY calls HALL

Half the time this will draw one of the four pre-defined ship hanger groups in HATB, and half the time this will draw a solitary Sidewinder, Mamba, Krait or Adder on a random position. In all cases, the ships will be randomly spun around on the ground so they can face in any dirction, and larger ships are drawn higher up off the ground than smaller ships.
.HALL JSR UNWISE \ Call UNWISE to switch the main line-drawing routine \ between EOR and OR logic (in this case, switching it \ to OR logic so that it overwrites anything that's \ on-screen) LDA #0 \ Clear the top part of the screen, draw a white border, JSR TT66 \ and set the current view type in QQ11 to 0 (space \ view) JSR DORND \ Set A and X to random numbers BPL HA7 \ Jump to HA7 if A is positive (50% chance) AND #3 \ Reduce A to a random number in the range 0-3 STA T \ Set X = A * 8 + A ASL A \ = 9 * A ASL A \ ASL A \ so X is a random number, either 0, 9, 18 or 27 ADC T TAX \ The following double loop calls the HAS1 routine three \ times to display three ships on screen. For each call, \ the values passed to HAS1 in XX15+2 to XX15 are taken \ from the HATB table, depending on the value in X, as \ follows: \ \ * If X = 0, pass bytes #0 to #2 of HATB to HAS1 \ then bytes #3 to #5 \ then bytes #6 to #8 \ \ * If X = 9, pass bytes #9 to #11 of HATB to HAS1 \ then bytes #12 to #14 \ then bytes #15 to #17 \ \ * If X = 18, pass bytes #18 to #20 of HATB to HAS1 \ then bytes #21 to #23 \ then bytes #24 to #26 \ \ * If X = 27, pass bytes #27 to #29 of HATB to HAS1 \ then bytes #30 to #32 \ then bytes #33 to #35 \ \ Note that the values are passed in reverse, so for the \ first call, for example, where we pass bytes #0 to #2 \ of HATB to HAS1, we call HAS1 with: \ \ XX15 = HATB+2 \ XX15+1 = HATB+1 \ XX15+2 = HATB LDY #3 \ Set CNT2 = 3 to act as an outer loop counter going STY CNT2 \ from 3 to 1, so the HAL8 loop is run 3 times .HAL8 LDY #2 \ Set Y = 2 to act as an inner loop counter going from \ 2 to 0 .HAL9 LDA HATB,X \ Copy the X-th byte of HATB to the Y-th byte of XX15, STA XX15,Y \ as described above INX \ Increment X to point to the next byte in HATB DEY \ Decrement Y to point to the previous byte in XX15 BPL HAL9 \ Loop back to copy the next byte until we have copied \ three of them (i.e. Y was 3 before the DEY) TXA \ Store X on the stack so we can retrieve it after the PHA \ call to HAS1 (as it contains the index of the next \ byte in HATB JSR HAS1 \ Call HAS1 to draw this ship in the hanger PLA \ Restore the value of X, so X points to the next byte TAX \ in HATB after the three bytes we copied into XX15 DEC CNT2 \ Decrement the outer loop counter in CNT2 BNE HAL8 \ Loop back to HAL8 to do it 3 times, once for each ship \ in the HATB table LDY #128 \ Set Y = 128 to send as byte #2 of the parameter block \ to the OSWORD 248 command below, to tell the I/O \ processor that there are multiple ships in the hanger BNE HA9 \ Jump to HA9 to display the ship hanger (this BNE is \ effectively a JMP as Y is never zero) .HA7 \ If we get here, A is a positive random number in the \ range 0-127 LSR A \ Set XX15+1 = A / 2 (random number 0-63) STA XX15+1 JSR DORND \ Set XX15 = random number 0-255 STA XX15 JSR DORND \ Set XX15+2 = random number 0-7 AND #7 \ STA XX15+2 \ which is either 0 (no ships in the hanger) or one of \ the first 7 ship types in the ship hanger blueprints \ table, i.e. a cargo canister, Shuttle, Transporter, \ Cobra Mk III, Python, Viper or Krait JSR HAS1 \ Call HAS1 to draw this ship in the hanger, with the \ the following properties: \ \ * Random x-coordinate from -63 to +63 \ \ * Randomly chosen cargo canister, Shuttle, \ Transporter, Cobra Mk III, Python, Viper or Krait \ \ * Random z-coordinate from +256 to +639 LDY #0 \ Set Y = 0 to use in the following instruction, to tell \ the hanger-drawing routine that there is just one ship \ in the hanger, so it knows not to draw between the \ ships .HA9 STY YSAV \ Store Y in YSAV to specify whether there are multiple \ ships in the hanger JSR UNWISE \ Call UNWISE to switch the main line-drawing routine \ between EOR and OR logic (in this case, switching it \ back to EOR logic so that we can erase anything we \ draw on-screen) \ Fall through into HANGER to draw the hanger background
Name: HANGER [Show more] Type: Subroutine Category: Ship hanger Summary: Display the ship hanger by sending picture_h and picture_v commands to the I/O processor
Context: See this subroutine on its own page References: No direct references to this subroutine in this source file
.HANGER \ We start by drawing the floor LDX #2 \ We start with a loop using a counter in T that goes \ from 2 to 12, one for each of the 11 horizontal lines \ in the floor, so set the initial value in X .HAL1 STX XSAV \ Store the loop counter in XSAV LDA #130 \ Set A = 130 LDX XSAV \ Retrieve the loop counter from XSAV STX Q \ Set Q = T JSR DVID4 \ Calculate the following: \ \ (P R) = 256 * A / Q \ = 256 * 130 / T \ \ so P = 130 / T, and as the counter T goes from 2 to \ 12, P goes 65, 43, 32 ... 13, 11, 10, with the \ difference between two consecutive numbers getting \ smaller as P gets smaller \ \ We can use this value as a y-coordinate to draw a set \ of horizontal lines, spaced out near the bottom of the \ screen (high value of P, high y-coordinate, lower down \ the screen) and bunching up towards the horizon (low \ value of P, low y-coordinate, higher up the screen) LDA #&9A \ Send command &9A to the I/O processor: JSR tube_write \ \ picture_h(line_count, multiple_ships) \ \ which will draw the specified number of horizontal \ lines as the hanger floor, drawing lines between \ multiple ships if required LDA P \ Send the first parameter to the I/O processor: JSR tube_write \ \ * line_count = P LDA YSAV \ Send the second parameter to the I/O processor: JSR tube_write \ \ * multiple_ships = YSAV LDX XSAV \ Fetch the loop counter from XSAV and increment it INX CPX #13 \ If the loop counter is less than 13 (i.e. T = 2 to 12) BCC HAL1 \ then loop back to HAL1 to draw the next line \ The floor is done, so now we move on to the back wall LDA #16 \ We want to draw 15 vertical lines, one every 16 pixels \ across the screen, with the first at x-coordinate 16, \ so set this in A to act as the x-coordinate of each \ line as we work our way through them from left to \ right, incrementing by 16 for each new line .HAL6 STA XSAV \ Store this value in XSAV, so we can retrieve it later LDA #&9B \ Send command &9B to the I/O processor: JSR tube_write \ \ picture_v(line_count) \ \ which will draw the specified number of vertical \ lines as the back wall of the hanger LDA XSAV \ Send the parameter to the I/O processor: JSR tube_write \ \ * line_count = XSAV LDA XSAV \ Fetch the x-coordinate of the line we just drew from CLC \ XSAV into A, and add 16 so that A contains the ADC #16 \ x-coordinate of the next line to draw BNE HAL6 \ Loop back to HAL6 until we have run through the loop \ 60 times, by which point we are most definitely done RTS \ Return from the subroutine
Name: HAS1 [Show more] Type: Subroutine Category: Ship hanger Summary: Draw a ship in the ship hanger
Context: See this subroutine on its own page References: This subroutine is called as follows: * HALL calls HAS1

The ship's position within the hanger is determined by the arguments and the size of the ship's targetable area, as follows: * The x-coordinate is (x_sign x_hi 0) from the arguments, so the ship can be left of centre or right of centre * The y-coordinate is negative and is lower down the screen for smaller ships, so smaller ships are drawn closer to the ground (because they are) * The z-coordinate is positive, with both z_hi (which is 1 or 2) and z_lo coming from the arguments Arguments: XX15 Bits 0-7 = Ship's z_lo Bit 0 = Ship's x_sign XX15+1 Bits 0-7 = Ship's x_hi Bit 0 = Ship's z_hi (1 if clear, or 2 if set) XX15+2 Non-zero = Ship type to draw 0 = Don't draw anything
.HAS1 JSR ZINF \ Call ZINF to reset the INWK ship workspace and reset \ the orientation vectors, with nosev pointing out of \ the screen, so this puts the ship flat on the \ horizontal deck (the y = 0 plane) with its nose \ pointing towards us LDA XX15 \ Set z_lo = XX15 STA INWK+6 LSR A \ Set the sign bit of x_sign to bit 0 of A ROR INWK+2 LDA XX15+1 \ Set x_hi = XX15+1 STA INWK LSR A \ Set z_hi = 1 + bit 0 of XX15+1 LDA #1 ADC #0 STA INWK+7 LDA #%10000000 \ Set bit 7 of y_sign, so y is negative STA INWK+5 STA RAT2 \ Set RAT2 = %10000000, so the yaw calls in HAL5 below \ are negative LDA #&B \ Set the ship line heap pointer in INWK(35 34) to point STA INWK+34 \ to &0B00 JSR DORND \ We now perform a random number of small angle (3.6 STA XSAV \ degree) rotations to spin the ship on the deck while \ keeping it flat on the deck (a bit like spinning a \ bottle), so we set XSAV to a random number between 0 \ and 255 for the number of small yaw rotations to \ perform, so the ship could be pointing in any \ direction by the time we're done .HAL5 LDX #21 \ Rotate (sidev_x, nosev_x) by a small angle (yaw) LDY #9 JSR MVS5 LDX #23 \ Rotate (sidev_y, nosev_y) by a small angle (yaw) LDY #11 JSR MVS5 LDX #25 \ Rotate (sidev_z, nosev_z) by a small angle (yaw) LDY #13 JSR MVS5 DEC XSAV \ Decrement the yaw counter in XSAV BNE HAL5 \ Loop back to yaw a little more until we have yawed \ by the number of times in XSAV LDY XX15+2 \ Set Y = XX15+2, the ship type of the ship we need to \ draw BEQ HA1 \ If Y = 0, return from the subroutine (as HA1 contains \ an RTS) \ We now work our way through the ship blueprints table \ for the hanger, counting valid blueprints until we \ have found the Y-th valid blueprint (we do this as the \ hanger blueprint table at XX21 is not fully populated, \ so the Y-th ship is not necessarily at position Y) LDX #4 \ We can start looking from ship blueprint 3, because we \ don't show ship 1 (missile) or ship 2 (space station) \ in the hanger. Setting X to 4, which then gets \ incremented to 6, will start us at XX21(5 4), which is \ the address of ship blueprint 3 (escape pod) .hloop INX \ Increment X by 2 to point to the next blueprint in the INX \ table LDA XX21-2,X \ Set XX0(1 0) to the X-th address in the ship blueprint STA XX0 \ address lookup table at XX21, so XX0(1 0) now points LDA XX21-1,X \ to the blueprint for the ship we need to draw STA XX0+1 BEQ hloop \ If the high byte of the blueprint address is 0, then \ the blueprint for this ship is not available, so jump \ back to hloop to try the next ship along in the table DEY \ We have found a valid blueprint, so decrement the ship \ number that we are looking for in Y BNE hloop \ If Y is not yet zero, we still haven't found the Y-th \ valid blueprint, so loop back to hloop to try the next \ ship along in the table LDY #1 \ Set Q = ship byte #1 LDA (XX0),Y STA Q INY \ Set R = ship byte #2 LDA (XX0),Y \ STA R \ so (R Q) contains the ship's targetable area, which is \ a square number JSR LL5 \ Set Q = SQRT(R Q) LDA #100 \ Set y_lo = (100 - Q) / 2 SBC Q \ LSR A \ so the bigger the ship's targetable area, the smaller STA INWK+3 \ the magnitude of the y-coordinate, so because we set \ y_sign to be negative above, this means smaller ships \ are drawn lower down, i.e. closer to the ground, while \ larger ships are drawn higher up, as you would expect JSR TIDY \ Call TIDY to tidy up the orientation vectors, to \ prevent the ship from getting elongated and out of \ shape due to the imprecise nature of trigonometry \ in assembly language JMP LL9 \ Jump to LL9 to display the ship and return from the \ subroutine using a tail call .HA1 RTS \ Return from the subroutine
Name: UNWISE [Show more] Type: Subroutine Category: Ship hanger Summary: Switch the main line-drawing routine between EOR and OR logic by sending a draw_mode command to the I/O processor
Context: See this subroutine on its own page References: This subroutine is called as follows: * HALL calls UNWISE
.UNWISE LDA #&94 \ Send command &94 to the I/O processor: JMP tube_write \ \ draw_mode() \ \ which will toggle the line drawing mode between EOR \ and OR, and return from the subroutine using a tail \ call
Name: HFS1 [Show more] Type: Subroutine Category: Drawing circles Summary: Draw the launch or hyperspace tunnel
Context: See this subroutine on its own page References: This subroutine is called as follows: * DOENTRY calls HFS1 * HFS2 calls HFS1 * TT110 calls HFS1

The animation gets drawn like this. First, we draw a circle of radius 8 at the centre, and then double the radius, draw another circle, double the radius again and draw a circle, and we keep doing this until the radius is bigger than 160 (which goes beyond the edge of the screen, which is 256 pixels wide, equivalent to a radius of 128). We then repeat this whole process for an initial circle of radius 9, then radius 10, all the way up to radius 15. This has the effect of making the tunnel appear to be racing towards us as we hurtle out into hyperspace or through the space station's docking tunnel. The hyperspace effect is done in a full mode 5 screen, which makes the rings all coloured and zig-zaggy, while the launch screen is in the normal monochrome mode 4 screen.
.HFS1 LDX #X \ Set K3 = #X (the x-coordinate of the centre of the STX K3 \ screen) LDX #Y \ Set K4 = #Y (the y-coordinate of the centre of the STX K4 \ screen) LDX #0 \ Set X = 0 STX XX4 \ Set XX4 = 0, which we will use as a counter for \ drawing eight concentric rings STX K3+1 \ Set the high bytes of K3(1 0) and K4(1 0) to 0 STX K4+1 .HFL5 JSR HFL1 \ Call HFL1 below to draw a set of rings, with each one \ twice the radius of the previous one, until they won't \ fit on-screen INC XX4 \ Increment the counter and fetch it into X LDX XX4 CPX #8 \ If we haven't drawn 8 sets of rings yet, loop back to BNE HFL5 \ HFL5 to draw the next ring RTS \ Return from the subroutine .HFL1 LDA XX4 \ Set K to the ring number in XX4 (0-7) + 8, so K has AND #7 \ a value of 8 to 15, which we will use as the starting CLC \ radius for our next set of rings ADC #8 STA K .HFL2 LDA #1 \ Set LSP = 1 to reset the ball line heap STA LSP JSR CIRCLE2 \ Call CIRCLE2 to draw a circle with the centre at \ (K3(1 0), K4(1 0)) and radius K ASL K \ Double the radius in K BCS HF8 \ If the radius had a 1 in bit 7 before the above shift, \ then doubling K will means the circle will no longer \ fit on the screen (which is width 256), so jump to \ HF8 to stop drawing circles LDA K \ If the radius in K <= 160, loop back to HFL2 to draw CMP #160 \ another one BCC HFL2 .HF8 RTS \ Return from the subroutine
Name: SQUA [Show more] Type: Subroutine Category: Maths (Arithmetic) Summary: Clear bit 7 of A and calculate (A P) = A * A
Context: See this subroutine on its own page References: This subroutine is called as follows: * NORM calls SQUA

Do the following multiplication of unsigned 8-bit numbers, after first clearing bit 7 of A: (A P) = A * A
.SQUA AND #%01111111 \ Clear bit 7 of A and fall through into SQUA2 to set \ (A P) = A * A
Name: SQUA2 [Show more] Type: Subroutine Category: Maths (Arithmetic) Summary: Calculate (A P) = A * A
Context: See this subroutine on its own page References: This subroutine is called as follows: * HITCH calls SQUA2 * MAS3 calls SQUA2 * SUN (Part 1 of 4) calls SQUA2 * SUN (Part 3 of 4) calls SQUA2 * TT111 calls SQUA2 * cour_count calls SQUA2

Do the following multiplication of unsigned 8-bit numbers: (A P) = A * A
.SQUA2 STA P \ Copy A into P and X TAX BNE MU11 \ If X = 0 fall through into MU1 to return a 0, \ otherwise jump to MU11 to return P * X
Name: MU1 [Show more] Type: Subroutine Category: Maths (Arithmetic) Summary: Copy X into P and A, and clear the C flag
Context: See this subroutine on its own page References: This subroutine is called as follows: * MULTU calls MU1

Used to return a 0 result quickly from MULTU below.
.MU1 CLC \ Clear the C flag STX P \ Copy X into P and A TXA RTS \ Return from the subroutine
Name: MULTU [Show more] Type: Subroutine Category: Maths (Arithmetic) Summary: Calculate (A P) = P * Q
Context: See this subroutine on its own page References: This subroutine is called as follows: * GCASH calls MULTU * MLU2 calls MULTU * PLS3 calls MULTU * TT210 calls MULTU * TT24 calls MULTU

Do the following multiplication of unsigned 8-bit numbers: (A P) = P * Q
.MULTU LDX Q \ Set X = Q BEQ MU1 \ If X = Q = 0, jump to MU1 to copy X into P and A, \ clear the C flag and return from the subroutine using \ a tail call \ Otherwise fall through into MU11 to set (A P) = P * X
Name: MU11 [Show more] Type: Subroutine Category: Maths (Arithmetic) Summary: Calculate (A P) = P * X Deep dive: Shift-and-add multiplication
Context: See this subroutine on its own page References: This subroutine is called as follows: * SQUA2 calls MU11

Do the following multiplication of two unsigned 8-bit numbers: (A P) = P * X This uses the same shift-and-add approach as MULT1, but it's simpler as we are dealing with unsigned numbers in P and X. See the deep dive on "Shift-and-add multiplication" for a discussion of how this algorithm works.
.MU11 DEX \ Set T = X - 1 STX T \ \ We subtract 1 as the C flag will be set when we want \ to do an addition in the loop below LDA #0 \ Set A = 0 so we can start building the answer in A LDX #8 \ Set up a counter in X to count the 8 bits in P LSR P \ Set P = P >> 1 \ and C flag = bit 0 of P \ We are now going to work our way through the bits of \ P, and do a shift-add for any bits that are set, \ keeping the running total in A. We just did the first \ shift right, so we now need to do the first add and \ loop through the other bits in P .MUL6 BCC P%+4 \ If C (i.e. the next bit from P) is set, do the ADC T \ addition for this bit of P: \ \ A = A + T + C \ = A + X - 1 + 1 \ = A + X ROR A \ Shift A right to catch the next digit of our result, \ which the next ROR sticks into the left end of P while \ also extracting the next bit of P ROR P \ Add the overspill from shifting A to the right onto \ the start of P, and shift P right to fetch the next \ bit for the calculation into the C flag DEX \ Decrement the loop counter BNE MUL6 \ Loop back for the next bit until P has been rotated \ all the way RTS \ Return from the subroutine
Name: FMLTU2 [Show more] Type: Subroutine Category: Maths (Arithmetic) Summary: Calculate A = K * sin(A) Deep dive: The sine, cosine and arctan tables
Context: See this subroutine on its own page References: This subroutine is called as follows: * CIRCLE2 calls FMLTU2

Calculate the following: A = K * sin(A) Because this routine uses the sine lookup table SNE, we can also call this routine to calculate cosine multiplication. To calculate the following: A = K * cos(B) call this routine with B + 16 in the accumulator, as sin(B + 16) = cos(B).
.FMLTU2 AND #%00011111 \ Restrict A to bits 0-5 (so it's in the range 0-31) TAX \ Set Q = sin(A) * 256 LDA SNE,X STA Q LDA K \ Set A to the radius in K \ Fall through into FMLTU to do the following: \ \ (A ?) = A * Q \ = K * sin(A) * 256 \ \ which is equivalent to: \ \ A = K * sin(A)
Name: FMLTU [Show more] Type: Subroutine Category: Maths (Arithmetic) Summary: Calculate A = A * Q / 256
Context: See this subroutine on its own page References: This subroutine is called as follows: * DOEXP calls FMLTU * LL51 calls FMLTU * LL9 (Part 5 of 12) calls FMLTU * MVEIT_FLIGHT (Part 3 of 6) calls FMLTU * PLS22 calls FMLTU

Do the following multiplication of two unsigned 8-bit numbers, returning only the high byte of the result: (A ?) = A * Q or, to put it another way: A = A * Q / 256
.FMLTU EOR #%11111111 \ Flip the bits in A, set the C flag and rotate right, SEC \ so the C flag now contains bit 0 of A inverted, and P ROR A \ contains A inverted and shifted right by one, with bit STA P \ 7 set to a 1. We can now use P as our source of bits \ to shift right, just as in MU11, just with the logic \ reversed LDA #0 \ Set A = 0 so we can start building the answer in A .MUL3 BCS MU7 \ If C (i.e. the next bit from P) is set, do not do the \ addition for this bit of P, and instead skip to MU7 \ to just do the shifts ADC Q \ Do the addition for this bit of P: \ \ A = A + Q + C \ = A + Q ROR A \ Shift A right to catch the next digit of our result. \ If we were interested in the low byte of the result we \ would want to save the bit that falls off the end, but \ we aren't, so we can ignore it LSR P \ Shift P right to fetch the next bit for the \ calculation into the C flag BNE MUL3 \ Loop back to MUL3 if P still contains some set bits \ (so we loop through the bits of P until we get to the \ 1 we inserted before the loop, and then we stop) RTS \ Return from the subroutine .MU7 LSR A \ Shift A right to catch the next digit of our result, \ pushing a 0 into bit 7 as we aren't adding anything \ here (we can't use a ROR here as the C flag is set, so \ a ROR would push a 1 into bit 7) LSR P \ Fetch the next bit from P into the C flag BNE MUL3 \ Loop back to MUL3 if P still contains some set bits \ (so we loop through the bits of P until we get to the \ 1 we inserted before the loop, and then we stop) RTS \ Return from the subroutine
Name: MULT1 [Show more] Type: Subroutine Category: Maths (Arithmetic) Summary: Calculate (A P) = Q * A Deep dive: Shift-and-add multiplication
Context: See this subroutine on its own page References: This subroutine is called as follows: * MAD calls MULT1 * MULT12 calls MULT1 * MUT1 calls MULT1

Do the following multiplication of two 8-bit sign-magnitude numbers: (A P) = Q * A
.MULT1 TAX \ Store A in X AND #%01111111 \ Set P = |A| >> 1 LSR A \ and C flag = bit 0 of A STA P TXA \ Restore argument A EOR Q \ Set bit 7 of A and T if Q and A have different signs, AND #%10000000 \ clear bit 7 if they have the same signs, 0 all other STA T \ bits, i.e. T contains the sign bit of Q * A LDA Q \ Set A = |Q| AND #%01111111 BEQ mu10 \ If |Q| = 0 jump to mu10 (with A set to 0) TAX \ Set T1 = |Q| - 1 DEX \ STX T1 \ We subtract 1 as the C flag will be set when we want \ to do an addition in the loop below \ We are now going to work our way through the bits of \ P, and do a shift-add for any bits that are set, \ keeping the running total in A. We already set up \ the first shift at the start of this routine, as \ P = |A| >> 1 and C = bit 0 of A, so we now need to set \ up a loop to sift through the other 7 bits in P LDA #0 \ Set A = 0 so we can start building the answer in A LDX #7 \ Set up a counter in X to count the 7 bits remaining \ in P .MUL4 BCC P%+4 \ If C (i.e. the next bit from P) is set, do the ADC T1 \ addition for this bit of P: \ \ A = A + T1 + C \ = A + |Q| - 1 + 1 \ = A + |Q| ROR A \ As mentioned above, this ROR shifts A right and \ catches bit 0 in C - giving another digit for our \ result - and the next ROR sticks that bit into the \ left end of P while also extracting the next bit of P \ for the next addition ROR P \ Add the overspill from shifting A to the right onto \ the start of P, and shift P right to fetch the next \ bit for the calculation DEX \ Decrement the loop counter BNE MUL4 \ Loop back for the next bit until P has been rotated \ all the way LSR A \ Rotate (A P) once more to get the final result, as ROR P \ we only pushed 7 bits through the above process ORA T \ Set the sign bit of the result that we stored in T RTS \ Return from the subroutine .mu10 STA P \ If we get here, the result is 0 and A = 0, so set \ P = 0 so (A P) = 0 RTS \ Return from the subroutine
Name: MULT12 [Show more] Type: Subroutine Category: Maths (Arithmetic) Summary: Calculate (S R) = Q * A
Context: See this subroutine on its own page References: This subroutine is called as follows: * TAS3 calls MULT12 * TAS4 calls MULT12 * TIDY calls MULT12 * TIS3 calls MULT12

Calculate: (S R) = Q * A
.MULT12 JSR MULT1 \ Set (A P) = Q * A STA S \ Set (S R) = (A P) LDA P STA R RTS \ Return from the subroutine
Name: MAD [Show more] Type: Subroutine Category: Maths (Arithmetic) Summary: Calculate (A X) = Q * A + (S R)
Context: See this subroutine on its own page References: This subroutine is called as follows: * MVS4 calls MAD * STARS2 calls MAD * TAS3 calls MAD * TAS4 calls MAD * TIS1 calls MAD * TIS3 calls MAD

Calculate (A X) = Q * A + (S R)
.MAD JSR MULT1 \ Call MULT1 to set (A P) = Q * A \ Fall through into ADD to do: \ \ (A X) = (A P) + (S R) \ = Q * A + (S R)
Name: ADD [Show more] Type: Subroutine Category: Maths (Arithmetic) Summary: Calculate (A X) = (A P) + (S R) Deep dive: Adding sign-magnitude numbers
Context: See this subroutine on its own page References: This subroutine is called as follows: * DIALS (Part 2 of 4) calls ADD * MVS5 calls ADD * PIX1 calls ADD * PLS22 calls ADD * STARS1 calls ADD * STARS2 calls ADD * STARS6 calls ADD * WARP calls ADD

Add two 16-bit sign-magnitude numbers together, calculating: (A X) = (A P) + (S R)
.ADD STA T1 \ Store argument A in T1 AND #%10000000 \ Extract the sign (bit 7) of A and store it in T STA T EOR S \ EOR bit 7 of A with S. If they have different bit 7s BMI MU8 \ (i.e. they have different signs) then bit 7 in the \ EOR result will be 1, which means the EOR result is \ negative. So the AND, EOR and BMI together mean "jump \ to MU8 if A and S have different signs" \ If we reach here, then A and S have the same sign, so \ we can add them and set the sign to get the result LDA R \ Add the least significant bytes together into X: CLC \ ADC P \ X = P + R TAX LDA S \ Add the most significant bytes together into A. We ADC T1 \ stored the original argument A in T1 earlier, so we \ can do this with: \ \ A = A + S + C \ = T1 + S + C ORA T \ If argument A was negative (and therefore S was also \ negative) then make sure result A is negative by \ OR-ing the result with the sign bit from argument A \ (which we stored in T) RTS \ Return from the subroutine .MU8 \ If we reach here, then A and S have different signs, \ so we can subtract their absolute values and set the \ sign to get the result LDA S \ Clear the sign (bit 7) in S and store the result in AND #%01111111 \ U, so U now contains |S| STA U LDA P \ Subtract the least significant bytes into X: SEC \ SBC R \ X = P - R TAX LDA T1 \ Restore the A of the argument (A P) from T1 and AND #%01111111 \ clear the sign (bit 7), so A now contains |A| SBC U \ Set A = |A| - |S| \ At this point we have |A P| - |S R| in (A X), so we \ need to check whether the subtraction above was the \ the right way round (i.e. that we subtracted the \ smaller absolute value from the larger absolute \ value) BCS MU9 \ If |A| >= |S|, our subtraction was the right way \ round, so jump to MU9 to set the sign \ If we get here, then |A| < |S|, so our subtraction \ above was the wrong way round (we actually subtracted \ the larger absolute value from the smaller absolute \ value). So let's subtract the result we have in (A X) \ from zero, so that the subtraction is the right way \ round STA U \ Store A in U TXA \ Set X = 0 - X using two's complement (to negate a EOR #&FF \ number in two's complement, you can invert the bits ADC #1 \ and add one - and we know the C flag is clear as we TAX \ didn't take the BCS branch above, so the ADC will do \ the correct addition) LDA #0 \ Set A = 0 - A, which we can do this time using a SBC U \ a subtraction with the C flag clear ORA #%10000000 \ We now set the sign bit of A, so that the EOR on the \ next line will give the result the opposite sign to \ argument A (as T contains the sign bit of argument \ A). This is the same as giving the result the same \ sign as argument S (as A and S have different signs), \ which is what we want, as S has the larger absolute \ value .MU9 EOR T \ If we get here from the BCS above, then |A| >= |S|, \ so we want to give the result the same sign as \ argument A, so if argument A was negative, we flip \ the sign of the result with an EOR (to make it \ negative) RTS \ Return from the subroutine
Name: TIS1 [Show more] Type: Subroutine Category: Maths (Arithmetic) Summary: Calculate (A ?) = (-X * A + (S R)) / 96 Deep dive: Shift-and-subtract division
Context: See this subroutine on its own page References: This subroutine is called as follows: * TIDY calls TIS1

Calculate the following expression between sign-magnitude numbers, ignoring the low byte of the result: (A ?) = (-X * A + (S R)) / 96 This uses the same shift-and-subtract algorithm as TIS2, just with the quotient A hard-coded to 96. Returns: Q Gets set to the value of argument X
.TIS1 STX Q \ Set Q = X EOR #%10000000 \ Flip the sign bit in A JSR MAD \ Set (A X) = Q * A + (S R) \ = X * -A + (S R) .DVID96 TAX \ Set T to the sign bit of the result AND #%10000000 STA T TXA \ Set A to the high byte of the result with the sign bit AND #%01111111 \ cleared, so (A ?) = |X * A + (S R)| \ The following is identical to TIS2, except Q is \ hard-coded to 96, so this does A = A / 96 LDX #254 \ Set T1 to have bits 1-7 set, so we can rotate through STX T1 \ 7 loop iterations, getting a 1 each time, and then \ getting a 0 on the 8th iteration... and we can also \ use T1 to catch our result bits into bit 0 each time .DVL3 ASL A \ Shift A to the left CMP #96 \ If A < 96 skip the following subtraction BCC DV4 SBC #96 \ Set A = A - 96 \ \ Going into this subtraction we know the C flag is \ set as we passed through the BCC above, and we also \ know that A >= 96, so the C flag will still be set \ once we are done .DV4 ROL T1 \ Rotate the counter in T1 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 DVL3 \ If we still have set bits in T1, loop back to DVL3 to \ do the next iteration of 7 LDA T1 \ Fetch the result from T1 into A ORA T \ Give A the sign of the result that we stored above RTS \ Return from the subroutine
Name: DVID4 [Show more] Type: Subroutine Category: Maths (Arithmetic) Summary: Calculate (P R) = 256 * A / Q Deep dive: Shift-and-subtract division
Context: See this subroutine on its own page References: This subroutine is called as follows: * DOEXP calls DVID4 * DV41 calls DVID4 * HANGER calls DVID4 * SPS2 calls DVID4

Calculate the following division and remainder: P = A / Q R = remainder as a fraction of Q, where 1.0 = 255 Another way of saying the above is this: (P R) = 256 * A / Q This uses the same shift-and-subtract algorithm as TIS2, but this time we keep the remainder. Returns: C flag The C flag is cleared
.DVID4 LDX #8 \ Set a counter in X to count the 8 bits in A ASL A \ Shift A left and store in P (we will build the result STA P \ in P) LDA #0 \ Set A = 0 for us to build a remainder .DVL4 ROL A \ Shift A to the left BCS DV8 \ If the C flag is set (i.e. bit 7 of A was set) then \ skip straight to the subtraction CMP Q \ If A < Q skip the following subtraction BCC DV5 .DV8 SBC Q \ A >= Q, so set A = A - Q SEC \ Set the C flag, so that P gets a 1 shifted into bit 0 .DV5 ROL P \ Shift P to the left, pulling the C flag into bit 0 DEX \ Decrement the loop counter BNE DVL4 \ Loop back for the next bit until we have done all 8 \ bits of P JMP LL28+4 \ Jump to LL28+4 to convert the remainder in A into an \ integer representation of the fractional value A / Q, \ in R, where 1.0 = 255. LL28+4 always returns with the \ C flag cleared, and we return from the subroutine \ using a tail call
Name: PDESC [Show more] Type: Subroutine Category: Text Summary: Print the system's extended description or a mission 1 directive Deep dive: Extended system descriptions Extended text tokens
Context: See this subroutine on its own page References: This subroutine is called as follows: * TT25 calls PDESC

This prints a specific system's extended description. This is called the "pink volcanoes string" in a comment in the original source, and the "goat soup" recipe by Ian Bell on his website (where he also refers to the species string as the "pink felines" string). For some special systems, when you are docked at them, the procedurally generated extended description is overridden and a text token from the RUTOK table is shown instead. If mission 1 is in progress, then a number of systems along the route of that mission's story will show custom mission-related directives in place of that system's normal "goat soup" phrase. Arguments: ZZ The system number (0-255)
.PDESC LDA QQ8 \ If either byte in QQ18(1 0) is non-zero, meaning that ORA QQ8+1 \ the distance from the current system to the selected BNE PD1 \ is non-zero, jump to PD1 to show the standard "goat \ soup" description \ If we get here, then the current system is the same as \ the selected system and we are docked, so now to check \ whether there is a special override token for this \ system LDY #NRU% \ Set Y as a loop counter as we work our way through the \ system numbers in RUPLA, starting at NRU% (which is \ the number of entries in RUPLA, 26) and working our \ way down to 1 .PDL1 LDA RUPLA-1,Y \ Fetch the Y-th byte from RUPLA-1 into A (we use \ RUPLA-1 because Y is looping from 26 to 1 CMP ZZ \ If A doesn't match the system whose description we BNE PD2 \ are printing (in ZZ), junp to PD2 to keep looping \ through the system numbers in RUPLA \ If we get here we have found a match for this system \ number in RUPLA LDA RUGAL-1,Y \ Fetch the Y-th byte from RUGAL-1 into A AND #%01111111 \ Extract bits 0-6 of A CMP GCNT \ If the result does not equal the current galaxy BNE PD2 \ number, jump to PD2 to keep looping through the system \ numbers in RUPLA LDA RUGAL-1,Y \ Fetch the Y-th byte from RUGAL-1 into A, once again BMI PD3 \ If bit 7 is set, jump to PD3 to print the extended \ token in A from the second table in RUTOK LDA TP \ Fetch bit 0 of TP into the C flag, and skip to PD1 if LSR A \ it is clear (i.e. if mission 1 is not in progress) to BCC PD1 \ print the "goat soup" extended description \ If we get here then mission 1 is in progress, so we \ print out the corresponding token from RUTOK JSR MT14 \ Call MT14 to switch to justified text LDA #1 \ Set A = 1 so that extended token 1 (an empty string) \ gets printed below instead of token 176, followed by \ the Y-th token in RUTOK EQUB &2C \ Skip the next instruction by turning it into \ &2C &A9 &B0, or BIT &B0A9, which does nothing apart \ from affect the flags .PD3 LDA #176 \ Print extended token 176 ("{lower case}{justify} JSR DETOK2 \ {single cap}") TYA \ Print the extended token in Y from the second table JSR DETOK3 \ in RUTOK LDA #177 \ Set A = 177 so when we jump to PD4 in the next \ instruction, we print token 177 (".{cr}{left align}") BNE PD4 \ Jump to PD4 to print the extended token in A and \ return from the subroutine using a tail call .PD2 DEY \ Decrement the byte counter in Y BNE PDL1 \ Loop back to check the next byte in RUPLA until we \ either find a match for the system in ZZ, or we fall \ through into the "goat soup" extended description \ routine .PD1 \ We now print the "goat soup" extended description LDX #3 \ We now want to seed the random number generator with \ the s1 and s2 16-bit seeds from the current system, so \ we get the same extended description for each system \ every time we call PDESC, so set a counter in X for \ copying 4 bytes { .PDL1 \ This label is a duplicate of the label above (which is \ why we need to surround it with braces, as BeebAsm \ doesn't allow us to redefine labels, unlike BBC BASIC) LDA QQ15+2,X \ Copy QQ15+2 to QQ15+5 (s1 and s2) to RAND to RAND+3 STA RAND,X DEX \ Decrement the loop counter BPL PDL1 \ Loop back to PDL1 until we have copied all LDA #5 \ Set A = 5, so we print extended token 5 in the next \ instruction ("{lower case}{justify}{single cap}[86-90] \ IS [140-144].{cr}{left align}" } .PD4 JMP DETOK \ Print the extended token given in A, and return from \ the subroutine using a tail call
Name: BRIEF2 [Show more] Type: Subroutine Category: Missions Summary: Start mission 2
Context: See this subroutine on its own page References: This subroutine is called as follows: * DOENTRY calls BRIEF2
.BRIEF2 LDA TP \ Set bit 2 of TP to indicate mission 2 is in progress ORA #%00000100 \ but plans have not yet been picked up STA TP LDA #11 \ Set A = 11 so the call to BRP prints extended token 11 \ (the initial contact at the start of mission 2, asking \ us to head for Ceerdi for a mission briefing) \ Fall through into BRP to print the extended token in A \ and show the Status Mode screen
Name: BRP [Show more] Type: Subroutine Category: Missions Summary: Print an extended token and show the Status Mode screen
Context: See this subroutine on its own page References: This subroutine is called as follows: * BRIEF3 calls BRP * DEBRIEF calls BRP * DEBRIEF2 calls BRP
.BRP JSR DETOK \ Print the extended token in A JMP BAY \ Jump to BAY to go to the docking bay (i.e. show the \ Status Mode screen) and return from the subroutine \ using a tail call
Name: BRIEF3 [Show more] Type: Subroutine Category: Missions Summary: Receive the briefing and plans for mission 2
Context: See this subroutine on its own page References: This subroutine is called as follows: * DOENTRY calls BRIEF3
.BRIEF3 LDA TP \ Set bits 1 and 3 of TP to indicate that mission 1 is AND #%11110000 \ complete, and mission 2 is in progress and the plans ORA #%00001010 \ have been picked up STA TP LDA #222 \ Set A = 222 so the call to BRP prints extended token \ 222 (the briefing for mission 2 where we pick up the \ plans we need to take to Birera) BNE BRP \ Jump to BRP to print the extended token in A and show \ the Status Mode screen), returning from the subroutine \ using a tail call (this BNE is effectively a JMP as A \ is never zero)
Name: DEBRIEF2 [Show more] Type: Subroutine Category: Missions Summary: Finish mission 2
Context: See this subroutine on its own page References: This subroutine is called as follows: * DOENTRY calls DEBRIEF2
.DEBRIEF2 LDA TP \ Set bit 2 of TP to indicate mission 2 is complete (so ORA #%00000100 \ both bits 2 and 3 are now set) STA TP LDA ENGY \ If we already have an energy unit fitted (i.e. ENGY is BNE rew_notgot \ non-zero), jump to rew_notgot to skip the following \ instruction DEC new_hold \ We're about to be given a special navy energy unit, \ which doesn't take up space in the hold, so decrement \ new_hold to reclaim the space for our old energy unit .rew_notgot LDA #2 \ Set ENGY to 2 so our energy banks recharge at twice STA ENGY \ the speed, as our mission reward is a special navy \ energy unit INC TALLY+1 \ Award 256 kill points for completing the mission LDA #223 \ Set A = 223 so the call to BRP prints extended token \ 223 (the thank you message at the end of mission 2) BNE BRP \ Jump to BRP to print the extended token in A and show \ the Status Mode screen), returning from the subroutine \ using a tail call (this BNE is effectively a JMP as A \ is never zero)
Name: DEBRIEF [Show more] Type: Subroutine Category: Missions Summary: Finish mission 1
Context: See this subroutine on its own page References: This subroutine is called as follows: * DOENTRY calls DEBRIEF * BRIEF calls entry point BRPS

Other entry points: BRPS Print the extended token in A, show the Status Mode screen and return from the subroutine
.DEBRIEF LSR TP \ Clear bit 0 of TP to indicate that mission 1 is no ASL TP \ longer in progress, as we have completed it INC TALLY+1 \ Award 256 kill points for completing the mission LDX #LO(50000) \ Increase our cash reserves by the generous mission LDY #HI(50000) \ reward of 5,000 CR JSR MCASH LDA #15 \ Set A = 15 so the call to BRP prints extended token 15 \ (the thank you message at the end of mission 1) .BRPS BNE BRP \ Jump to BRP to print the extended token in A and show \ the Status Mode screen, returning from the subroutine \ using a tail call (this BNE is effectively a JMP as A \ is never zero)
Name: BRIEF [Show more] Type: Subroutine Category: Missions Summary: Start mission 1 and show the mission briefing
Context: See this subroutine on its own page References: This subroutine is called as follows: * DOENTRY calls BRIEF

This routine does the following: * Clear the screen * Display "INCOMING MESSAGE" in the middle of the screen * Wait for 2 seconds * Clear the screen * Show the Constrictor rolling and pitching in the middle of the screen * Do this for 64 loop iterations * Move the ship away from us and up until it's near the top of the screen * Show the mission 1 briefing in extended token 10 The mission briefing ends with a "{display ship, wait for key press}" token, which calls the PAUSE routine. This continues to display the rotating ship, waiting until a key is pressed, and then removes the ship from the screen.
.BRIEF LSR TP \ Set bit 0 of TP to indicate that mission 1 is now in SEC \ progress ROL TP JSR BRIS \ Call BRIS to clear the screen, display "INCOMING \ MESSAGE" and wait for 2 seconds JSR ZINF \ Call ZINF to reset the INWK ship workspace LDA #CON \ Set the ship type in TYPE to the Constrictor STA TYPE JSR NWSHP \ Add a new Constrictor to the local bubble (in this \ case, the briefing screen) LDA #1 \ Move the text cursor to column 1 STA XC STA INWK+7 \ Set z_hi = 1, the distance at which we show the \ rotating ship JSR TT66 \ Clear the top part of the screen, draw a white border, \ and set the current view type in QQ11 to 1 LDA #64 \ Set the main loop counter to 64, so the ship rotates STA MCNT \ for 64 iterations through MVEIT .BRL1 LDX #%01111111 \ Set the ship's roll counter to a positive roll that STX INWK+29 \ doesn't dampen STX INWK+30 \ Set the ship's pitch counter to a positive pitch that \ doesn't dampen JSR LL9 \ Draw the ship on screen JSR MVEIT \ Call MVEIT to rotate the ship in space DEC MCNT \ Decrease the counter in MCNT BNE BRL1 \ Loop back to keep moving the ship until we have done \ all 64 iterations .BRL2 LSR INWK \ Halve x_lo so the Constrictor moves towards the centre INC INWK+6 \ Increment z_lo so the Constrictor moves away from us BEQ BR2 \ If z_lo = 0 (i.e. it just went past 255), jump to BR2 \ to show the briefing INC INWK+6 \ Increment z_lo so the Constrictor moves a bit further \ away from us BEQ BR2 \ If z_lo = 0 (i.e. it just went past 255), jump out of \ the loop to BR2 to stop moving the ship up the screen \ and show the briefing LDX INWK+3 \ Set X = y_lo + 1 INX CPX #112 \ If X < 112 then skip the next instruction BCC P%+4 LDX #112 \ X is bigger than 112, so set X = 112 so that X has a \ maximum value of 112 STX INWK+3 \ Set y_lo = X \ = y_lo + 1 \ \ so the ship moves up the screen (as space coordinates \ have the y-axis going up) JSR LL9 \ Draw the ship on screen JSR MVEIT \ Call MVEIT to move and rotate the ship in space JMP BRL2 \ Loop back to keep moving the ship up the screen and \ away from us .BR2 INC INWK+7 \ Increment z_hi, to keep the ship at the same distance \ as we just incremented z_lo past 255 LDA #10 \ Set A = 10 so the call to BRP prints extended token 10 \ (the briefing for mission 1 where we find out all \ about the stolen Constrictor) BNE BRPS \ Jump to BRP via BRPS to print the extended token in A \ and show the Status Mode screen), returning from the \ subroutine using a tail call (this BNE is effectively \ a JMP as A is never zero)
Name: BRIS [Show more] Type: Subroutine Category: Missions Summary: Clear the screen, display "INCOMING MESSAGE" and wait for 2 seconds
Context: See this subroutine on its own page References: This subroutine is called as follows: * BRIEF calls BRIS * JMTB calls BRIS
.BRIS LDA #216 \ Print extended token 216 ("{clear screen}{tab 6}{move JSR DETOK \ to row 10, white, lower case}{white}{all caps}INCOMING \ MESSAGE" LDY #100 \ Delay for 100 vertical syncs (100/50 = 2 seconds) and JMP DELAY \ return from the subroutine using a tail call
Name: PAUSE [Show more] Type: Subroutine Category: Keyboard Summary: Display a rotating ship, waiting until a key is pressed, then remove the ship from the screen
Context: See this subroutine on its own page References: This subroutine is called as follows: * JMTB calls PAUSE
.PAUSE JSR PAS1 \ Call PAS1 to display the rotating ship at space \ coordinates (0, 112, 256) and scan the keyboard, \ returning the internal key number in X (or 0 for no \ key press) BNE PAUSE \ If a key was already being held down when we entered \ this routine, keep looping back up to PAUSE, until \ the key is released .PAL1 JSR PAS1 \ Call PAS1 to display the rotating ship at space \ coordinates (0, 112, 256) and scan the keyboard, \ returning the internal key number in X (or 0 for no \ key press) BEQ PAL1 \ Keep looping up to PAL1 until a key is pressed LDA #0 \ Set the ship's AI flag to 0 (no AI) so it doesn't get STA INWK+31 \ any ideas of its pwn LDA #1 \ Clear the top part of the screen, draw a white border, JSR TT66 \ and set the current view type in QQ11 to 1 JSR LL9 \ Draw the ship on screen to remove it \ Fall through into MT23 to move to row 10, switch to \ white text, and switch to lower case when printing \ extended tokens
Name: MT23 [Show more] Type: Subroutine Category: Text Summary: Move to row 10, switch to white text, and switch to lower case when printing extended tokens Deep dive: Extended text tokens
Context: See this subroutine on its own page References: This subroutine is called as follows: * JMTB calls MT23
.MT23 LDA #10 \ Set A = 10, so when we fall through into MT29, the \ text cursor gets moved to row 10 EQUB &2C \ Skip the next instruction by turning it into \ &2C &A9 &06, or BIT &06A9, which does nothing apart \ from affect the flags \ Fall through into MT29 to move to the row in A, switch \ to white text, and switch to lower case
Name: MT29 [Show more] Type: Subroutine Category: Text Summary: Move to row 6, switch to white text, and switch to lower case when printing extended tokens Deep dive: Extended text tokens
Context: See this subroutine on its own page References: This subroutine is called as follows: * JMTB calls MT29

This routine sets the following: * YC = 6 (move to row 6) Then it calls WHITETEXT to switch to white text, before jumping to MT13 to switch to lower case when printing extended tokens.
.MT29 LDA #6 \ Move the text cursor to row 6 STA YC JMP MT13 \ Jump to MT13 to set bit 7 of DTW6 and bit 5 of DTW1, \ returning from the subroutine using a tail call
Name: PAS1 [Show more] Type: Subroutine Category: Keyboard Summary: Display a rotating ship at space coordinates (0, 112, 256) and scan the keyboard
Context: See this subroutine on its own page References: This subroutine is called as follows: * PAUSE calls PAS1

Returns: X If a key is being pressed, X contains the internal key number, otherwise it contains 0 A Contains the same as X
.PAS1 LDA #112 \ Set y_lo = 112 STA INWK+3 LDA #0 \ Set x_lo = 0 STA INWK STA INWK+6 \ Set z_lo = 0 LDA #2 \ Set z_hi = 1, so (z_hi z_lo) = 256 STA INWK+7 JSR LL9 \ Draw the ship on screen JSR MVEIT \ Call MVEIT to move and rotate the ship in space JMP RDKEY \ Scan the keyboard for a key press and return the \ internal key number in X (or 0 for no key press), \ returning from the subroutine using a tail call
Name: PAUSE2 [Show more] Type: Subroutine Category: Keyboard Summary: Wait until a key is pressed, ignoring any existing key press
Context: See this subroutine on its own page References: This subroutine is called as follows: * JMTB calls PAUSE2

Returns: X The internal key number of the key that was pressed
.PAUSE2 JSR RDKEY \ Scan the keyboard for a key press and return the \ internal key number in X (or 0 for no key press) BNE PAUSE2 \ If a key was already being held down when we entered \ this routine, keep looping back up to PAUSE2, until \ the key is released JSR RDKEY \ Any pre-existing key press is now gone, so we can \ start scanning the keyboard again, returning the \ internal key number in X (or 0 for no key press) BEQ PAUSE2 \ Keep looping up to PAUSE2 until a key is pressed RTS \ Return from the subroutine
Name: TT66 [Show more] Type: Subroutine Category: Utility routines Summary: Clear the screen and set the current view type
Context: See this subroutine on its own page References: This subroutine is called as follows: * BRIEF calls TT66 * DEATH calls TT66 * EQSHP calls TT66 * HALL calls TT66 * LOOK1 calls TT66 * MJP calls TT66 * MT9 calls TT66 * PAUSE calls TT66 * STATUS calls TT66 * TITLE calls TT66 * TT167 calls TT66 * TT18 calls TT66 * TT208 calls TT66 * TT213 calls TT66 * TT219 calls TT66 * TT22 calls TT66 * TT23 calls TT66 * TT25 calls TT66 * controls calls TT66 * cour_dock calls TT66 * equip_data calls TT66 * menu calls TT66 * qv calls TT66 * ships_ag calls TT66

Clear the top part of the screen, draw a white border, and set the current view type in QQ11 to A. Arguments: A The type of the new current view (see QQ11 for a list of view types)
.TT66 STA QQ11 \ Set the current view type in QQ11 to A \ Fall through into TTX66 to clear the screen and draw a \ white border
Name: TTX66 [Show more] Type: Subroutine Category: Utility routines Summary: Clear the top part of the screen and draw a white border by sending a clr_scrn command to the I/O processor
Context: See this subroutine on its own page References: This subroutine is called as follows: * CHPR calls TTX66 * HFS2 calls TTX66 * TT18 calls TTX66

Clear the top part of the screen (the space view) and draw a white border along the top and sides.
.TTX66 JSR MT2 \ Switch to Sentence Case when printing extended tokens LDA #%10000000 \ Set bit 7 of QQ17 to switch to Sentence Case STA QQ17 STA DTW2 \ Set bit 7 of DTW2 to indicate we are not currently \ printing a word ASL A \ Set A to 0, as 128 << 1 = %10000000 << 1 = 0 STA DLY \ Set the delay in DLY to 0, to indicate that we are \ no longer showing an in-flight message, so any new \ in-flight messages will be shown instantly STA de \ Clear de, the flag that appends " DESTROYED" to the \ end of the next text token, so that it doesn't JSR write_0346 \ Tell the I/O processor to set its copy of LASCT to 0 LDA #&83 \ Send command &83 to the I/O processor: JSR tube_write \ \ clr_scrn() \ \ to clear the top part of the screen LDX QQ22+1 \ Fetch into X the number that's shown on-screen during \ the hyperspace countdown BEQ BOX \ If the counter is zero then we are not counting down \ to hyperspace, so jump to BOX to skip the next \ instruction JSR ee3 \ Print the 8-bit number in X at text location (0, 1), \ i.e. print the hyperspace countdown in the top-left \ corner .BOX LDY #1 \ Move the text cursor to row 1 STY YC LDA QQ11 \ If this is not a space view, jump to tt66 to skip BNE tt66 \ displaying the view name LDY #11 \ Move the text cursor to row 11 STY XC LDA VIEW \ Load the current view into A: \ \ 0 = front \ 1 = rear \ 2 = left \ 3 = right ORA #&60 \ OR with &60 so we get a value of &60 to &63 (96 to 99) JSR TT27 \ Print recursive token 96 to 99, which will be in the \ range "FRONT" to "RIGHT" JSR TT162 \ Print a space LDA #175 \ Print recursive token 15 ("VIEW ") JSR TT27 .tt66 LDX #0 \ Set QQ17 = 0 to switch to ALL CAPS STX QQ17 STX X1 \ Set (X1, Y1) to (0, 0) STX Y1 DEX \ Set X2 = 255 STX X2 JSR HLOIN \ Draw a horizontal line from (X1, Y1) to (X2, Y1), so \ that's (0, 0) to (255, 0), along the very top of the \ screen LDA #2 \ Set X1 = X2 = 2 STA X1 STA X2 JSR BOS2 \ Call BOS2 below, which will call BOS1 twice, and then \ fall through into BOS2 again, so we effectively do \ BOS1 four times, decrementing X1 and X2 each time \ before calling LOIN, so this whole loop-within-a-loop \ mind-bender ends up drawing these four lines: \ \ (1, 0) to (1, 191) \ (0, 0) to (0, 191) \ (255, 0) to (255, 191) \ (254, 0) to (254, 191) \ \ So that's a 2-pixel wide vertical border along the \ left edge of the upper part of the screen, and a \ 2-pixel wide vertical border along the right edge .BOS2 JSR BOS1 \ Call BOS1 below and then fall through into it, which \ ends up running BOS1 twice. This is all part of the \ loop-the-loop border-drawing mind-bender explained \ above .BOS1 LDA #0 \ Set Y1 = 0 STA Y1 LDA #2*Y-1 \ Set Y2 = 2 * #Y - 1. The constant #Y is 96, the STA Y2 \ y-coordinate of the mid-point of the space view, so \ this sets Y2 to 191, the y-coordinate of the bottom \ pixel row of the space view DEC X1 \ Decrement X1 and X2 DEC X2 JMP LOIN \ Draw a line from (X1, Y1) to (X2, Y2), and return from \ the subroutine using a tail call
Name: DELAY [Show more] Type: Subroutine Category: Utility routines Summary: Wait for a specified time, in 1/50s of a second
Context: See this subroutine on its own page References: This subroutine is called as follows: * BRIS calls DELAY * DKS3 calls DELAY * DOENTRY calls DELAY * GTNMEW calls DELAY * Main game loop (Part 5 of 6) calls DELAY * Main game loop for flight (Part 5 of 6) calls DELAY * cour_dock calls DELAY * dn2 calls DELAY

Wait for the number of vertical syncs given in Y, so this effectively waits for Y/50 of a second (as the vertical sync occurs 50 times a second). Arguments: Y The number of vertical sync events to wait for
.DELAY JSR WSCAN \ Call WSCAN to wait for the vertical sync, so the whole \ screen gets drawn DEY \ Decrement the counter in Y BNE DELAY \ If Y isn't yet at zero, jump back to DELAY to wait \ for another vertical sync RTS \ Return from the subroutine
Name: CLYNS [Show more] Type: Subroutine Category: Utility routines Summary: Clear the bottom three text rows of the mode 4 screen by sending a clr_line command to the I/O processor
Context: See this subroutine on its own page References: This subroutine is called as follows: * EQSHP calls CLYNS * JMTB calls CLYNS * TITLE calls CLYNS * TT102 calls CLYNS * TT219 calls CLYNS * cour_buy calls CLYNS * hm calls CLYNS * menu calls CLYNS * n_buyship calls CLYNS * qv calls CLYNS

Returns: A A is set to 0 Y Y is set to 0
.CLYNS LDA #%11111111 \ Set DTW2 = %11111111 to denote that we are not STA DTW2 \ currently printing a word LDA #20 \ Move the text cursor to row 20, near the bottom of STA YC \ the screen JSR TT67 \ Print a newline, which will move the text cursor down \ a line (to row 21) and back to column 1 LDY #1 \ Move the text cursor to column 1 STY XC DEY \ Set Y = 0, so the subroutine returns with this value LDA #&84 \ Send command &84 to the I/O processor: JMP tube_write \ \ clr_line() \ \ which will clear the bottom three text rows of the top \ part of the screen and return from the subroutine \ using a tail call
Name: WSCAN [Show more] Type: Subroutine Category: Screen mode Summary: Wait for the vertical sync by sending a sync_in command to the I/O processor
Context: See this subroutine on its own page References: This subroutine is called as follows: * DELAY calls WSCAN * DK4 calls WSCAN * DK4_FLIGHT calls WSCAN * TT102 calls WSCAN * check_keys calls WSCAN
.WSCAN LDA #&85 \ Send command &86 to the I/O processor: JSR tube_write \ \ =sync_in() \ \ which will wait until the vertical sync before \ returning control to the parasite JMP tube_read \ Set A to the response from the I/O processor, which \ will be sent when the vertical sync occurs (it doesn't \ matter what the value is), and return from the \ subroutine using a tail call
Save ELTC.bin
PRINT "ELITE C" PRINT "Assembled at ", ~CODE_C% PRINT "Ends at ", ~P% PRINT "Code size is ", ~(P% - CODE_C%) PRINT "Execute at ", ~LOAD% PRINT "Reload at ", ~LOAD_C% PRINT "S.2.ELTC ", ~CODE_C%, " ", ~P%, " ", ~LOAD%, " ", ~LOAD_C% SAVE "3-assembled-output/2.ELTC.bin", CODE_C%, P%, LOAD%