Skip to navigation

Elite on the BBC Micro

Dashboard: SCAN [Elite-A, Parasite]

Name: SCAN [Show more] Type: Subroutine Category: Dashboard Summary: Display the current ship on the scanner by sending a draw_tail command to the I/O processor Deep dive: The 3D scanner The I.F.F. system
Context: See this subroutine in context in the source code References: This subroutine is called as follows: * ESCAPE calls SCAN * MVEIT (Part 9 of 9) calls SCAN * MVEIT_FLIGHT (Part 2 of 6) calls SCAN * Main flight loop (Part 11 of 16) calls SCAN * WPSHPS calls SCAN

This is used both to display a ship on the scanner, and to erase it again. Arguments: INWK The ship's data block
.SC5 RTS \ Return from the subroutine .SCAN LDA INWK+31 \ Fetch the ship's scanner flag from byte #31 AND #%00010000 \ If bit 4 is clear then the ship should not be shown BEQ SC5 \ on the scanner, so return from the subroutine (as SC5 \ contains an RTS) LDA TYPE \ Fetch the ship's type from TYPE into A BMI SC5 \ If this is the planet or the sun, then the type will \ have bit 7 set and we don't want to display it on the \ scanner, so return from the subroutine (as SC5 \ contains an RTS) LDX CRGO \ If we do not have an I.F.F. system fitted (i.e. CRGO BEQ iff_not \ is zero), jump to iff_not to fetch the default \ colours, which are those for a trader or innocent \ bystander (i.e. X = 0) \ If we get here then X = &FF (as CRGO is &FF if we have \ an I.F.F. system fitted) LDY #36 \ Set A to byte #36 of the ship's blueprint, i.e. the LDA (INF),Y \ NEWB flags ASL A \ If bit 6 is set, i.e. this is a cop, a space station ASL A \ or an escape pod, jump to iff_cop to set X = 1 BCS iff_cop ASL A \ If bit 5 is set, i.e. this is an innocent bystander BCS iff_trade \ (which applies to traders and some bounty hunters), \ jump to iff_trade to set X = 0 LDY TYPE \ Set Y to the ship's type - 1 DEY BEQ iff_missle \ If Y = 0, i.e. this is a missile, then jump to \ iff_missle to set X = 3 CPY #8 \ If Y < 8, i.e. this is a cargo canister, alloy plate, BCC iff_aster \ boulder, asteroid or splinter, then jump to iff_aster \ to set X = 2 \ If we get here then the ship is not the following: \ \ * A cop/station/escape pod \ * An innocent bystander/trader/good bounty hunter \ * A missile \ * Cargo or an asteroid \ \ So it must be a pirate or a non-innocent bounty hunter INX \ X is &FF at this point, so this INX sets X = 0, and we \ then fall through into the four INX instructions below \ to set X = 4 .iff_missle INX \ If we jump to this point, then set X = 3 .iff_aster INX \ If we jump to this point, then set X = 2 .iff_cop INX \ If we jump to this point, then set X = 1 .iff_trade INX \ If we jump to this point, then set X = 0 .iff_not LDA iff_base,X \ Set COL to the base colour for this ship, given the STA COL \ I.F.F. colour index in X (this colour is used for both \ the dot and stick) LDA iff_xor,X \ Set Y2 to the alternating colour for this ship, given STA Y2 \ the I.F.F. colour index in X (this colour is used for \ making the stick striped, where appropriate) LDA INWK+1 \ If any of x_hi, y_hi and z_hi have a 1 in bit 6 or 7, ORA INWK+4 \ then the ship is too far away to be shown on the ORA INWK+7 \ scanner, so return from the subroutine (as SC5 AND #%11000000 \ contains an RTS) BNE SC5 \ If we get here, we know x_hi, y_hi and z_hi are all \ 63 (%00111111) or less \ Now, we convert the x_hi coordinate of the ship into \ the screen x-coordinate of the dot on the scanner, \ using the following (see the deep dive on "The 3D \ scanner" for an explanation): \ \ X1 = 123 + (x_sign x_hi) LDA INWK+1 \ Set x_hi CLC \ Clear the C flag so we can do addition below LDX INWK+2 \ Set X = x_sign BPL SC2 \ If x_sign is positive, skip the following EOR #%11111111 \ x_sign is negative, so flip the bits in A and subtract ADC #1 \ 1 to make it a negative number (bit 7 will now be set \ as we confirmed above that bits 6 and 7 are clear). So \ this gives A the sign of x_sign and gives it a value \ range of -63 (%11000001) to 0 .SC2 ADC #123 \ Set X1 = 123 + x_hi STA X1 \ Next, we convert the z_hi coordinate of the ship into \ the y-coordinate of the base of the ship's stick, \ like this (see the deep dive on "The 3D scanner" for \ an explanation): \ \ SC = 220 - (z_sign z_hi) / 4 \ \ though the following code actually does it like this: \ \ SC = 255 - (35 + z_hi / 4) LDA INWK+7 \ Set A = z_hi / 4 LSR A \ LSR A \ So A is in the range 0-15 CLC \ Clear the C flag LDX INWK+8 \ Set X = z_sign BPL SC3 \ If z_sign is positive, skip the following EOR #%11111111 \ z_sign is negative, so flip the bits in A and set the SEC \ C flag. As above, this makes A negative, this time \ with a range of -16 (%11110000) to -1 (%11111111). And \ as we are about to do an ADC, the SEC effectively adds \ another 1 to that value, giving a range of -15 to 0 .SC3 ADC #35 \ Set A = 35 + A to give a number in the range 20 to 50 EOR #%11111111 \ Flip all the bits and store in SC, so SC is in the STA SC \ range 205 to 235, with a higher z_hi giving a lower SC \ Now for the stick height, which we calculate using the \ following (see the deep dive on "The 3D scanner" for \ an explanation): \ \ A = - (y_sign y_hi) / 2 LDA INWK+4 \ Set A = y_hi / 2 LSR A CLC \ Clear the C flag LDX INWK+5 \ Set X = y_sign BMI SCD6 \ If y_sign is negative, skip the following, as we \ already have a positive value in A EOR #%11111111 \ y_sign is positive, so flip the bits in A and set the SEC \ C flag. This makes A negative, and as we are about to \ do an ADC below, the SEC effectively adds another 1 to \ that value to implement two's complement negation, so \ we don't need to add another 1 here .SCD6 \ We now have all the information we need to draw this \ ship on the scanner, namely: \ \ X1 = the screen x-coordinate of the ship's dot \ \ SC = the screen y-coordinate of the base of the \ stick \ \ A = the screen height of the ship's stick, with the \ correct sign for adding to the base of the stick \ to get the dot's y-coordinate \ \ First, though, we have to make sure the dot is inside \ the dashboard, by moving it if necessary ADC SC \ Set A = SC + A, so A now contains the y-coordinate of \ the end of the stick, plus the length of the stick, to \ give us the screen y-coordinate of the dot BPL ld246 \ If the result has bit 0 clear, then the result has \ overflowed and is bigger than 256, so jump to ld246 to \ set A to the maximum allowed value of 246 (this \ instruction isn't required as we test both the maximum \ and minimum below, but it might save a few cycles) CMP #194 \ If A >= 194, skip the following instruction, as 194 is BCS P%+4 \ the minimum allowed value of A LDA #194 \ A < 194, so set A to 194, the minimum allowed value \ for the y-coordinate of our ship's dot CMP #247 \ If A < 247, skip the following instruction, as 246 is BCC P%+4 \ the maximum allowed value of A .ld246 LDA #246 \ A >= 247, so set A to 246, the maximum allowed value \ for the y-coordinate of our ship's dot STA Y1 \ Store A in Y1, as it now contains the screen \ y-coordinate for the ship's dot, clipped so that it \ fits within the dashboard SEC \ Set A = A - SC to get the stick length, by reversing SBC SC \ the ADC SC we did above. This clears the C flag if the \ result is negative (i.e. the stick length is negative) \ and sets it if the result is positive (i.e. the stick \ length is negative) \ So now we have the following: \ \ X1 = the screen x-coordinate of the ship's dot, \ clipped to fit into the dashboard \ \ Y1 = the screen y-coordinate of the ship's dot, \ clipped to fit into the dashboard \ \ SC = the screen y-coordinate of the base of the \ stick \ \ A = the screen height of the ship's stick, with the \ correct sign for adding to the base of the stick \ to get the dot's y-coordinate \ \ C = 0 if A is negative, 1 if A is positive \ \ and we can get on with drawing the dot and stick TAX \ Copy the stick height in A into X LDA #&91 \ Send command &91 to the I/O processor: JSR tube_write \ \ draw_tail(x, y, base_colour, alt_colour, height) \ \ which will draw a ship on the 3D scanner with a dot \ and stick of the specified height and colour, possibly \ with stripes 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 COL \ Send the third parameter to the I/O processor: JSR tube_write \ \ * base_colour = COL LDA Y2 \ Send the fourth parameter to the I/O processor: JSR tube_write \ \ * alt_colour = Y2 TXA \ Send the fifth parameter to the I/O processor: JSR tube_write \ \ * height = the stick height that we stored in X LDX #0 \ Set X = 0 to ensure we return the same value as the \ SCAN routine in the non-Tube version RTS \ Return from the subroutine