Skip to navigation

Elite on the BBC Micro and NES

Version analysis of HANGER

This code appears in the following versions (click to see it in the source code):

Code variations between these versions are shown below.

Name: HANGER Type: Subroutine Category: Ship hangar

Code variation 1 of 21A variation in the comments only

Tap on a block to expand it, and tap it again to revert.

Summary: Display the ship hangar
Summary: Implement the OSWORD 248 command (display the ship hangar)

Code variation 2 of 21A variation in the comments only

Tap on a block to expand it, and tap it again to revert.

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.
This command is sent 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.

Code variation 3 of 21A variation in the comments only

This variation is blank in the Disc (docked) version.

Other entry points: HA3 Contains an RTS
.HANGER \ We start by drawing the floor

Code variation 4 of 21Minor and very low-impact

Tap on a block to expand it, and tap it again to revert.

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

Code variation 5 of 21Specific to an individual platform

This variation is blank in the Disc (docked) and 6502 Second Processor versions.

LDA #%00001111 \ Set bits 1 and 2 of the Access Control Register at STA VIA+&34 \ SHEILA &34 to switch screen memory into &3000-&7FFF
.HAL1

Code variation 6 of 21Minor and very low-impact

Tap on a block to expand it, and tap it again to revert.

STX XSAV \ Store the loop counter in XSAV
STX T \ Store the loop counter in T
 LDA #130               \ Set A = 130

Code variation 7 of 21Minor and very low-impact

This variation is blank in the 6502 Second Processor and Master versions.

LDX XSAV \ Retrieve the loop counter from XSAV
 STX Q                  \ Set Q to the value of the loop counter

Code variation 8 of 21A variation in the labels only

Tap on a block to expand it, and tap it again to revert.

JSR DVID4 \ Calculate the following:
JSR DVID4K \ 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)

Code variation 9 of 21Related to the screen mode

Tap on a block to expand it, and tap it again to revert.

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 Y = #Y + P CLC \ ADC #Y \ where #Y is the y-coordinate of the centre of the TAY \ screen, so Y is now the horizontal pixel row of the \ line we want to draw to display the hangar floor LDA ylookup,Y \ Look up the page number of the character row that STA SC+1 \ contains the pixel with the y-coordinate in Y, and \ store it in the high byte of SC(1 0) at SC+1 STA R \ Also store the page number in R
 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

Code variation 10 of 21Related to the screen mode

Tap on a block to expand it, and tap it again to revert.

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 R \ Fetch the page number of the line from R, increment it INY \ so it points to the right half of the character row STY SC+1 \ (as each row takes up 2 pages), and store it in the \ high byte of SC(1 0) at SC+1 LDA #%01000000 \ Now to draw the same line but from the right edge of \ the screen, so set a pixel mask in A to check the \ second 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

Code variation 11 of 21Related to Elite's use of the Tube

Tap on a block to expand it, and tap it again to revert.

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
LDY HANGFLAG \ Fetch the value of HANGFLAG, which gets set to 0 in \ the HALL routine above if there is only one ship BEQ HA2 \ If HANGFLAG is zero, jump to HA2 to skip the following \ as there is only one ship in the hangar
LDY #2 \ Fetch byte #2 from the parameter block, which tells us LDA (OSSC),Y \ whether the ship hangar contains just one ship, or TAY \ multiple ships BEQ HA2 \ If byte #2 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

Code variation 12 of 21Related to the screen mode

Tap on a block to expand it, and tap it again to revert.

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
LDY #0 \ First we draw the line from the centre of the screen \ to the right. SC(1 0) points to the start address of \ the second half of the screen row, so we set Y to 0 so \ the call to HAL3 starts drawing from the first \ character in that second half LDA #%10001000 \ We want to start drawing from the first pixel, so we \ set a mask in A to the first pixel in the 4-pixel byte JSR HAL3 \ Call HAL3, which draws a line from 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 DEC SC+1 \ Decrement the high byte of SC(1 0) in SC+1 to point to \ the previous page (i.e. the left half of this screen \ row) LDY #248 \ We now draw the line from the centre of the screen \ to the left. SC(1 0) points to the start address of \ the first half of the screen row, so we set Y to 248 \ so the call to HAS3 starts drawing from the last \ character in that first half LDA #%00010000 \ We want to start drawing from the last pixel, so we \ set a mask in A to the last pixel in the 4-pixel byte 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

