Skip to navigation

Elite on the BBC Micro

Elite I source (6502SP version)

ELITE I FILE Produces the binary file ELTI.bin that gets loaded by elite-bcfs.asm.
CODE_I% = P% LOAD_I% = LOAD% + P% - CODE%
Name: HIMCNT [View individually] Type: Variable Category: Demo Summary: Used as a loop counter for the Cobra's slow approach in the demo
.HIMCNT EQUB 0
Name: ZINF2 [View individually] Type: Subroutine Category: Utility routines Summary: Reset the INWK workspace and orientation vectors
Zero-fill the INWK ship workspace and reset the orientation vectors, with nosev pointing into the screen.
.ZINF2 LDA #0 \ Set A to 0 so we can zero-fill the workspace LDX #NI%-1 \ There are NI% bytes in the INWK workspace, so set a \ counter in X so we can loop through them .DML1 STA INWK,X \ Zero the X-th byte of the INWK workspace DEX \ Decrement the loop counter BPL DML1 \ Loop back for the next byte, until we have zero-filled \ the last byte at INWK \ Finally, we reset the orientation vectors as follows: \ \ sidev = (1, 0, 0) \ roofv = (0, 1, 0) \ nosev = (0, 0, 1) \ \ 96 * 256 (&6000) represents 1 in the orientation \ vectors, and we already set the vectors to zero above, \ so we just need to set up the high bytes of the \ diagonal values and we're done LDA #96 \ Set A to represent a 1 (in normalised vector terms) STA INWK+18 \ Set byte #18 = roofv_y_hi = 96 = 1 STA INWK+22 \ Set byte #22 = sidev_x_hi = 96 = 1 STA INWK+14 \ Set byte #14 = nosev_z_hi = 96 = 1 RTS \ Return from the subroutine
Name: TWIST [View individually] Type: Subroutine Category: Demo Summary: Pitch the current ship by a small angle in a positive direction
Other entry points: TWIST2 Pitch in the direction given in A
.TWIST2 EQUB &2C \ Skip the next instruction by turning it into \ &2C &A9 &00, or BIT &00A9, which does nothing apart \ from affect the flags .TWIST LDA #0 \ Set A = 0 STA RAT2 \ Set the pitch direction in RAT2 to A LDX #15 \ Rotate (roofv_x, nosev_x) by a small angle (pitch) LDY #9 \ in the direction given in RAT2 JSR MVS5 LDX #17 \ Rotate (roofv_y, nosev_y) by a small angle (pitch) LDY #11 \ in the direction given in RAT2 JSR MVS5 LDX #19 \ Rotate (roofv_z, nosev_z) by a small angle (pitch) LDY #13 \ in the direction given in RAT2 and return from the JMP MVS5 \ subroutine using a tail call
Name: STORE [View individually] Type: Subroutine Category: Universe Summary: Copy the ship data block at INWK back to the K% workspace
Arguments: INF The ship data block in the K% workspace to copy INWK to
.STORE LDY #(NI%-1) \ Set a counter in Y so we can loop through the NI% \ bytes in the ship data block .DML2 LDA INWK,Y \ Load the Y-th byte of INWK and store it in the Y-th STA (INF),Y \ byte of INF DEY \ Decrement the loop counter BPL DML2 \ Loop back for the next byte, until we have copied the \ last byte from INWK back to INF RTS \ Return from the subroutine
Name: DEMON [View individually] Type: Subroutine [Compare versions] Category: Demo Summary: Show the demo Deep dive: The 6502 Second Processor demo mode Secrets of the Executive version
See the deep dive on "The 6502 Second Processor demo mode" for details of how the demo is implemented.
.DEMON LDA #1 \ Clear the top part of the screen, draw a white border, JSR TT66 \ and set the current view type in QQ11 to 1 JSR RESET \ Call RESET to initialise most of the game variables LDA #0 \ Set ALPHA and ALP1 to 0, so our roll angle (i.e. that STA ALPHA \ of the camera) is 0 STA ALP1 STA DELTA \ Set DELTA to 0, so our current speed (i.e. that of the \ camera) is 0 STA scacol+CYL \ Set the scanner colour for the Cobra Mk III to colour \ 0 (black), so it doesn't appear on the scanner during \ the demo JSR DOVDU19 \ Send a #SETVDU19 0 command to the I/O processor to \ switch to the mode 1 palette for the space view, \ which is yellow (colour 1), red (colour 2) and cyan \ (colour 3) JSR nWq \ Call nWq to create a random cloud of stardust LDX #LO(acorn) \ Set (Y X) to the address of acorn, which contains the LDY #HI(acorn) \ text: "ACORNSOFT PRESENTS" (or, in the Executive \ version: "PIZZASOFT PRESENTS") JSR SLIDE \ Call SLIDE to display the Star Wars scroll text JSR ZINF2 \ Call ZINF2 to reset INWK and the orientation vectors, \ with nosev pointing into the screen. We are about to \ add the Elite logo to the universe, and the logo's \ nosev points out of the top of the logo, so this will \ spawn the logo with it tilted back so it appears \ on-edge, with the bottom of the logo pointing towards \ the viewer LDA #%10000000 \ Set y_sign to be negative STA INWK+5 LDA #100 \ Set y_lo = 100 STA INWK+3 LDA #LGO \ Set the ship type to the Elite logo STA TYPE JSR NWSHP \ Add a new Elite logo to the local bubble (in this \ case, the demo screen), pointing INF to the new ship's \ data block in K% LDA #150 \ Set a loop counter in MCNT to 150 for the grand STA MCNT \ entrance of the logo, which takes it from z = 0 (right \ up against the camera) to z = 450 (a fair distance in \ front of us), moving the logo a distance of 3 away \ from us with each iteration .FLYL1 LDA INWK+6 \ Set (z_hi z_lo) = (z_hi z_lo) + 3 CLC \ ADC #3 \ starting with the low bytes STA INWK+6 LDA INWK+7 \ And then adding the high bytes ADC #0 STA INWK+7 JSR LL9 \ Call LL9 to draw the logo on-screen DEC MCNT \ Decrement the main loop counter BNE FLYL1 \ Loop back to FLYL1 until we have done 150 iterations, \ after which (z_hi z_lo) = 150 * 3 = 450 .FLYL2 LDA INWK+6 \ Set (z_hi z_lo) = (z_hi z_lo) + 2 CLC \ ADC #2 \ starting with the low bytes STA INWK+6 LDA INWK+7 \ And then adding the high bytes ADC #0 STA INWK+7 LDA #%10000000 \ Call TWIST2 with a negative A to pitch the logo by a JSR TWIST2 \ small angle in a negative direction \DEC INWK+3 \ This instruction is commented out in the original \ source, but it would decrement y_lo, moving the logo \ down the screen JSR LL9 \ Call LL9 to draw the logo on-screen LDA INWK+14 \ Loop back to FLYL2 to keep pitching, until nosev_z_hi BPL FLYL2 \ is negative (i.e. the logo has pitched forward through \ 90 degrees, as nosev starts out by pointing into the \ screen towards the camera, in a positive direction, \ and turns negative when it's reached the vertical). \ In other words, we loop until the logo has tilted \ towards the camera and is fully vertical in front of \ the viewer JSR STORE \ Call STORE to copy the ship data block at INWK back to \ the K% workspace at INF, so the logo becomes the first \ ship in the K% block JSR ZINF2 \ Call ZINF2 to reset INWK and the orientation vectors, \ with nosev pointing into the screen LDA #108 \ Set y_lo = 108, so the Cobra we are about to spawn STA INWK+3 \ appears at the top of the screen LDA #40 \ Set z_lo = -40, so it appears a small distance behind STA INWK+6 \ the camera (the negative part is achieved by setting LDA #%10000000 \ z_sign in INWK+8 to be negative, so the ship is behind STA INWK+8 \ the camera) LDA #CYL \ Set the ship type to a Cobra Mk III STA TYPE JSR NWSHP \ Add a new Cobra Mk III to the local bubble (in this \ case, the demo screen), pointing INF to the new ship's \ data block in K% LDA #1 \ Set the Cobra's speed to 1 STA INWK+27 STA HIMCNT \ Set HIMCNT = 1 to act as an outer counter for the \ following loop LDA #90 \ Set MCNT = 90 to act as an inner counter for the STA MCNT \ following loop JSR TWIST \ Call TWIST three times to pitch by a smallish angle in JSR TWIST \ a positive direction (i.e. 3 x 3.6 degree, or 10.8 JSR TWIST \ degrees) \ The following loop iterates 90 times while HIMCNT is 1 \ and 256 times while HIMCNT is 0, to give a total of \ 346 iterations .FLYL4 JSR LL9 \ Call LL9 to draw the Cobra on-screen JSR MVEIT \ Call MVEIT to move the Cobra slowly forward DEC MCNT \ Decrement the inner counter in MCNT BNE FLYL4 \ Loop back to FLYL4 until the inner counter is 0 DEC HIMCNT \ Decrement the outer counter in HIMCNT BPL FLYL4 \ Loop back to FLYL4 until the outer counter is negative JSR ZZAAP \ Call ZZAAP to draw a vertical laser line from the \ Cobra LDA #0 \ Call the NOISE routine with A = 0 to make the sound JSR NOISE \ of a laser firing LDY #10 \ Wait for 10/50 of a second (0.2 seconds) JSR DELAY LDA #44 \ Set the Cobra's roll counter to 44 to make it roll in STA INWK+29 \ a positive direction (clockwise), for just under a \ half roll (44 * 1/16 radians = 2.75 radians = 158 \ degrees) LDA #8 \ Set the Cobra's speed to 8 STA INWK+27 LDA #&87 \ Set the Cobra's pitch counter to -7 to make it pitch STA INWK+30 \ slightly in a negative direction (pull up), so it \ starts slying gently towards the top of the screen JSR STORE \ Call STORE to copy the ship data block at INWK back to \ the K% workspace at INF, so the Cobra becomes the \ second ship in the K% block LDA #%10000000 \ Set bit 7 of byte #31 of the first ship in the K% TSB K%+31 \ block, which is the Elite logo, so this flags the logo \ as having been killed (the TSB instruction applies the \ accumulator to the memory location using an OR) JSR EXNO3 \ Make an explosion sound JSR ZZAAP \ Call ZZAAP to redraw the vertical laser line from the \ Cobra, which removes it from the screen .FLYL5 \ We now want to draw the logo exploding, so we first \ need to copy the logo's ship data block from K% to \ INWK LDX #NI%-1 \ Set a counter in X so we can loop through the NI% \ bytes in the ship data block .DML3 LDA K%,X \ Copy the X-th byte of the first ship data block in K% STA INWK,X \ to the X-th byte of INWK DEX \ Decrement the loop counter BPL DML3 \ Loop back for the next byte, until we have copied the \ last byte from K% to INWK INX \ Increment X back to 0 JSR GINF \ Call GINF to fetch the address of the ship data block \ for the ship in slot 0 (the logo) and store it in INF LDA XX21-2+2*LGO \ Set XX0(1 0) to point to the ship blueprint for the STA XX0 \ Elite logo LDA XX21-1+2*LGO STA XX0+1 LDA #LGO \ Set the ship type to the Elite logo STA TYPE INC INWK \ Increment x_lo to move the logo a little to the right JSR LL9 \ Call LL9 to draw the now-exploding logo on-screen JSR STORE \ Call STORE to copy the ship data block at INWK back to \ the K% workspace at INF JSR PBFL \ Call PBFL to send the contents of the pixel buffer to \ the I/O processor for plotting on-screen LDA INWK+31 \ Test whether bits 5 and 7 of the logo's byte #31 are AND #%10100000 \ both set ("ship is exploding" and "ship has been CMP #%10100000 \ killed") and store the resulting flags on the stack PHP \ We now want to animate the Cobra flying into the \ distance while rolling clockwise, so we first need to \ copy the logo's ship data block from K% to INWK LDX #NI%-1 \ Set a counter in X so we can loop through the NI% \ bytes in the ship data block .DML4 LDA K%+NI%,X \ Copy the X-th byte of the second ship data block in K% STA INWK,X \ to the X-th byte of INWK DEX \ Decrement the loop counter BPL DML4 \ Loop back for the next byte, until we have copied the \ last byte from K% to INWK LDX #1 \ Call GINF to fetch the address of the ship data block JSR GINF \ for the ship in slot 1 (the Cobra) and store it in INF LDA XX21-2+2*CYL \ Set XX0(1 0) to point to the ship blueprint for a STA XX0 \ Cobra Mk III LDA XX21-1+2*CYL STA XX0+1 LDA #CYL \ Set the ship type to a Cobra Mk III STA TYPE JSR MVEIT \ Call MVEIT to move the Cobra so it pitches, rolls and \ flies on JSR LL9 \ Call LL9 to draw the Cobra on-screen JSR STORE \ Call STORE to copy the ship data block at INWK back to \ the K% workspace PLP \ Restore the flags that we stored on the stack above BNE FLYL5 \ If it is not the case that bits 5 and 7 of the logo's \ byte #31 are both set, jump back to FLYL5 to keep \ drawing the exploding logo and the Cobra \ The logo has now finished exploding, as bits 5 and 7 \ of the logo's byte #31 are now both set ("ship is \ exploding" and "ship has been killed"). By this time \ the Cobra will have reached the upper part of the \ screen, where we leave it while we do the next bit of \ scrolling text LDA #14 \ Set DELTA to 14, so our current speed (i.e. that of STA DELTA \ the camera) is 14 STZ DELT4 \ Set DELT4 = 0 LSR A \ Set DELT4+1 = 14 / 4 ROR DELT4 \ LSR A \ so DELT4(1 0) therefore contains 14 * 64 ROR DELT4 STA DELT4+1 IF _EXECUTIVE LDX #LO(executive) \ Set (Y X) to the address of executive, which contains LDY #HI(executive) \ the text: "THE EXECUTIVE VERSION" JSR SLIDE \ Call SLIDE to display the Star Wars scroll text ENDIF LDX #LO(byian) \ Set (Y X) to the address of byian, which contains the LDY #HI(byian) \ text: "BY IAN BELL AND DAVID BRABEN" JSR SLIDE \ Call SLIDE to display the Star Wars scroll text \ We now want the Cobra to start flying again, so we \ first need to copy the logo's ship data block from K% \ to INWK LDX #NI%-1 \ Set a counter in X so we can loop through the NI% \ bytes in the ship data block .DML5 LDA K%+NI%,X \ Copy the X-th byte of the second ship data block in K% STA INWK,X \ to the X-th byte of INWK DEX \ Decrement the loop counter BPL DML5 \ Loop back for the next byte, until we have copied the \ last byte from K% to INWK .FLYL6 JSR STARS1 \ Call STARS1 to process the stardust for the front view JSR MVEIT \ Call MVEIT to move the Cobra so it pitches, rolls and \ flies onwards JSR LL9 \ Call LL9 to draw the Cobra on-screen LDA INWK+8 \ Keep looping back to FLYL6 until z_sign is negative, BPL FLYL6 \ i.e. the Cobra has been overtaken by the camera as the \ camera moves forward, and it's disappeared off the top \ of the screen LDX #LO(true3) \ Set (Y X) to the address of true3, which contains the LDY #HI(true3) \ text: "THE GALAXY IS IN TURMOIL, THE NAVY FAR AWAY AS \ THE EMPIRE CRUMBLES" (or, in the Executive version: \ "CONGRATULATIONS ON OBTAINING A COPY OF THIS ELUSIVE \ PRODUCT") JSR SLIDE \ Call SLIDE to display the Star Wars scroll text JSR RES2 \ Reset a number of flight variables and workspaces LDA #&E0 \ Set nosev_z_hi = -1 (as &E0 is a negative unit vector STA INWK+14 \ length), so the ship points out of the screen, towards \ us STZ DELTA \ Set DELTA to 0, so our current speed (i.e. that of the \ camera) is 0 STZ ALPHA \ Set ALPHA and ALP1 to 0, so our roll angle (i.e. that STZ ALP1 \ of the camera) is 0 LDX #15 \ Set the ship's speed to 15 STX INWK+27 LDX #5 \ Set the ship's z_hi to 5, so it's in the distance STX INWK+7 LDA #ADA \ Set the ship type to an Adder STA TYPE JSR NWSHP \ Add a new Adder to the local bubble (in this case, the \ demo screen) .FLYL7 JSR MVEIT \ Call MVEIT to move the Adder so it flies towards the \ camera JSR LL9 \ Call LL9 to draw the Adder on-screen LDA INWK+7 \ Keep looping back to FLYL7 until z_hi is zero BNE FLYL7 LDA #3 \ Set the Adder's roll counter to 3 to make it roll in STA INWK+29 \ a positive direction (clockwise) STA INWK+30 \ Set the Adder's pitch counter to 3 to make it pitch in \ a positive direction (dive) LDA INWK+8 \ Keep looping back to FLYL7 until z_sign is negative BPL FLYL7 \ i.e. the Adder has flown past the camera JSR SCAN \ Call SCAN to remove the adder from the scanner (by \ redrawing it) JSR RES2 \ Reset a number of flight variables and workspaces LDA #CYAN2 \ Set the scanner colour for the Cobra Mk III to its STA scacol+CYL \ default colour of cyan, so Cobras will appear on the \ scanner once again JMP DEATH2 \ Jump to DEATH2 to reset most of the game and restart \ from the title screen
Name: SLIDE [View individually] Type: Subroutine Category: Demo Summary: Display a Star Wars scroll text Deep dive: The 6502 Second Processor demo mode
See the deep dive on "The 6502 Second Processor demo mode" for details of how the scroll text works. Arguments: (Y X) The contents of the scroll text to display
.SLIDE JSR GRIDSET \ Call GRIDSET to populate the line coordinate tables at \ X1TB, Y1TB, X2TB and Y2TB (the TB tables) with the \ lines for the scroll text in (Y X) \ The following section does the following: \ \ * Clear the VB tables (X1VB, Y1VB, X2VB and Y2VB) \ \ * Call GRID with values of BALI dropping by 2 each \ time, from 254 to 252 to 250 ... to 6 to 4 to 2, \ to display the scroll text moving up the screen \ and into the distance \ \ * Clear the VB tables \ \ * Call GRID with BALI = 2 to erase the final set of \ lines from the screen JSR ZEVB \ Call ZEVB to zero-fill the Y1VB variable, which \ effectively clears all the VB tables as we only check \ the Y1VB table for zero values LDA #YELLOW \ Send a #SETCOL YELLOW command to the I/O processor to JSR DOCOL \ switch to colour 2, which is yellow LDA #254 \ Set BALI = 254 to act as a counter from 254 to 2, STA BALI \ decreasing by 2 each iteration, which represents the \ scrolling of the Star Wars scroll text up the screen \ and into the distance .SLL2 JSR GRID \ Call GRID to draw the Star Wars scroll text at the \ scroll position in BALI DEC BALI \ Set BALI = BALI - 2 to move the scroll text up the DEC BALI \ screen and into the distance BNE SLL2 \ Loop back to SLL2 until the loop counter is 0 (so GRID \ was last called with BALI = 2) .SL1 JSR ZEVB \ Call ZEVB to zero-fill the Y1VB variable, which \ effectively clears all the VB tables as we only check \ the Y1VB table for zero values LDA #2 \ Set BALI = 2 and fall into GRID below to redraw the STA BALI \ last set of scroll text, which erases it from the \ screen .GRID \ The GRID routine draws the Star Wars scroll text, with \ the value in BALI determining the scroll position of \ the perspective view, starting from 254 (not yet \ on-screen) and going down to 2 (the scroll has almost \ faded into the distance) \ \ The routine loops through the lines we just put in the \ TB tables, projects them into a Star Wars-like \ perspective scroll view in 3D space, then projects \ them onto the 2D screen, saving the resulting screen \ coordinates into the VB table. It then calls the \ GRIDEX routine to erase the lines from the previous \ call to GRID, and draw the new ones LDY #0 \ Set Y = 0, to act as an index into the TB tables, \ where we put the line coordinates above STY UPO \ Set UPO = 0, to act as an index into the UB tables STY INWK+8 \ Set z_sign = 0 STY INWK+1 \ Set x_hi = 0 STY INWK+4 \ Set y_hi = 0 DEY \ Decrement Y to 255, so the following loop starts with \ Y pointing to the first byte from the TB tables .GRIDL INY \ Increment Y to point to the next pair of line \ coordinates in the TB tables \ We now fetch the line's start point as 3D space \ coordinates, project it onto the Star Wars perspective \ scroll text, and project it again onto the 2D screen STZ INWK+7 \ Set z_hi = 0 LDA Y1TB,Y \ Set A to the y-coordinate of the line's start point, \ let's call it Y1 BNE P%+5 \ If A = 0, jump to GREX to draw the projected lines JMP GREX \ as we have now processed all of them SEC \ Set A = A - BALI SBC BALI \ = Y1 - BALI BCC GRIDL \ If Y1 < BALI, jump back to GRIDL to process the next \ line, as this one is not yet on-screen STA R \ Set R = Y1 - BALI ASL A \ Shift bits 6-7 of A into bits 0-1 of z_hi, so the C ROL INWK+7 \ flag is clear (as we set z_hi to 0 above) and z_hi is ASL A \ the high byte if A * 4 = (Y1 - BALI) * 4 is expressed ROL INWK+7 \ as a 16-bit value, i.e. ((Y1 - BALI) * 4) div 256 ADC #D \ Set (z_hi z_lo) = (z_hi z_lo) + #D STA INWK+6 \ \ first adding the low bytes LDA INWK+7 \ And then adding the high bytes, so we now have: ADC #0 \ STA INWK+7 \ (z_hi z_lo) = ((Y1 - BALI) * 4 div 256) + #D \ \ so because we set z_sign to 0 above, we have: \ \ (z_sign z_hi z_lo) = ((Y1 - BALI) * 4 div 256) + #D STZ S \ Set S = 0 LDA #%10000000 \ Set A to a negative sign byte STA P \ Set P = 128 JSR ADD \ Set (A X) = (A P) + (S R) \ = -128 + (0 R) \ = -128 + R \ = -128 + (Y1 - BALI) \ = Y1 - BALI - 128 STA INWK+5 \ Set (y_sign y_lo) = (A X) STX INWK+3 \ = Y1 - BALI - 128 \ \ so because we set y_hi to 0 above, we have: \ \ (y_sign y_hi y_lo) = Y1 - BALI - 128 LDA X1TB,Y \ Set A to the x-coordinate of the line's start point, \ let's call it X1. A is in the range 0 to 255, and we \ now need to move the coordinate to the left so it's in \ the range -128 to +128, but we need to put the result \ into (x_sign x_hi x_lo) which is a sign-magnitude \ number, so we can't just subtract 128, as that would \ give us a two's complement number EOR #%10000000 \ Flip the sign bit of A BPL GR2 \ If bit 7 is now clear, meaning it was previously set, \ then jump to GR2 as the original A was in the range \ 128 to 255, and we now have the correct result for \ A = A - 128, which is also |A - 128| as A was positive \ Otherwise bit 7 was previously clear, so A was in the \ range 0 to 127 and the EOR has shifted that up to 128 \ to 255, so we need to negate the number so that 128 \ becomes 0, 129 becomes 1 and so on EOR #%11111111 \ Negate the result in A by flipping all the bits and INA \ adding 1, i.e. using two's complement to negate it to \ set A to the magnitude part of the sign-magnitude \ number A - 128, i.e. |A - 128| .GR2 STA INWK \ Set x_lo = |A - 128| \ = |X1 - 128| LDA X1TB,Y \ Set x_sign to the opposite of bit 7 in X1, so it will EOR #%10000000 \ be positive if X1 > 127 and negative if X1 <= 127, so AND #%10000000 \ x_sign has the correct sign for X1 - 128: STA INWK+2 \ \ (x_sign x_lo) = X1 - 128 \ \ and because we set x_hi to 0 above, we have: \ \ (x_sign x_hi x_lo) = X1 - 128 STY YS \ Store Y, the index into the TB tables, in YS JSR PROJ \ Project the line's start coordinate onto the screen, \ returning: \ \ * K3(1 0) = the screen x-coordinate \ * K4(1 0) = the screen y-coordinate LDY YS \ Retrieve the value of Y from YS, so it once again \ contains the index into the TB tables LDA K3 \ Set XX15(1 0) = K3(1 0) STA XX15 LDA K3+1 STA XX15+1 LDA K4 \ Set XX15(3 2) = K4(1 0) STA XX15+2 LDA K4+1 STA XX15+3 \ We now fetch the line's end point as 3D space \ coordinates, project it onto the Star Wars perspective \ scroll text, and project it again onto the 2D screen STZ INWK+7 \ Set x_hi = 0 LDA Y2TB,Y \ Set A to Y2, the end point's y-coordinate from Y1TB SEC SBC BALI BCC GR6 STA R ASL A ROL INWK+7 ASL A ROL INWK+7 ADC #D STA INWK+6 LDA INWK+7 ADC #0 STA INWK+7 STZ S LDA #%10000000 STA P JSR ADD \ Set (A X) = (A P) + (S R) STA INWK+5 STX INWK+3 LDA X2TB,Y EOR #%10000000 BPL GR3 EOR #%11111111 INA .GR3 STA INWK LDA X2TB,Y EOR #%10000000 AND #%10000000 STA INWK+2 JSR PROJ \ Project the line's end coordinate onto the screen, \ returning: \ \ * K3(1 0) = the screen x-coordinate \ * K4(1 0) = the screen y-coordinate LDA K3 \ Set XX15(5 4) = K3(1 0) STA XX15+4 LDA K3+1 STA XX15+5 LDA K4 \ Set XX12(1 0) = K4(1 0) STA XX12 LDA K4+1 STA XX12+1 \ We now have our line, projected onto the Star Wars \ perspective scroll text and then onto the screen, so \ we can clip it and store it in the UB tables for \ drawing later, once we have processed all the lines in \ the scroll text in the same way JSR LL145 \ Call LL145 to see if the new line segment needs to be \ clipped to fit on-screen, returning the clipped line's \ end-points in (X1, Y1) and (X2, Y2) LDY YS \ Retrieve the value of Y from YS, so it once again \ contains the index into the TB tables BCS GR6 \ If the C flag is set then the line is not visible on \ screen, so loop back to GRIDL via GR6 to process the \ next line to draw in the scroll text INC UPO \ Increment the table pointer in UPO to point to the \ next free slot in the UB tables LDX UPO \ Load the UPO table pointer into X LDA X1 \ Store the line coordinates (X1, Y1) and (X2, Y2) in STA X1UB,X \ the next free slot in the UB tables LDA Y1 STA Y1UB,X LDA X2 STA X2UB,X LDA Y2 STA Y2UB,X .GR6 JMP GRIDL \ Loop back to GRIDL to process the next line to draw \ in the scroll text .GREX \ If we get here then it's time to draw the lines we \ just projected, and remove any lines that are already \ on-screen \ \ The VB table holds the new lines to draw, while UB \ holds all their previous coordinates, i.e. the current \ lines on-screen, so drawing the VB lines draws the \ lines in their new positions, while drawing the UB \ lines erases the old lines from the screen LDY UPO \ Set Y to the the UPO table pointer, which contains the \ number of coordinates in the X1UB, Y1UB, X2UB and Y2UB \ tables (i.e. the number of lines we projected) BEQ GREX2 \ If UPO = 0 then there are no projected lines to draw, \ so jump to GREX2 to return from the subroutine \ We now loop through the projected lines, using Y as a \ loop counter that doubles as an index into the line \ coordinate tables \ \ First we draw the Y-th line from the VB table, if \ there is one, and then we draw the Y-th line from the \ UB table, before copying the Y-th VB line coordinates \ into the UB table (so the UB table contains the lines \ that are now on-screen) .GRL2 LDA Y1VB,Y \ If there is no Y-th line in the VB table, jump to GR4 BEQ GR4 STA Y1 \ Otherwise copy the Y-th line's coordinates from the VB LDA X1VB,Y \ table into (X1, Y1) and (X2, Y2) STA X1 LDA X2VB,Y STA X2 LDA Y2VB,Y STA Y2 JSR LOIN \ Draw the line from (X1, Y1) to (X2, Y2) .GR4 LDA X1UB,Y \ Copy the Y-th line's coordinates from the UB table STA X1 \ into both the VB table and into (X1, Y1) and (X2, Y2) STA X1VB,Y LDA Y1UB,Y STA Y1 STA Y1VB,Y LDA X2UB,Y STA X2 STA X2VB,Y LDA Y2UB,Y STA Y2 STA Y2VB,Y JSR LOIN \ Draw a line from (X1, Y1) to (X2, Y2) DEY BNE GRL2 JSR LBFL .GREX2 RTS \ Return from the subroutine
Name: ZEVB [View individually] Type: Subroutine Category: Utility routines Summary: Zero-fill the Y1VB variable
.ZEVB LDA #0 \ Set A = 0 so we can use it to zero-fill the variable TAY \ Set Y = 0 to use as a loop counter, starting at 0 and \ working from 255 down to 1 .SLL1 STA Y1VB,Y \ Zero the Y-th byte from Y1VB DEY \ Decrement the loop counter BNE SLL1 \ Jump back to zero the next byte until the whole page \ is done RTS \ Return from the subroutine
Name: GRIDSET [View individually] Type: Subroutine Category: Demo Summary: Populate the line coordinate tables with the lines for the scroll text
This routine populates the X1TB, Y1TB, X2TB and Y2TB tables (the TB tables) with the line coordinates that make up each character in the scroll text that we want to display. Arguments: (Y X) The contents of the scroll text to display
.GRIDSET STX GSL1+1 \ Modify the LDA instruction at GSL1 below to point to STY GSL1+2 \ (Y X) instead of P%, i.e. to the Y-th character of the \ text we want to display LDA #254 \ Set YP = 254 STA YP LDY #0 \ Set Y = 0, to act as an index into the text we want \ to display, pointing to the character we are currently \ processing LDX #0 \ Set X = 0, to act as a pointer when populating the TB \ tables with one byte per character STX XP \ Set XP = 0, so we now have (XP, YP) = (0, 254) \ \ (XP, YP) is the coordinate in space where we start \ drawing the lines that make up the scroll text, so \ this effectively moves the scroll text cursor to the \ top-left corner (as these are space coordinates where \ higher y-coordinates are further up the screen) .GSL1 LDA P%,Y \ This instruction was modified above to load the Y-th \ character from the text we want to display into A, so \ A now contains the ASCII code of the character we want \ to process BEQ GRSEX \ If A = 0 then we have reached the end of the text to \ display, so jump down to GRSEX STY T \ Store the character index in T so we can retrieve it \ later SEC \ Set S = A - ASCII ",", as the table at LTDEF starts SBC #',' \ with the lines needed for a comma, so A now contains STA S \ the number of the entry in LTDEF for this character ASL A \ Set Y = S + 4 * A ASL A \ = A + 4 * A ADC S \ = 5 * A TAY \ \ so Y now points to the offset of the definition in the \ LTDEF table for the character in A, where the first \ character in the table is a comma and each definition \ in LTDEF consists of five bytes LDA LTDEF,Y \ Call GRS1 to put the coordinates of the character's JSR GRS1 \ first line into the TB tables LDA LTDEF+1,Y \ Call GRS1 to put the coordinates of the character's JSR GRS1 \ second line into the TB tables LDA LTDEF+2,Y \ Call GRS1 to put the coordinates of the character's JSR GRS1 \ third line into the TB tables LDA LTDEF+3,Y \ Call GRS1 to put the coordinates of the character's JSR GRS1 \ fourth line into the TB tables LDA LTDEF+4,Y \ Call GRS1 to put the coordinates of the character's JSR GRS1 \ fifth line into the TB tables LDY T \ Retrieve the original character index from T into Y INY \ Increment the character index to point to the next \ character in the text we want to display LDA XP \ Set XP = XP + #W2 CLC \ ADC #W2 \ to move the x-coordinate along by #WP (the horizontal STA XP \ character spacing for the scroll text) BCC GSL1 \ If the addition didn't overflow (i.e. XP < 256) loop \ back to GSL1 LDA #0 \ Otherwise we just reached the end of a line in the STA XP \ scroll text, so set XP = 0 to move the scroll text \ cursor to the start of the line LDA YP \ And set YP = YP - #W2Y to move the scroll text cursor SBC #W2Y \ down by one line (as #W2Y is the scroll text's STA YP \ vertical line spacing) JMP GSL1 \ Loop back to GSL1 to process the next character in the \ scroll text .GRSEX LDA #0 \ Set the X-th byte of Y1TB to 0 to indicate that we STA Y1TB,X \ have reached the end of the scroll text RTS \ Return from the subroutine
Name: GRS1 [View individually] Type: Subroutine Category: Demo Summary: Populate the line coordinate tables with the lines for a single scroll text character
This routine populates the X-th byte in the X1TB, Y1TB, X2TB and Y2TB tables (the TB tables) with the coordinates for the lines that make up the character whose definition is given in A. Arguments: A The value from the LTDEF table for the character (XP, YP) The coordinate where we should draw this character X The index of the character within the scroll text Returns: X X gets incremented to point to the next character Y Y is preserved
.GRS1 BEQ GRR1 \ If A = 0, jump to GRR1 to return from the subroutine \ as 0 denotes no line segment STA R \ Store the value from the LTDEF table in R AND #%00001111 \ Set A to bits 0-3 of the LTDEF table value, i.e the \ bottom nibble STY P \ Store the offset in P, so we can preserve it through \ calls to GRS1 TAY \ Set Y = A LDA NOFX,Y \ Set X1TB+X = XP + NOFX+Y CLC \ ADC XP \ so the X1 coordinate is XP + the NOFX entry given by STA X1TB,X \ the bottom nibble of the LTDEF table value LDA YP \ Set Y1TB+X = YP - NOFY+Y SEC \ SBC NOFY,Y \ so the Y1 coordinate is YP - the NOFY entry given by STA Y1TB,X \ the bottom nibble of the LTDEF table value LDA R \ Set Y to bits 4-7 of the LTDEF table value, i.e. the LSR A \ top nibble LSR A LSR A LSR A TAY LDA NOFX,Y \ Set X2TB+X = XP + NOFX+Y CLC \ ADC XP \ so the X2 coordinate is XP + the NOFX entry given by STA X2TB,X \ the top nibble of the LTDEF table value LDA YP \ Set Y2TB+X = YP - NOFY+Y SEC \ SBC NOFY,Y \ so the Y2 coordinate is YP - the NOFY entry given by STA Y2TB,X \ the top nibble of the LTDEF table value INX \ Increment the byte pointer in X LDY P \ Restore Y from P so it gets preserved through calls to \ GRS1 .GRR1 RTS \ Return from the subroutine
Name: ZZAAP [View individually] Type: Subroutine Category: Demo Summary: Draw a vertical red laser line from (128, 67) to (128, 160)
.ZZAAP LDA #RED \ Send a #SETCOL RED command to the I/O processor to JSR DOCOL \ switch to colour 2, which is red in the space view LDA #128 \ Set X1 = 128 STA X1 STA X2 \ Set X2 = 128 LDA #67 \ Set Y1 = 67 STA Y1 LDA #160 \ Set Y2 = 160 STA Y2 JMP LL30 \ Call LL30 to draw a line from (X1, Y1) to (X2, Y2), \ returning from the subroutine using a tail
Name: LTDEF [View individually] Type: Variable Category: Demo Summary: Line definitions for characters in the Star Wars scroll text
Characters in the scroll text are drawn using lines on a 3x6 grid like this: . . . . . . . . . . . . . . . . . . The spacing of the grid points is configured like this (in terms of space coordinates): 0 . . . 0.5 * WY . . . 1.0 * WY . . . 1.5 * WY . . . 2.0 * WY . . . 2.5 * WY . . . 4 8 12 so the vertical spacing is controlled by configuration variable WY. The default value of WY is 12, so the vertical grid spacing is 6, while the horizontal grid spacing is 4. When drawing letters, only 12 of the 18 points can be used. They are numbered as follows: 0 1 2 . . . 3 4 5 . . . 6 7 8 9 A B The x-coordinate of point n within the grid (relative to the top-left corner) is given by the n-th entry in the NOFX table, while the y-coordinate is given by the n-th entry in NOFY. So point 0 is at (NOFX+0, NOFX+0) = (4, 0), and point 8 is at (NOFX+8, NOFX+8) = (12, 2 * WY). The LTDEF table contains definitions for all the letters and some punctuation characters. Each definition consists of 5 bytes, with each byte describing one line in the character's shape (bytes with value 0 are ignored, so each character consists of up to five lines but can contain fewer lines). The bottom nibble of each byte is the starting point for that line segment, and the top nibble is the end point, so a value of &28, for example, means "draw a line from point 8 to point 2". Let's look at a few examples to make this clearer. The definition in LTDEF for "A" is: &60, &02, &28, &35, &00 This translates to the following: &60 = line from point 0 to point 6 &02 = line from point 2 to point 0 &28 = line from point 8 to point 2 &35 = line from point 5 to point 3 &00 = ignore which looks like this on the grid: +-------+ | . | +-------+ | . | | . | . . . The definition in LTDEF for "S" is: &20, &03, &35, &58, &86 This translates to the following: &20 = line from point 0 to point 2 &03 = line from point 3 to point 0 &35 = line from point 5 to point 3 &58 = line from point 8 to point 5 &86 = line from point 6 to point 8 which looks like this on the grid: +-------+ | . . +-------+ . . | +-------+ . . . The definition in LTDEF for "," is: &63, &34, &47, &76, &97 This translates to the following: &63 = line from point 3 to point 6 &34 = line from point 4 to point 3 &47 = line from point 7 to point 4 &76 = line from point 6 to point 7 &97 = line from point 7 to point 9 which looks like this on the grid: . . . . . . +---+ . | | . +---/ . _.-ยด. . Colons and semi-colons are shown as spaces (as their LTDEF definitions are all zeroes), so when a string like "TURMOIL,THE:NAVY" is displayed, the comma is shown as a comma, but the colon is shown as a space. The scroll text has 16 characters per line, as the character width in #W2 is set to 16 by default, and the width of the whole scroll text is 256.
.LTDEF EQUB &63, &34, &47, &76, &97 \ Letter definition for "," EQUB &35, &00, &00, &00, &00 \ Letter definition for "-" EQUB &63, &34, &47, &76, &00 \ Letter definition for "." EQUB &61, &00, &00, &00, &00 \ Letter definition for "/" EQUB &73, &31, &15, &57, &00 \ Letter definition for "0" EQUB &31, &17, &00, &00, &00 \ Letter definition for "1" EQUB &02, &25, &53, &36, &68 \ Letter definition for "2" EQUB &02, &28, &86, &35, &00 \ Letter definition for "3" EQUB &82, &23, &35, &00, &00 \ Letter definition for "4" EQUB &20, &03, &35, &58, &86 \ Letter definition for "5" EQUB &20, &06, &68, &85, &53 \ Letter definition for "6" EQUB &02, &28, &00, &00, &00 \ Letter definition for "7" EQUB &60, &02, &28, &86, &35 \ Letter definition for "8" EQUB &82, &20, &03, &35, &00 \ Letter definition for "9" EQUB &00, &00, &00, &00, &00 \ Letter definition for ":" (blank) EQUB &00, &00, &00, &00, &00 \ Letter definition for ";" (blank) EQUB &00, &00, &00, &00, &00 \ Letter definition for "<" (blank) EQUB &00, &00, &00, &00, &00 \ Letter definition for "=" (blank) EQUB &00, &00, &00, &00, &00 \ Letter definition for ">" (blank) EQUB &00, &00, &00, &00, &00 \ Letter definition for "?" (blank) EQUB &00, &00, &00, &00, &00 \ Letter definition for "@" (blank) EQUB &60, &02, &28, &35, &00 \ Letter definition for "A" EQUB &60, &02, &28, &86, &35 \ Letter definition for "B" EQUB &86, &60, &02, &00, &00 \ Letter definition for "C" EQUB &60, &05, &56, &00, &00 \ Letter definition for "D" EQUB &86, &60, &02, &35, &00 \ Letter definition for "E" EQUB &60, &02, &35, &00, &00 \ Letter definition for "F" EQUB &45, &58, &86, &60, &02 \ Letter definition for "G" EQUB &60, &28, &35, &00, &00 \ Letter definition for "H" EQUB &17, &00, &00, &00, &00 \ Letter definition for "I" EQUB &28, &86, &63, &00, &00 \ Letter definition for "J" EQUB &60, &23, &83, &00, &00 \ Letter definition for "K" EQUB &86, &60, &00, &00, &00 \ Letter definition for "L" EQUB &60, &04, &42, &28, &00 \ Letter definition for "M" EQUB &60, &08, &82, &00, &00 \ Letter definition for "N" EQUB &60, &02, &28, &86, &00 \ Letter definition for "O" EQUB &60, &02, &25, &53, &00 \ Letter definition for "P" EQUB &60, &02, &28, &86, &48 \ Letter definition for "Q" EQUB &60, &02, &25, &53, &48 \ Letter definition for "R" EQUB &20, &03, &35, &58, &86 \ Letter definition for "S" EQUB &02, &17, &00, &00, &00 \ Letter definition for "T" EQUB &28, &86, &60, &00, &00 \ Letter definition for "U" EQUB &27, &70, &00, &00, &00 \ Letter definition for "V" EQUB &28, &84, &46, &60, &00 \ Letter definition for "W" EQUB &26, &08, &00, &00, &00 \ Letter definition for "X" EQUB &74, &04, &24, &00, &00 \ Letter definition for "Y" EQUB &02, &26, &68, &00, &00 \ Letter definition for "Z"
Name: NOFX [View individually] Type: Variable Category: Demo Summary: The x-coordinates of the scroll text letter grid
.NOFX EQUB 4 \ Grid points 0-2 EQUB 8 EQUB 12 EQUB 4 \ Grid points 3-5 EQUB 8 EQUB 12 EQUB 4 \ Grid points 6-8 EQUB 8 EQUB 12 EQUB 4 \ Grid points 9-B EQUB 8 EQUB 12
Name: NOFY [View individually] Type: Variable Category: Demo Summary: The y-coordinates of the scroll text letter grid
.NOFY EQUB 0 \ Grid points 0-2 EQUB 0 EQUB 0 EQUB WY \ Grid points 3-5 EQUB WY EQUB WY EQUB 2*WY \ Grid points 6-8 EQUB 2*WY EQUB 2*WY EQUB 2.5*WY \ Grid points 9-B EQUB 2.5*WY EQUB 2.5*WY
Name: acorn [View individually] Type: Variable [Compare versions] Category: Demo Summary: The text for the demo's opening scroll text
.acorn IF _SNG45 OR _SOURCE_DISC EQUS ":::ACORNSOFT::::" EQUS ";;;;;;;;;;;;;;;;" EQUS "::::PRESENTS" EQUB 0 ELIF _EXECUTIVE EQUS ":::PIZZASOFT::::" EQUS ";;;;;;;;;;;;;;;;" EQUS "::::PRESENTS" EQUB 0 ENDIF
Name: byian [View individually] Type: Variable Category: Demo Summary: The text for the demo's middle scroll text
.byian EQUS "::::::BY:;::::::" EQUS ";;;;IAN;BELL;;;;" EQUS "::::::AND:::::::" EQUS ";;DAVID;BRABEN" EQUB 0
Name: executive [View individually] Type: Variable [Compare versions] Category: Demo Summary: Extra text for the demo in the Executive version
.executive IF _EXECUTIVE EQUS "::::::THE;::::::" EQUS ";;;EXECUTIVE;;;;" EQUS "::::VERSION" EQUB 0 ENDIF
Name: true3 [View individually] Type: Variable [Compare versions] Category: Demo Summary: The text for the demo's final scroll text
.true3 IF _SNG45 OR _SOURCE_DISC EQUS "THE:GALAXY:IS:IN" EQUS "TURMOIL,THE:NAVY" EQUS "FAR:AWAY:AS::THE" EQUS "EMPIRE:CRUMBLES." EQUB 0 ELIF _EXECUTIVE EQUS "CONGRATULATIONS:" EQUS ";ON;OBTAINING;A;" EQUS "::COPY:OF:THIS::" EQUS "ELUSIVE;PRODUCT." EQUB 0 ENDIF
Name: TALK [View individually] Type: Subroutine [Compare versions] Category: Sound Summary: Speak using the Watford Electronics Beeb Speech Synthesiser Deep dive: Secrets of the Executive version
In the Executive version, if you have a Watford Electronics Beeb Speech Synthesiser fitted and enable speech by presing ":" while the game is paused, then the game will speak to you at various points. Arguments: X The number of the phrase to speak: 1 = "Incoming missile" 2 = "Energy low" 3 = "Elite" 4 = "Oh shit, it's a mis-jump"
.TALK IF _EXECUTIVE TYA \ Store Y on the stack to we can retrieve it later PHA BIT SPEAK \ If SPEAK is 0, then speech is not enabled, so jump BPL TALK4 \ to TALK4 to restore Y from the stack and return \ from the subroutine LDA #0 \ Set SC = 0 STA SC LDY #LO(SPEECH) \ Set Y to point to the low byte of SPEECH LDA #HI(SPEECH) \ Set SC(1 0) so it points to the start of the page STA SC+1 \ containing SPEECH, so by this point, so SC+Y points \ to the first byte of SPEECH .TALKL LDA (SC),Y \ Fetch the next byte from the SPEECH block CMP #13 \ If it not 13 (which is the terminator for each speech BNE TALK1 \ command), jump to TALK1 to skip to the next byte DEX \ We just reached a terminator, so decrement the phrase \ number in X BEQ TALK2 \ If X is now 0, we have now found the terminator just \ before the phrase we want (the X-th phrase), so jump \ to TALK2 to speak it .TALK1 INY \ Increment the byte counter in Y to point to the next \ byte in the SPEECH table BNE TALKL \ If Y is non-zero, loop back to TALKL to process the \ next byte INC SC+1 \ Y is 0, which means SC+Y has just crossed a page \ boundary, so increment the high byte in SC+1 so that \ SC+Y points to the next page BNE TALKL \ Loop back to TALKL to process the next byte (this BNE \ is effectively a JMP as SC+1 is never zero) .TALK2 INY \ If we get here then SC+Y points to the terminator \ before the phrase we want, so increment Y to point to \ the start of the phrase we want BNE TALK3 \ If Y is non-zero, then SC+Y points to the phrase we \ want to speak, so jump to TALK3 to do the speaking INC SC+1 \ Y is 0, which means SC+Y has just crossed a page \ boundary, so increment the high byte in SC+1 so that \ SC+Y points to the next page .TALK3 TYA \ Set (Y X) to point to (SC+1 Y), i.e. SC+Y TAX LDY SC+1 JSR OSCLI \ Call OSCLI to run the OS command in SC+Y, which will \ be of the form "*TALK xx", a command for making the \ Watford Electronics Beeb Speech Synthesiser talk .TALK4 PLA \ Restore the value of Y we stored on the stack, so it TAY \ gets preserved across the call to the subroutine RTS \ Return from the subroutine ENDIF
Name: SPEECH [View individually] Type: Variable [Compare versions] Category: Sound Summary: Phrases for the Watford Electronics Beeb Speech Synthesiser Deep dive: Secrets of the Executive version
.SPEECH IF _EXECUTIVE EQUB 13 EQUS "TALK " \ 1: "Incoming missile" EQUS "A NN1 " EQUS "PA2 " EQUS "KK3 AA MM IH NG " EQUS "PA4 " EQUS "MM IH SS I LL" EQUB 13 EQUS "TALK " \ 2: "Energy low" EQUS "N ER1 G " EQUS "PA4 " EQUS "LOW" EQUB 13 EQUS "TALK " \ 3: "Elite" EQUS "EH LL EY TT1" EQUB 13 EQUS "TALK " \ 4: "Oh shit, it's a mis-jump" EQUS "O " EQUS "PA2 " EQUS "SH IH TT1 " EQUS "PA5 " EQUS "IH TT1 SS " EQUS "PA4 " EQUS "A " EQUS "PA4 " EQUS "MM IS " EQUS "PA2 " EQUS "JH UW1 MM PP" EQUB 13 ENDIF
Save output/ELTI.bin
PRINT "ELITE I" PRINT "Assembled at ", ~CODE_I% PRINT "Ends at ", ~P% PRINT "Code size is ", ~(P% - CODE_I%) PRINT "Execute at ", ~LOAD% PRINT "Reload at ", ~LOAD_I% PRINT "S.ELTI ", ~CODE_I%, " ", ~P%, " ", ~LOAD%, " ", ~LOAD_H% SAVE "output/ELTI.bin", CODE_I%, P%, LOAD%