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
```