Code variation 13 of 21Minor and very low-impact

Tap on a block to expand it, and tap it again to revert.

LDX XSAV \ Fetch the loop counter from XSAV and increment it INX
LDX T \ Fetch the loop counter from T 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

Code variation 14 of 21Other (e.g. bug fix, optimisation)

The ship hangar in the advanced versions draws the vertical lines for the backdrop 60 times, when it only needs to do this 15 times. Is this a quick way of making the hangar display hang around for longer, or is it just a mistake?

This variation is blank in the Disc (docked) version.

LDA #60 \ Set S = 60, so we run the following 60 times (though I STA S \ have no idea why it's 60 times, when it should be 15, \ as this has the effect of drawing each vertical line \ four times, each time starting one character row lower \ on-screen)
 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

Code variation 15 of 21Related to the screen mode

This variation is blank in the Disc (docked) version.

LDX #&40 \ Set X = &40, the high byte of the start of screen STX R \ memory (the screen starts at location &4000) and the \ page number of the first screen row
.HAL6

Code variation 16 of 21Related to the screen mode

Tap on a block to expand it, and tap it again to revert.

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
LDX R \ Set the high byte of SC(1 0) to R STX SC+1 STA T \ Store A in T so we can retrieve it later AND #%11111100 \ A contains the x-coordinate of the line to draw, and STA SC \ each character block is 4 pixels wide, so setting the \ low byte of SC(1 0) to A mod 4 points SC(1 0) to the \ correct character block on the top screen row for this \ x-coordinate LDX #%10001000 \ Set a mask in X to the first pixel in the 4-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

Code variation 17 of 21Related to the screen mode

Tap on a block to expand it, and tap it again to revert.

ORA (SC),Y \ OR the byte with the current contents of screen \ memory, so the pixel we want is set
AND #RED \ Apply the pixel mask in A to a four-pixel block of \ red pixels, so we now know which bits to set in screen \ memory ORA (SC),Y \ OR the byte with the current contents of screen \ memory, so the pixel we want is set to red (because \ we know the bits are already 0 from the above test)
 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

Code variation 18 of 21Related to the screen mode

Tap on a block to expand it, and tap it again to revert.

INC SC+1 \ Point SC(1 0) to the next page in memory, i.e. the \ next character row
INC SC+1 \ There are two pages of memory for each character row, INC SC+1 \ so we increment the high byte of SC(1 0) twice to \ point to the same character but in the next row down
 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

Code variation 19 of 21Related to the screen mode

Tap on a block to expand it, and tap it again to revert.

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
LDA T \ Fetch the x-coordinate of the line we just drew from T CLC \ into A, and add 16 so that A contains the x-coordinate ADC #16 \ of the next line to draw BCC P%+4 \ If the addition overflowed, increment the page number INC R \ in R to point to the second half of the screen row DEC S \ Decrement the loop counter in S
 BNE HAL6               \ Loop back to HAL6 until we have run through the loop
                        \ 60 times, by which point we are most definitely done

Code variation 20 of 21Specific to an individual platform

This variation is blank in the Disc (docked) and 6502 Second Processor versions.

IF _SNG47 LDA #%00001001 \ Clear bits 1 and 2 of the Access Control Register at STA VIA+&34 \ SHEILA &34 to switch main memory back into &3000-&7FFF RTS \ Return from the subroutine (this instruction is not \ needed as we could just fall through into the RTS at \ HA3 below) ELIF _COMPACT JMP away \ Jump to away to switch main memory back into \ &3000-&7FFF and return from the subroutine ENDIF

Code variation 21 of 21A variation in the labels only

This variation is blank in the Disc (docked) version.

.HA3
 RTS                    \ Return from the subroutine