Elite on the BBC Micro

# Elite C encyclopedia source [Elite-A]

``` ELITE C FILE

CODE_C% = P%

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

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:
* SUN (Part 1 of 4) calls SQUA2
* SUN (Part 3 of 4) calls SQUA2
* TT111 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,

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

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

Type: Subroutine
Category: Maths (Arithmetic)
Summary: Calculate (A P) = P * X
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
\
\   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

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)

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:
* LL51 calls FMLTU
* LL9 (Part 5 of 12) 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
\ to just do the shifts

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

Type: Subroutine
Category: Maths (Arithmetic)
Summary: Calculate (A P) = Q * A
Context: See this subroutine on its own page
References: This subroutine is called as follows:
* MULT12 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
\
\   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

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

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

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:

Calculate

(A X) = Q * A + (S R)

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)

Type: Subroutine
Category: Maths (Arithmetic)
Summary: Calculate (A X) = (A P) + (S R)
Context: See this subroutine on its own page
References: This subroutine is called as follows:

Add two 16-bit sign-magnitude numbers together, calculating:

(A X) = (A P) + (S R)

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

\ 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

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

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

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 entry point PD1

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)

Other entry points:

PD1                  Print the standard "goat soup" description without
checking for overrides

.PDESC

\ --- Mod: Original Acornsoft code removed: ----------->

\ 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

\ --- End of removed code ----------------------------->

.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

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

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

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:

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

\ --- Mod: Code added for Elite-A: -------------------->

.l_out

\ --- End of added code ------------------------------->

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)

\ --- Mod: Original Acornsoft code removed: ----------->

\ BEQ PAUSE2            \ Keep looping up to PAUSE2 until a key is pressed

\ --- And replaced by: -------------------------------->

BEQ l_out              \ Keep looping up to l_out until a key is pressed

\ --- End of replacement ------------------------------>

RTS                    \ Return from the subroutine

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:
* MT9 calls TT66
* TT22 calls TT66
* TT23 calls TT66
* TT25 calls TT66
* controls calls TT66
* equip_data 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

Type: Subroutine
Category: Utility routines
Summary: Clear the top part of the screen and draw a white border
Context: See this subroutine on its own page
References: This subroutine is called as follows:
* CHPR calls TTX66

Clear the top part of the screen (the space view) and draw a white border
along the top and sides.

Other entry points:

BOL1-1               Contains an RTS

.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 LASCT to 0, as 128 << 1 = %10000000 << 1 = 0. This
STA LASCT              \ stops any laser pulsing

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

LDX #&60               \ Set X to the screen memory page for the top row of the
\ screen (as screen memory starts at &6000)

.BOL1

JSR ZES1               \ Call ZES1 to zero-fill the page in X, which clears
\ that character row on the screen

INX                    \ Increment X to point to the next page, i.e. the next
\ character row

CPX #&78               \ Loop back to BOL1 until we have cleared page &7700,
BNE BOL1               \ the last character row in the space view part of the
\ screen (the top part)

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 (X1, Y1) to (0, 0)
STX X1
STX Y1

STX QQ17               \ Set QQ17 = 0 to switch to ALL CAPS

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

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:
* DKS3 calls DELAY
* Main game loop (Part 5 of 6) calls DELAY
* TT217 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

Type: Subroutine
Category: Utility routines
Summary: Clear the bottom three text rows of the mode 4 screen
Context: See this subroutine on its own page
References: This subroutine is called as follows:
* JMTB calls CLYNS
* TT102 calls CLYNS
* hm calls CLYNS

This routine clears some space at the bottom of the screen and moves the text
cursor to column 1, row 21.

Specifically, it zeroes the following screen locations:

&7507 to &75F0
&7607 to &76F0
&7707 to &77F0

which clears the three bottom text rows of the mode 4 screen (rows 21 to 23),
clearing each row from text column 1 to 30 (so it doesn't overwrite the box
border in columns 0 and 32, or the last usable column in column 31).

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

LDA #&75               \ Set the two-byte value in SC to &7507
STA SC+1
LDA #7
STA SC

LDA #0                 \ Call LYN to clear the pixels from &7507 to &75F0
JSR LYN

INC SC+1               \ Increment SC+1 so SC points to &7607

JSR LYN                \ Call LYN to clear the pixels from &7607 to &76F0

INC SC+1               \ Increment SC+1 so SC points to &7707

INY                    \ Move the text cursor to column 1 (as LYN sets Y to 0)
STY XC

\ Fall through into LYN to clear the pixels from &7707
\ to &77F0

Type: Subroutine
Category: Utility routines
Summary: Clear most of a row of pixels
Context: See this subroutine on its own page
References: This subroutine is called as follows:
* CLYNS calls LYN

Set pixels 0-233 to the value in A, starting at the pixel pointed to by SC.

Arguments:

A                    The value to store in pixels 1-233 (the only value that
is actually used is A = 0, which clears those pixels)

Returns:

Y                    Y is set to 0

Other entry points:

SC5                  Contains an RTS

.LYN

LDY #233               \ Set up a counter in Y to count down from pixel 233

.EE2

STA (SC),Y             \ Store A in the Y-th byte after the address pointed to
\ by SC

DEY                    \ Decrement Y

BNE EE2                \ Loop back until Y is zero

.SC5

RTS                    \ Return from the subroutine

Type: Subroutine
Category: Screen mode
Summary: Wait for the vertical sync
Context: See this subroutine on its own page
References: This subroutine is called as follows:
* DELAY calls WSCAN
* DK4 calls WSCAN
* TT16 calls WSCAN
* ships_ag calls WSCAN

Wait for vertical sync to occur on the video system - in other words, wait
for the screen to start its refresh cycle, which it does 50 times a second
(50Hz).

.WSCAN

LDA #0                 \ Set DL to 0
STA DL

LDA DL                 \ Loop round these two instructions until DL is no
BEQ P%-2               \ longer 0 (DL gets set to 30 in the LINSCN routine,
\ which is run when vertical sync has occurred on the
\ video system, so DL will change to a non-zero value
\ at the start of each screen refresh)

RTS                    \ Return from the subroutine

Save ELTC.bin

PRINT "ELITE C"
PRINT "Assembled at ", ~CODE_C%
PRINT "Ends at ", ~P%
PRINT "Code size is ", ~(P% - CODE_C%)