Skip to navigation

Elite on the BBC Micro and NES

Ship hangar: HANGER

[BBC Micro disc version, Docked]

Name: HANGER [Show more] Type: Subroutine Category: Ship hangar Summary: Display the ship hangar
Context: See this subroutine in context in the source code Variations: See code variations for this subroutine in the different versions References: No direct references to this subroutine in this source file

This routine is called after the ships in the hangar have been drawn, so all it has to do is draw the hangar's background. The hangar background is made up of two parts: * The hangar floor consists of 11 screen-wide horizontal lines, which start out quite spaced out near the bottom of the screen, and bunch ever closer together as the eye moves up towards the horizon, where they merge to give a sense of perspective * The back wall of the hangar consists of 15 equally spaced vertical lines that join the horizon to the top of the screen The ships in the hangar have already been drawn by this point, so the lines are drawn so they don't overlap anything that's already there, which makes them look like they are behind and below the ships. This is achieved by drawing the lines in from the screen edges until they bump into something already on-screen. For the horizontal lines, when there are multiple ships in the hangar, this also means drawing lines between the ships, as well as in from each side.
.HANGER \ We start by drawing the floor LDX #2 \ We start with a loop using a counter in XSAV 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 to the value of the loop counter JSR DVID4 \ Calculate the following: \ \ (P R) = 256 * A / Q \ = 256 * 130 / Q \ \ so P = 130 / Q, and as the counter Q 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 P \ Set A = #Y + P CLC \ ADC #Y \ where #Y is the y-coordinate of the centre of the \ screen, so A is now the horizontal pixel row of the \ line we want to draw to display the hangar floor LSR A \ Set A = A >> 3 LSR A LSR A ORA #&60 \ Each character row in Elite's screen mode takes up one \ page in memory (256 bytes), so we now OR with &60 to \ get the page containing the line STA SCH \ Store the screen page in the high byte of SC(1 0) LDA P \ Set the low byte of SC(1 0) to the y-coordinate mod 7, AND #7 \ which determines the pixel row in the character block STA SC \ we need to draw in (as each character row is 8 pixels \ high), so SC(1 0) now points to the address of the \ start of the horizontal line we want to draw LDY #0 \ Set Y = 0 so the call to HAS2 starts drawing the line \ in the first byte of the screen row, at the left edge \ of the screen JSR HAS2 \ Draw a horizontal line from the left edge of the \ screen, going right until we bump into something \ already on-screen, at which point stop drawing LDA #%00000100 \ Now to draw the same line but from the right edge of \ the screen, so set a pixel mask in A to check the \ sixth pixel of the last byte, so we skip the 2-pixel \ screen border at the right edge of the screen LDY #248 \ Set Y = 248 so the call to HAS3 starts drawing the \ line in the last byte of the screen row, at the right \ edge of the screen JSR HAS3 \ Draw a horizontal line from the right edge of the \ screen, going left until we bump into something \ already on-screen, at which point stop drawing LDY YSAV \ Fetch the value of YSAV, which gets set to 0 in the \ HALL routine above if there is only one ship BEQ HA2 \ If YSAV is zero, jump to HA2 to skip the following \ as there is only one ship in the hangar \ If we get here then there are multiple ships in the \ hangar, so we also need to draw the horizontal line in \ the gap between the ships JSR HAS2 \ Call HAS2 to draw a line to the right, starting with \ the third pixel of the pixel row at screen address \ SC(1 0), so this draws a line from just after the \ halfway point across the right half of the screen, \ going right until we bump into something already \ on-screen, at which point it stops drawing LDY #128 \ We now draw the line from the centre of the screen \ to the left. SC(1 0) points to the start address of \ the screen row, so we set Y to 128 so the call to \ HAS3 starts drawing from halfway along the row (i.e. \ from the centre of the screen) LDA #%01000000 \ We want to start drawing from the second pixel, to \ avoid the border, so we set a pixel mask accordingly JSR HAS3 \ Call HAS3, which draws a line from the halfway point \ across the left half of the screen, going left until \ we bump into something already on-screen, at which \ point it stops drawing .HA2 \ We have finished threading our horizontal line behind \ the ships already on-screen, so now for the next line LDX XSAV \ Fetch the loop counter from XSAV and increment it INX CPX #13 \ If the loop counter is less than 13 (i.e. 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 LDX #&60 \ Set the high byte of SC(1 0) to &60, the high byte of STX SCH \ the start of screen STA XSAV \ Store this value in XSAV, so we can retrieve it later AND #%11111000 \ Each character block contains 8 pixel rows, so to get \ the address of the first byte in the character block \ that we need to draw into, as an offset from the start \ of the row, we clear bits 0-2 STA SC \ Set the low byte of SC(1 0) to this value, so SC(1 0) \ now points to the address where the line starts LDX #%10000000 \ Set a mask in X to the first pixel the 8-pixel byte LDY #1 \ We are going to start drawing the line from the second \ pixel from the top (to avoid drawing on the 1-pixel \ border), so set Y to 1 to point to the second row in \ the first character block .HAL7 TXA \ Copy the pixel mask to A AND (SC),Y \ If the pixel we want to draw is non-zero (using A as a BNE HA6 \ mask), then this means it already contains something, \ so jump to HA6 to stop drawing this line TXA \ Copy the pixel mask to A again ORA (SC),Y \ OR the byte with the current contents of screen \ memory, so the pixel we want is set STA (SC),Y \ Store the updated pixel in screen memory INY \ Increment Y to point to the next row in the character \ block, i.e. the next pixel down CPY #8 \ Loop back to HAL7 to draw this next pixel until we BNE HAL7 \ have drawn all 8 in the character block INC SC+1 \ Point SC(1 0) to the next page in memory, i.e. the \ next character row LDY #0 \ Set Y = 0 to point to the first row in this character \ block BEQ HAL7 \ Loop back up to HAL7 to keep drawing the line (this \ BEQ is effectively a JMP as Y is always zero) .HA6 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