Skip to navigation

Elite on the BBC Micro

Elite A flight source (Disc version)

ELITE A FILE
CODE% = &11E3 LOAD% = &11E3 ORG CODE% LOAD_A% = LOAD%
Name: S% [View individually] Type: Workspace Address: &11E3 to &11F0 Category: Workspaces Summary: Entry points and vector addresses in the main flight code
.S% JMP scramble \ Decrypt the main flight code and join the main loop JMP scramble \ Decrypt the main flight code and start a new game JMP TT26 \ WRCHV is set to point here by elite-loader3.asm EQUW IRQ1 \ IRQ1V is set to point here by elite-loader3.asm JMP BRBR1 \ BRKV is set to point here by elite-loader3.asm
Name: INBAY [View individually] Type: Subroutine Category: Loader Summary: Load and run the main docked code in T.CODE
.INBAY LDX #LO(LTLI) \ Set (Y X) to point to LTLI ("L.T.CODE", which gets LDY #HI(LTLI) \ modified to "R.T.CODE" in the DOENTRY routine) JSR OSCLI \ Call OSCLI to run the OS command in LTLI, which *RUNs \ the main docked code in T.CODE
Name: LTLI [View individually] Type: Variable Category: Loader Summary: The OS command string for loading the docked code file T.CODE
.LTLI EQUS "L.T.CODE" EQUB 13
Name: scramble [View individually] Type: Subroutine [Compare versions] Category: Loader Summary: Decrypt the main flight code between &1300 and &55FF and jump into the main game loop
.scramble LDY #0 \ We're going to work our way through a large number of \ encrypted bytes, so we set Y to 0 to be the index of \ the current byte within its page in memory STY SC \ Set the low byte of SC(1 0) to 0 LDX #&13 \ Set X to &13 to be the page number of the current \ byte, so we start the decryption with the first byte \ of page &13 .scrl STX SCH \ Set the high byte of SC(1 0) to X, so SC(1 0) now \ points to the first byte of page X TYA \ Set A to Y, so A now contains the index of the current \ byte within its page EOR (SC),Y \ EOR the current byte with its index within the page EOR #&33 \ EOR the current byte with &33 STA (SC),Y \ Update the current byte \ The current byte is in page X at offset Y, and SC(1 0) \ points to the first byte of page X, so we just did \ this: \ \ (X Y) = (X Y) EOR Y EOR &33 DEY \ Decrement the index in Y to point to the next byte BNE scrl \ Loop back to scrl to decrypt the next byte until we \ have done the whole page INX \ Increment X to point to the next page in memory CPX #&56 \ Loop back to scrl to decrypt the next page until we BNE scrl \ reach the start of page &56 JMP RSHIPS \ Call RSHIPS to launch from the station, load a new set \ of ship blueprints and jump into the main game loop
Name: DOENTRY [View individually] Type: Subroutine Category: Loader Summary: Load and run the docked code
.DOENTRY LDA #'R' \ Modify the command in LTLI from "L.T.CODE" to STA LTLI \ "R.T.CODE" so it *RUNs the code rather than loading it \ Fall into DEATH2 to reset most variables and *RUN the \ docked code
Name: DEATH2 [View individually] Type: Subroutine [Compare versions] Category: Start and end Summary: Reset most of the game and restart from the title screen
This routine is called following death, and when the game is quit by pressing ESCAPE when paused.
.DEATH2 JSR RES2 \ Reset a number of flight variables and workspaces \ and fall through into the entry code for the game \ to restart from the title screen JSR CATD \ Call CATD to reload the disc catalogue BNE INBAY \ Jump to INBAY to load the docked code (this BNE is \ effectively a JMP)
Name: Main flight loop (Part 1 of 16) [View individually] Type: Subroutine [Compare versions] Category: Main loop Summary: Seed the random number generator Deep dive: Program flow of the main game loop Generating random numbers
The main flight loop covers most of the flight-specific aspects of Elite. This section covers the following: * Seed the random number generator Other entry points: M% The entry point for the main flight loop
.M% LDA K% \ We want to seed the random number generator with a \ pretty random number, so fetch the contents of K%, \ which is the x_lo coordinate of the planet. This value \ will be fairly unpredictable, so it's a pretty good \ candidate STA RAND \ Store the seed in the first byte of the four-byte \ random number seed that's stored in RAND
Name: Main flight loop (Part 2 of 16) [View individually] Type: Subroutine [Compare versions] Category: Main loop Summary: Calculate the alpha and beta angles from the current pitch and roll of our ship Deep dive: Program flow of the main game loop Pitching and rolling
The main flight loop covers most of the flight-specific aspects of Elite. This section covers the following: * Calculate the alpha and beta angles from the current pitch and roll Here we take the current rate of pitch and roll, as set by the joystick or keyboard, and convert them into alpha and beta angles that we can use in the matrix functions to rotate space around our ship. The alpha angle covers roll, while the beta angle covers pitch (there is no yaw in this version of Elite). The angles are in radians, which allows us to use the small angle approximation when moving objects in the sky (see the MVEIT routine for more on this). Also, the signs of the two angles are stored separately, in both the sign and the flipped sign, as this makes calculations easier.
LDX JSTX \ Set X to the current rate of roll in JSTX, and JSR cntr \ apply keyboard damping twice (if enabled) so the roll JSR cntr \ rate in X creeps towards the centre by 2 \ The roll rate in JSTX increases if we press ">" (and \ the RL indicator on the dashboard goes to the right). \ This rolls our ship to the right (clockwise), but we \ actually implement this by rolling everything else \ to the left (anticlockwise), so a positive roll rate \ in JSTX translates to a negative roll angle alpha TXA \ Set A and Y to the roll rate but with the sign bit EOR #%10000000 \ flipped (i.e. set them to the sign we want for alpha) TAY AND #%10000000 \ Extract the flipped sign of the roll rate and store STA ALP2 \ in ALP2 (so ALP2 contains the sign of the roll angle \ alpha) STX JSTX \ Update JSTX with the damped value that's still in X EOR #%10000000 \ Extract the correct sign of the roll rate and store STA ALP2+1 \ in ALP2+1 (so ALP2+1 contains the flipped sign of the \ roll angle alpha) TYA \ Set A to the roll rate but with the sign bit flipped BPL P%+7 \ If the value of A is positive, skip the following \ three instructions EOR #%11111111 \ A is negative, so change the sign of A using two's CLC \ complement so that A is now positive and contains ADC #1 \ the absolute value of the roll rate, i.e. |JSTX| LSR A \ Divide the (positive) roll rate in A by 4 LSR A CMP #8 \ If A >= 8, skip the following instruction BCS P%+3 LSR A \ A < 8, so halve A again STA ALP1 \ Store A in ALP1, so we now have: \ \ ALP1 = |JSTX| / 8 if |JSTX| < 32 \ \ ALP1 = |JSTX| / 4 if |JSTX| >= 32 \ \ This means that at lower roll rates, the roll angle is \ reduced closer to zero than at higher roll rates, \ which gives us finer control over the ship's roll at \ lower roll rates \ \ Because JSTX is in the range -127 to +127, ALP1 is \ in the range 0 to 31 ORA ALP2 \ Store A in ALPHA, but with the sign set to ALP2 (so STA ALPHA \ ALPHA has a different sign to the actual roll rate) LDX JSTY \ Set X to the current rate of pitch in JSTY, and JSR cntr \ apply keyboard damping so the pitch rate in X creeps \ towards the centre by 1 TXA \ Set A and Y to the pitch rate but with the sign bit EOR #%10000000 \ flipped TAY AND #%10000000 \ Extract the flipped sign of the pitch rate into A STX JSTY \ Update JSTY with the damped value that's still in X STA BET2+1 \ Store the flipped sign of the pitch rate in BET2+1 EOR #%10000000 \ Extract the correct sign of the pitch rate and store STA BET2 \ it in BET2 TYA \ Set A to the pitch rate but with the sign bit flipped BPL P%+4 \ If the value of A is positive, skip the following \ instruction EOR #%11111111 \ A is negative, so flip the bits ADC #4 \ Add 4 to the (positive) pitch rate, so the maximum \ value is now up to 131 (rather than 127) LSR A \ Divide the (positive) pitch rate in A by 16 LSR A LSR A LSR A CMP #3 \ If A >= 3, skip the following instruction BCS P%+3 LSR A \ A < 3, so halve A again STA BET1 \ Store A in BET1, so we now have: \ \ BET1 = |JSTY| / 32 if |JSTY| < 48 \ \ BET1 = |JSTY| / 16 if |JSTY| >= 48 \ \ This means that at lower pitch rates, the pitch angle \ is reduced closer to zero than at higher pitch rates, \ which gives us finer control over the ship's pitch at \ lower pitch rates \ \ Because JSTY is in the range -131 to +131, BET1 is in \ the range 0 to 8 ORA BET2 \ Store A in BETA, but with the sign set to BET2 (so STA BETA \ BETA has the same sign as the actual pitch rate) LDA BSTK \ If BSTK = 0 then the Bitstik is not configured, so BEQ BS2 \ jump to BS2 to skip the following LDX #3 \ Call OSBYTE 128 to fetch the 16-bit value from ADC LDA #128 \ channel 3 (the Bitstik rotation value), returning the JSR OSBYTE \ value in (Y X) TYA \ Copy Y to A, so the result is now in (A X) LSR A \ Divide A by 4 LSR A CMP #40 \ If A < 40, skip the following instruction BCC P%+4 LDA #40 \ Set A = 40, which ensures a maximum speed of 40 STA DELTA \ Update our speed in DELTA BNE MA4 \ If the speed we just set is non-zero, then jump to MA4 \ to skip the following, as we don't need to check the \ keyboard for speed keys, otherwise do check the \ keyboard (so Bitstik users can still use the keyboard \ for speed adjustments if they twist the stick to zero)
Name: Main flight loop (Part 3 of 16) [View individually] Type: Subroutine [Compare versions] Category: Main loop Summary: Scan for flight keys and process the results Deep dive: Program flow of the main game loop The key logger
The main flight loop covers most of the flight-specific aspects of Elite. This section covers the following: * Scan for flight keys and process the results Flight keys are logged in the key logger at location KY1 onwards, with a non-zero value in the relevant location indicating a key press. See the deep dive on "The key logger" for more details. The key presses that are processed are as follows: * Space and "?" to speed up and slow down * "U", "T" and "M" to disarm, arm and fire missiles * TAB to fire an energy bomb * ESCAPE to launch an escape pod * "J" to initiate an in-system jump * "E" to deploy E.C.M. anti-missile countermeasures * "C" to use the docking computer * "A" to fire lasers
.BS2 LDA KY2 \ If Space is being pressed, keep going, otherwise jump BEQ MA17 \ down to MA17 to skip the following LDA DELTA \ The "go faster" key is being pressed, so first we CMP #40 \ fetch the current speed from DELTA into A, and if BCS MA17 \ A >= 40, we are already going at full pelt, so jump \ down to MA17 to skip the following INC DELTA \ We can go a bit faster, so increment the speed in \ location DELTA .MA17 LDA KY1 \ If "?" is being pressed, keep going, otherwise jump BEQ MA4 \ down to MA4 to skip the following DEC DELTA \ The "slow down" key is being pressed, so we decrement \ the current ship speed in DELTA BNE MA4 \ If the speed is still greater than zero, jump to MA4 INC DELTA \ Otherwise we just braked a little too hard, so bump \ the speed back up to the minimum value of 1 .MA4 LDA KY15 \ If "U" is being pressed and the number of missiles AND NOMSL \ in NOMSL is non-zero, keep going, otherwise jump down BEQ MA20 \ to MA20 to skip the following LDY #&EE \ The "disarm missiles" key is being pressed, so call JSR ABORT \ ABORT to disarm the missile and update the missile \ indicators on the dashboard to green/cyan (Y = &EE) LDA #40 \ Call the NOISE routine with A = 40 to make a low, JSR NOISE \ long beep to indicate the missile is now disarmed .MA31 LDA #0 \ Set MSAR to 0 to indicate that no missiles are STA MSAR \ currently armed .MA20 LDA MSTG \ If MSTG is positive (i.e. it does not have bit 7 set), BPL MA25 \ then it indicates we already have a missile locked on \ a target (in which case MSTG contains the ship number \ of the target), so jump to MA25 to skip targeting. Or \ to put it another way, if MSTG = &FF, which means \ there is no current target lock, keep going LDA KY14 \ If "T" is being pressed, keep going, otherwise jump BEQ MA25 \ down to MA25 to skip the following LDX NOMSL \ If the number of missiles in NOMSL is zero, jump down BEQ MA25 \ to MA25 to skip the following STA MSAR \ The "target missile" key is being pressed and we have \ at least one missile, so set MSAR = &FF to denote that \ our missile is currently armed (we know A has the \ value &FF, as we just loaded it from MSTG and checked \ that it was negative) LDY #&E0 \ Change the leftmost missile indicator to yellow/white JSR MSBAR \ on the missile bar (this call changes the leftmost \ indicator because we set X to the number of missiles \ in NOMSL above, and the indicators are numbered from \ right to left, so X is the number of the leftmost \ indicator) .MA25 LDA KY16 \ If "M" is being pressed, keep going, otherwise jump BEQ MA24 \ down to MA24 to skip the following LDA MSTG \ If MSTG = &FF then there is no target lock, so jump to BMI MA64 \ MA64 to skip the following (also skipping the checks \ for TAB, ESCAPE, "J" and "E") JSR FRMIS \ The "fire missile" key is being pressed and we have \ a missile lock, so call the FRMIS routine to fire \ the missile .MA24 LDA KY12 \ If TAB is being pressed, keep going, otherwise jump BEQ MA76 \ jump down to MA76 to skip the following ASL BOMB \ The "energy bomb" key is being pressed, so double \ the value in BOMB. If we have an energy bomb fitted, \ BOMB will contain &7F (%01111111) before this shift \ and will contain &FE (%11111110) after the shift; if \ we don't have an energy bomb fitted, BOMB will still \ contain 0. The bomb explosion is dealt with in the \ MAL1 routine below - this just registers the fact that \ we've set the bomb ticking .MA76 LDA KY20 \ If "P" is being pressed, keep going, otherwise skip BEQ MA78 \ the next two instructions LDA #0 \ The "cancel docking computer" key is bring pressed, STA auto \ so turn it off by setting auto to 0 .MA78 LDA KY13 \ If ESCAPE is being pressed and we have an escape pod AND ESCP \ fitted, keep going, otherwise jump to noescp to skip BEQ noescp \ the following instructions JMP ESCAPE \ The "launch escape pod" button is being pressed and \ we have an escape pod fitted, so jump to ESCAPE to \ launch it, and exit the main flight loop using a tail \ call .noescp LDA KY18 \ If "J" is being pressed, keep going, otherwise skip BEQ P%+5 \ the next instruction JSR WARP \ Call the WARP routine to do an in-system jump LDA KY17 \ If "E" is being pressed and we have an E.C.M. fitted, AND ECM \ keep going, otherwise jump down to MA64 to skip the BEQ MA64 \ following LDA ECMA \ If ECMA is non-zero, that means an E.C.M. is already BNE MA64 \ operating and is counting down (this can be either \ our E.C.M. or an opponent's), so jump down to MA64 to \ skip the following (as we can't have two E.C.M. \ systems operating at the same time) DEC ECMP \ The "E.C.M." button is being pressed and nobody else \ is operating their E.C.M., so decrease the value of \ ECMP to make it non-zero, to denote that our E.C.M. \ is now on JSR ECBLB2 \ Call ECBLB2 to light up the E.C.M. indicator bulb on \ the dashboard, set the E.C.M. countdown timer to 32, \ and start making the E.C.M. sound .MA64 LDA KY19 \ If "C" is being pressed, and we have a docking AND DKCMP \ computer fitted, keep going, otherwise jump down to BEQ MA68 \ MA68 to skip the following STA auto \ Set auto to the non-zero value of A, so the docking \ computer is activated .MA68 LDA #0 \ Set LAS = 0, to switch the laser off while we do the STA LAS \ following logic STA DELT4 \ Take the 16-bit value (DELTA 0) - i.e. a two-byte LDA DELTA \ number with DELTA as the high byte and 0 as the low LSR A \ byte - and divide it by 4, storing the 16-bit result ROR DELT4 \ in DELT4(1 0). This has the effect of storing the LSR A \ current speed * 64 in the 16-bit location DELT4(1 0) ROR DELT4 STA DELT4+1 LDA LASCT \ If LASCT is zero, keep going, otherwise the laser is BNE MA3 \ a pulse laser that is between pulses, so jump down to \ MA3 to skip the following LDA KY7 \ If "A" is being pressed, keep going, otherwise jump BEQ MA3 \ down to MA3 to skip the following LDA GNTMP \ If the laser temperature >= 242 then the laser has CMP #242 \ overheated, so jump down to MA3 to skip the following BCS MA3 LDX VIEW \ If the current space view has a laser fitted (i.e. the LDA LASER,X \ laser power for this view is greater than zero), then BEQ MA3 \ keep going, otherwise jump down to MA3 to skip the \ following \ If we get here, then the "fire" button is being \ pressed, our laser hasn't overheated and isn't already \ being fired, and we actually have a laser fitted to \ the current space view, so it's time to hit me with \ those laser beams PHA \ Store the current view's laser power on the stack AND #%01111111 \ Set LAS and LAS2 to bits 0-6 of the laser power STA LAS STA LAS2 LDA #0 \ Call the NOISE routine with A = 0 to make the sound JSR NOISE \ of our laser firing JSR LASLI \ Call LASLI to draw the laser lines PLA \ Restore the current view's laser power into A BPL ma1 \ If the laser power has bit 7 set, then it's an "always \ on" laser rather than a pulsing laser, so keep going, \ otherwise jump down to ma1 to skip the following \ instruction LDA #0 \ This is an "always on" laser (i.e. a beam laser, \ as the cassette version of Elite doesn't have military \ lasers), so set A = 0, which will be stored in LASCT \ to denote that this is not a pulsing laser .ma1 AND #%11111010 \ LASCT will be set to 0 for beam lasers, and to the STA LASCT \ laser power AND %11111010 for pulse lasers, which \ comes to 10 (as pulse lasers have a power of 15). See \ MA23 below for more on laser pulsing and LASCT
Name: Main flight loop (Part 4 of 16) [View individually] Type: Subroutine [Compare versions] Category: Main loop Summary: For each nearby ship: Copy the ship's data block from K% to the zero-page workspace at INWK Deep dive: Program flow of the main game loop Ship data blocks
The main flight loop covers most of the flight-specific aspects of Elite. This section covers the following: * Start looping through all the ships in the local bubble, and for each one: * Copy the ship's data block from K% to INWK * Set XX0 to point to the ship's blueprint (if this is a ship) Other entry points: MAL1 Marks the beginning of the ship analysis loop, so we can jump back here from part 12 of the main flight loop to work our way through each ship in the local bubble. We also jump back here when a ship is removed from the bubble, so we can continue processing from the next ship
.MA3 LDX #0 \ We're about to work our way through all the ships in \ our local bubble of universe, so set a counter in X, \ starting from 0, to refer to each ship slot in turn .MAL1 STX XSAV \ Store the current slot number in XSAV LDA FRIN,X \ Fetch the contents of this slot into A. If it is 0 BNE P%+5 \ then this slot is empty and we have no more ships to JMP MA18 \ process, so jump to MA18 below, otherwise A contains \ the type of ship that's in this slot, so skip over the \ JMP MA18 instruction and keep going STA TYPE \ Store the ship type in TYPE JSR GINF \ Call GINF to fetch the address of the ship data block \ for the ship in slot X and store it in INF. The data \ block is in the K% workspace, which is where all the \ ship data blocks are stored \ Next we want to copy the ship data block from INF to \ the zero-page workspace at INWK, so we can process it \ more efficiently LDY #NI%-1 \ There are NI% bytes in each ship data block (and in \ the INWK workspace, so we set a counter in Y so we can \ loop through them .MAL2 LDA (INF),Y \ Load the Y-th byte of INF and store it in the Y-th STA INWK,Y \ byte of INWK DEY \ Decrement the loop counter BPL MAL2 \ Loop back for the next byte until we have copied the \ last byte from INF to INWK LDA TYPE \ If the ship type is negative then this indicates a BMI MA21 \ planet or sun, so jump down to MA21, as the next bit \ sets up a pointer to the ship blueprint, and then \ checks for energy bomb damage, and neither of these \ apply to planets and suns ASL A \ Set Y = ship type * 2 TAY LDA XX21-2,Y \ The ship blueprints at XX21 start with a lookup STA XX0 \ table that points to the individual ship blueprints, \ so this fetches the low byte of this particular ship \ type's blueprint and stores it in XX0 LDA XX21-1,Y \ Fetch the high byte of this particular ship type's STA XX0+1 \ blueprint and store it in XX0+1
Name: Main flight loop (Part 5 of 16) [View individually] Type: Subroutine [Compare versions] Category: Main loop Summary: For each nearby ship: If an energy bomb has been set off, potentially kill this ship Deep dive: Program flow of the main game loop
The main flight loop covers most of the flight-specific aspects of Elite. This section covers the following: * Continue looping through all the ships in the local bubble, and for each one: * If an energy bomb has been set off and this ship can be killed, kill it and increase the kill tally
LDA BOMB \ If we set off our energy bomb (see MA24 above), then BPL MA21 \ BOMB is now negative, so this skips to MA21 if our \ energy bomb is not going off CPY #2*SST \ If the ship in Y is the space station, jump to BA21 BEQ MA21 \ as energy bombs are useless against space stations LDA INWK+31 \ If the ship we are checking has bit 5 set in its ship AND #%00100000 \ byte #31, then it is already exploding, so jump to BNE MA21 \ BA21 as ships can't explode more than once ASL INWK+31 \ The energy bomb is killing this ship, so set bit 7 of SEC \ the ship byte #31 to indicate that it has now been ROR INWK+31 \ killed JSR EXNO2 \ Call EXNO2 to process the fact that we have killed a \ ship (so increase the kill tally, make an explosion \ sound and possibly display "RIGHT ON COMMANDER!")
Name: Main flight loop (Part 6 of 16) [View individually] Type: Subroutine Category: Main loop Summary: For each nearby ship: Move the ship in space and copy the updated INWK data block back to K% Deep dive: Program flow of the main game loop Program flow of the ship-moving routine Ship data blocks
The main flight loop covers most of the flight-specific aspects of Elite. This section covers the following: * Continue looping through all the ships in the local bubble, and for each one: * Move the ship in space * Copy the updated ship's data block from INWK back to K%
.MA21 JSR MVEIT \ Call MVEIT to move the ship we are processing in space \ Now that we are done processing this ship, we need to \ copy the ship data back from INWK to the correct place \ in the K% workspace. We already set INF in part 4 to \ point to the ship's data block in K%, so we can simply \ do the reverse of the copy we did before, this time \ copying from INWK to INF LDY #(NI%-1) \ Set a counter in Y so we can loop through the NI% \ bytes in the ship data block .MAL3 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 MAL3 \ Loop back for the next byte, until we have copied the \ last byte from INWK back to INF
Name: Main flight loop (Part 7 of 16) [View individually] Type: Subroutine [Compare versions] Category: Main loop Summary: For each nearby ship: Check whether we are docking, scooping or colliding with it Deep dive: Program flow of the main game loop
The main flight loop covers most of the flight-specific aspects of Elite. This section covers the following: * Continue looping through all the ships in the local bubble, and for each one: * Check how close we are to this ship and work out if we are docking, scooping or colliding with it
LDA INWK+31 \ Fetch the status of this ship from bits 5 (is ship AND #%10100000 \ exploding?) and bit 7 (has ship been killed?) from \ ship byte #31 into A JSR MAS4 \ Or this value with x_hi, y_hi and z_hi BNE MA65 \ If this value is non-zero, then either the ship is \ far away (i.e. has a non-zero high byte in at least \ one of the three axes), or it is already exploding, \ or has been flagged as being killed - in which case \ jump to MA65 to skip the following, as we can't dock \ scoop or collide with it LDA INWK \ Set A = (x_lo OR y_lo OR z_lo), and if bit 7 of the ORA INWK+3 \ result is set, the ship is still a fair distance ORA INWK+6 \ away (further than 127 in at least one axis), so jump BMI MA65 \ to MA65 to skip the following, as it's too far away to \ dock, scoop or collide with LDX TYPE \ If the current ship type is negative then it's either BMI MA65 \ a planet or a sun, so jump down to MA65 to skip the \ following, as we can't dock with it or scoop it CPX #SST \ If this ship is the space station, jump to ISDK to BEQ ISDK \ check whether we are docking with it AND #%11000000 \ If bit 6 of (x_lo OR y_lo OR z_lo) is set, then the BNE MA65 \ ship is still a reasonable distance away (further than \ 63 in at least one axis), so jump to MA65 to skip the \ following, as it's too far away to dock, scoop or \ collide with CPX #MSL \ If this ship is a missile, jump down to MA65 to skip BEQ MA65 \ the following, as we can't scoop or dock with a \ missile, and it has its own dedicated collision \ checks in the TACTICS routine LDA BST \ If we have fuel scoops fitted then BST will be &FF, \ otherwise it will be 0 AND INWK+5 \ Ship byte #5 contains the y_sign of this ship, so a \ negative value here means the canister is below us, \ which means the result of the AND will be negative if \ the canister is below us and we have a fuel scoop \ fitted BPL MA58 \ If the result is positive, then we either have no \ scoop or the canister is above us, and in both cases \ this means we can't scoop the item, so jump to MA58 \ to process a collision
Name: Main flight loop (Part 8 of 16) [View individually] Type: Subroutine [Compare versions] Category: Main loop Summary: For each nearby ship: Process us potentially scooping this item Deep dive: Program flow of the main game loop
The main flight loop covers most of the flight-specific aspects of Elite. This section covers the following: * Continue looping through all the ships in the local bubble, and for each one: * Process us potentially scooping this item
CPX #OIL \ If this is a cargo canister, jump to oily to randomly BEQ oily \ decide the canister's contents LDY #0 \ Fetch byte #0 of the ship's blueprint LDA (XX0),Y LSR A \ Shift it right four times, so A now contains the high LSR A \ nibble (i.e. bits 4-7) LSR A LSR A BEQ MA58 \ If A = 0, jump to MA58 to skip all the docking and \ scooping checks \ Only the Thargon, alloy plate, splinter and escape pod \ have non-zero upper nibbles in their blueprint byte #0 \ so if we get here, our ship is one of those, and the \ upper nibble gives the market item number of the item \ when scooped, less 1 ADC #1 \ Add 1 to the upper nibble to get the market item \ number BNE slvy2 \ Skip to slvy2 so we scoop the ship as a market item .oily JSR DORND \ Set A and X to random numbers and reduce A to a AND #7 \ random number in the range 0-7 .slvy2 \ By the time we get here, we are scooping, and A \ contains the type of item we are scooping (a random \ number 0-7 if we are scooping a cargo canister, 3 if \ we are scooping an escape pod, or 16 if we are \ scooping a Thargon). These numbers correspond to the \ relevant market items (see QQ23 for a list), so a \ cargo canister can contain anything from food to \ computers, while escape pods contain slaves, and \ Thargons become alien items when scooped JSR tnpr1 \ Call tnpr1 with the scooped cargo type stored in A \ to work out whether we have room in the hold for one \ tonne of this cargo (A is set to 1 by this call, and \ the C flag contains the result) LDY #78 \ This instruction has no effect, so presumably it used \ to do something, but didn't get removed BCS MA59 \ If the C flag is set then we have no room in the hold \ for the scooped item, so jump down to MA59 make a \ sound to indicate failure, before destroying the \ canister LDY QQ29 \ Scooping was successful, so set Y to the type of \ item we just scooped, which we stored in QQ29 above ADC QQ20,Y \ Add A (which we set to 1 above) to the number of items STA QQ20,Y \ of type Y in the cargo hold, as we just successfully \ scooped one canister of type Y TYA \ Print recursive token 48 + A as an in-flight token, ADC #208 \ which will be in the range 48 ("FOOD") to 64 ("ALIEN JSR MESS \ ITEMS"), so this prints the scooped item's name ASL NEWB \ The item has now been scooped, so set bit 7 of its SEC \ NEWB flags to indicate this ROR NEWB .MA65 JMP MA26 \ If we get here, then the ship we are processing was \ too far away to be scooped, docked or collided with, \ so jump to MA26 to skip over the collision routines \ and move on to missile targeting
Name: Main flight loop (Part 9 of 16) [View individually] Type: Subroutine [Compare versions] Category: Main loop Summary: For each nearby ship: If it is a space station, check whether we are successfully docking with it Deep dive: Program flow of the main game loop Docking checks
The main flight loop covers most of the flight-specific aspects of Elite. This section covers the following: * Process docking with a space station For details on the various docking checks in this routine, see the deep dive on "Docking checks". Other entry points: GOIN We jump here from part 3 of the main flight loop if the docking computer is activated by pressing "C"
.ISDK LDA K%+NI%+36 \ 1. Fetch the NEWB flags (byte #36) of the second ship AND #%00000100 \ in the ship data workspace at K%, which is reserved BNE MA62 \ for the sun or the space station (in this case it's \ the latter), and if bit 2 is set, meaning the station \ is hostile, jump down to MA62 to fail docking (so \ trying to dock at a station that we have annoyed does \ not end well) LDA INWK+14 \ 2. If nosev_z_hi < 214, jump down to MA62 to fail CMP #214 \ docking, as the angle of approach is greater than 26 BCC MA62 \ degrees JSR SPS1 \ Call SPS1 to calculate the vector to the planet and \ store it in XX15 LDA XX15+2 \ Set A to the z-axis of the vector CMP #86 \ 4. If z-axis < 86, jump to MA62 to fail docking, as BCC MA62 \ we are not in the 26.3 degree safe cone of approach LDA INWK+16 \ 5. If |roofv_x_hi| < 80, jump to MA62 to fail docking, AND #%01111111 \ as the slot is more than 36.6 degrees from horizontal CMP #80 BCC MA62 .GOIN \ If we arrive here, either the docking computer has \ been activated, or we just docked successfully JSR RES2 \ Reset a number of flight variables and workspaces LDA #8 \ Set the step size for the launch tunnel rings to 8, so \ there are fewer sections in the rings and they are \ quite polygonal (compared to the step size of 4 used \ in the much rounder hyperspace rings) JSR HFS2 \ Call HFS2 to draw the launch tunnel rings JMP DOENTRY \ Go to the docking bay (i.e. show the ship hanger) .MA62 \ If we arrive here, docking has just failed LDA DELTA \ If the ship's speed is < 5, jump to MA67 to register CMP #5 \ some damage, but not a huge amount BCC MA67 JMP DEATH \ Otherwise we have just crashed into the station, so \ process our death
Name: Main flight loop (Part 10 of 16) [View individually] Type: Subroutine Category: Main loop Summary: For each nearby ship: Remove if scooped, or process collisions Deep dive: Program flow of the main game loop
The main flight loop covers most of the flight-specific aspects of Elite. This section covers the following: * Continue looping through all the ships in the local bubble, and for each one: * Remove scooped item after both successful and failed scoopings * Process collisions
.MA59 \ If we get here then scooping failed JSR EXNO3 \ Make the sound of the cargo canister being destroyed \ and fall through into MA60 to remove the canister \ from our local bubble .MA60 \ If we get here then scooping was successful ASL INWK+31 \ Set bit 7 of the scooped or destroyed item, to denote SEC \ that it has been killed and should be removed from ROR INWK+31 \ the local bubble .MA61 \ This label is not used but is in the original source BNE MA26 \ Jump to MA26 to skip over the collision routines and \ to move on to missile targeting (this BNE is \ effectively a JMP as A will never be zero) .MA67 \ If we get here then we have collided with something, \ but not fatally LDA #1 \ Set the speed in DELTA to 1 (i.e. a sudden stop) STA DELTA LDA #5 \ Set the amount of damage in A to 5 (a small dent) and BNE MA63 \ jump down to MA63 to process the damage (this BNE is \ effectively a JMP as A will never be zero) .MA58 \ If we get here, we have collided with something in a \ potentially fatal way ASL INWK+31 \ Set bit 7 of the ship we just collided with, to SEC \ denote that it has been killed and should be removed ROR INWK+31 \ from the local bubble LDA INWK+35 \ Load A with the energy level of the ship we just hit SEC \ Set the amount of damage in A to 128 + A / 2, so ROR A \ this is quite a big dent, and colliding with higher \ energy ships will cause more damage .MA63 JSR OOPS \ The amount of damage is in A, so call OOPS to reduce \ our shields, and if the shields are gone, there's a \ a chance of cargo loss or even death JSR EXNO3 \ Make the sound of colliding with the other ship and \ fall through into MA26 to try targeting a missile
Name: Main flight loop (Part 11 of 16) [View individually] Type: Subroutine [Compare versions] Category: Main loop Summary: For each nearby ship: Process missile lock and firing our laser Deep dive: Program flow of the main game loop Flipping axes between space views
The main flight loop covers most of the flight-specific aspects of Elite. This section covers the following: * Continue looping through all the ships in the local bubble, and for each one: * If this is not the front space view, flip the axes of the ship's coordinates in INWK * Process missile lock * Process our laser firing
.MA26 LDA NEWB \ If bit 7 of the ship's NEWB flags is clear, skip the BPL P%+5 \ following instruction JSR SCAN \ Bit 7 of the ship's NEWB flags is set, which means the \ ship has docked or been scooped, so we draw the ship \ on the scanner, which has the effect of removing it LDA QQ11 \ If this is not a space view, jump to MA15 to skip BNE MA15 \ missile and laser locking LDX VIEW \ Load the current view into X BEQ P%+5 \ If the current view is the front view, skip the \ following instruction, as the geometry in INWK is \ already correct JSR PU1 \ Call PU1 to update the geometric axes in INWK to \ match the view (front, rear, left, right) JSR HITCH \ Call HITCH to see if this ship is in the crosshairs, BCC MA8 \ in which case the C flag will be set (so if there is \ no missile or laser lock, we jump to MA8 to skip the \ following) LDA MSAR \ We have missile lock, so check whether the leftmost BEQ MA47 \ missile is currently armed, and if not, jump to MA47 \ to process laser fire, as we can't lock an unarmed \ missile JSR BEEP \ We have missile lock and an armed missile, so call \ the BEEP subroutine to make a short, high beep LDX XSAV \ Call ABORT2 to store the details of this missile LDY #&0E \ lock, with the targeted ship's slot number in X JSR ABORT2 \ (which we stored in XSAV at the start of this ship's \ loop at MAL1), and set the colour of the missile \ indicator to the colour in Y (red = &0E) .MA47 \ If we get here then the ship is in our sights, but \ we didn't lock a missile, so let's see if we're \ firing the laser LDA LAS \ If we are firing the laser then LAS will contain the BEQ MA8 \ laser power (which we set in MA68 above), so if this \ is zero, jump down to MA8 to skip the following LDX #15 \ We are firing our laser and the ship in INWK is in JSR EXNO \ the crosshairs, so call EXNO to make the sound of \ us making a laser strike on another ship LDA TYPE \ Did we just hit the space station? If so, jump to CMP #SST \ MA14+2 to make the station hostile, skipping the BEQ MA14+2 \ following as we can't destroy a space station CMP #CON \ If the ship we hit is not a Constrictor, jump to BURN BNE BURN \ to skip the following LDA LAS \ Set A to the power of the laser we just used to hit \ the ship (i.e. the laser in the current view) CMP #(Armlas AND 127) \ If the laser is not a military laser, jump to MA8 BNE MA8 \ to skip the following, as only military lasers have \ any effect on the Constrictor LSR LAS \ Divide the laser power of the current view by 4, so LSR LAS \ the damage inflicted on the super-ship is a quarter of \ the damage our military lasers would inflict on a \ normal ship .BURN LDA INWK+35 \ Fetch the hit ship's energy from byte #35 and subtract SEC \ our current laser power, and if the result is greater SBC LAS \ than zero, the other ship has survived the hit, so BCS MA14 \ jump down to MA14 ASL INWK+31 \ Set bit 7 of the ship byte #31 to indicate that it has SEC \ now been killed ROR INWK+31 LDA TYPE \ Did we just kill an asteroid? If not, jump to nosp, CMP #AST \ otherwise keep going BNE nosp LDA LAS \ Did we kill the asteroid using mining lasers? If not, CMP #Mlas \ jump to nosp, otherwise keep going BNE nosp JSR DORND \ Set A and X to random numbers LDX #SPL \ Set X to the ship type for a splinter AND #3 \ Reduce the random number in A to the range 0-3 JSR SPIN2 \ Call SPIN2 to spawn A items of type X (i.e. spawn \ 0-3 spliters) .nosp LDY #PLT \ Randomly spawn some alloy plates JSR SPIN LDY #OIL \ Randomly spawn some cargo canisters JSR SPIN JSR EXNO2 \ Call EXNO2 to process the fact that we have killed a \ ship (so increase the kill tally, make an explosion \ sound and so on) .MA14 STA INWK+35 \ Store the hit ship's updated energy in ship byte #35 LDA TYPE \ Call ANGRY to make this ship hostile, now that we JSR ANGRY \ have hit it
Name: Main flight loop (Part 12 of 16) [View individually] Type: Subroutine [Compare versions] Category: Main loop Summary: For each nearby ship: Draw the ship, remove if killed, loop back Deep dive: Program flow of the main game loop Drawing ships
The main flight loop covers most of the flight-specific aspects of Elite. This section covers the following: * Continue looping through all the ships in the local bubble, and for each one: * Draw the ship * Process removal of killed ships * Loop back up to MAL1 to move onto the next ship in the local bubble
.MA8 JSR LL9 \ Call LL9 to draw the ship we're processing on-screen .MA15 LDY #35 \ Fetch the ship's energy from byte #35 and copy it to LDA INWK+35 \ byte #35 in INF (so the ship's data in K% gets STA (INF),Y \ updated) LDA NEWB \ If bit 7 of the ship's NEWB flags is set, which means BMI KS1S \ the ship has docked or been scooped, jump to KS1S to \ skip the following, as we can't get a bounty for a \ ship that's no longer around LDA INWK+31 \ If bit 7 of the ship's byte #31 is clear, then the BPL MAC1 \ ship hasn't been killed by energy bomb, collision or \ laser fire, so jump to MAC1 to skip the following AND #%00100000 \ If bit 5 of the ship's byte #31 is clear then the BEQ MAC1 \ ship is no longer exploding, so jump to MAC1 to skip \ the following LDA NEWB \ Extract bit 6 of the ship's NEWB flags, so A = 64 if AND #%01000000 \ bit 6 is set, or 0 if it is clear. Bit 6 is set if \ this ship is a cop, so A = 64 if we just killed a \ policeman, otherwise it is 0 ORA FIST \ Update our FIST flag ("fugitive/innocent status") to STA FIST \ at least the value in A, which will instantly make us \ a fugitive if we just shot the sheriff, but won't \ affect our status if the enemy wasn't a copper LDA DLY \ If we already have an in-flight message on-screen (in ORA MJ \ which case DLY > 0), or we are in witchspace (in BNE KS1S \ which case MJ > 0), jump to KS1S to skip showing an \ on-screen bounty for this kill LDY #10 \ Fetch byte #10 of the ship's blueprint, which is the LDA (XX0),Y \ low byte of the bounty awarded when this ship is BEQ KS1S \ killed (in Cr * 10), and if it's zero jump to KS1S as \ there is no on-screen bounty to display TAX \ Put the low byte of the bounty into X INY \ Fetch byte #11 of the ship's blueprint, which is the LDA (XX0),Y \ high byte of the bounty awarded (in Cr * 10), and put TAY \ it into Y JSR MCASH \ Call MCASH to add (Y X) to the cash pot LDA #0 \ Print control code 0 (current cash, right-aligned to JSR MESS \ width 9, then " CR", newline) as an in-flight message .KS1S JMP KS1 \ Process the killing of this ship (which removes this \ ship from its slot and shuffles all the other ships \ down to close up the gap) .MAC1 LDA TYPE \ If the ship we are processing is a planet or sun, BMI MA27 \ jump to MA27 to skip the following two instructions JSR FAROF \ If the ship we are processing is a long way away (its BCC KS1S \ distance in any one direction is > 224, jump to KS1S \ to remove the ship from our local bubble, as it's just \ left the building .MA27 LDY #31 \ Fetch the ship's explosion/killed state from byte #31 LDA INWK+31 \ and copy it to byte #31 in INF (so the ship's data in STA (INF),Y \ K% gets updated) LDX XSAV \ We're done processing this ship, so fetch the ship's \ slot number, which we saved in XSAV back at the start \ of the loop INX \ Increment the slot number to move on to the next slot JMP MAL1 \ And jump back up to the beginning of the loop to get \ the next ship in the local bubble for processing
Name: Main flight loop (Part 13 of 16) [View individually] Type: Subroutine [Compare versions] Category: Main loop Summary: Show energy bomb effect, charge shields and energy banks Deep dive: Program flow of the main game loop Scheduling tasks with the main loop counter
The main flight loop covers most of the flight-specific aspects of Elite. This section covers the following: * Show energy bomb effect (if applicable) * Charge shields and energy banks (every 7 iterations of the main loop)
.MA18 LDA BOMB \ If we set off our energy bomb (see MA24 above), then BPL MA77 \ BOMB is now negative, so this skips to MA21 if our \ energy bomb is not going off ASL BOMB \ We set off our energy bomb, so rotate BOMB to the \ left by one place. BOMB was rotated left once already \ during this iteration of the main loop, back at MA24, \ so if this is the first pass it will already be \ %11111110, and this will shift it to %11111100 - so \ if we set off an energy bomb, it stays activated \ (BOMB > 0) for four iterations of the main loop JSR WSCAN \ Call WSCAN to wait for the vertical sync, so the whole \ screen gets drawn and the following palette change \ won't kick in while the screen is still refreshing LDA #%00110000 \ Set the palette byte at SHEILA &21 to map logical STA VIA+&21 \ colour 0 to physical colour 7 (white), but with only \ one mapping (rather than the 7 mappings required to \ do the mapping properly). This makes the space screen \ flash with black and white stripes. See p.382 of the \ Advanced User Guide for details of why this single \ palette change creates a special effect .MA77 LDA MCNT \ Fetch the main loop counter and calculate MCNT mod 7, AND #7 \ jumping to MA22 if it is non-zero (so the following BNE MA22 \ code only runs every 8 iterations of the main loop) LDX ENERGY \ Fetch our ship's energy levels and skip to b if bit 7 BPL b \ is not set, i.e. only charge the shields from the \ energy banks if they are at more than 50% charge LDX ASH \ Call SHD to recharge our aft shield and update the JSR SHD \ shield status in ASH STX ASH LDX FSH \ Call SHD to recharge our forward shield and update JSR SHD \ the shield status in FSH STX FSH .b SEC \ Set A = ENERGY + ENGY + 1, so our ship's energy LDA ENGY \ level goes up by 2 if we have an energy unit fitted, ADC ENERGY \ otherwise it goes up by 1 BCS P%+5 \ If the value of A did not overflow (the maximum STA ENERGY \ energy level is &FF), then store A in ENERGY
Name: Main flight loop (Part 14 of 16) [View individually] Type: Subroutine [Compare versions] Category: Main loop Summary: Spawn a space station if we are close enough to the planet Deep dive: Program flow of the main game loop Scheduling tasks with the main loop counter Ship data blocks
The main flight loop covers most of the flight-specific aspects of Elite. This section covers the following: * Spawn a space station if we are close enough to the planet (every 32 iterations of the main loop)
LDA MJ \ If we are in witchspace, jump down to MA23S to skip BNE MA23S \ the following, as there are no space stations in \ witchspace LDA MCNT \ Fetch the main loop counter and calculate MCNT mod 32, AND #31 \ jumping to MA93 if it is on-zero (so the following BNE MA93 \ code only runs every 32 iterations of the main loop LDA SSPR \ If we are inside the space station safe zone, jump to BNE MA23S \ MA23S to skip the following, as we already have a \ space station and don't need another TAY \ Set Y = A = 0 (A is 0 as we didn't branch with the \ previous BNE instruction) JSR MAS2 \ Call MAS2 to calculate the largest distance to the BNE MA23S \ planet in any of the three axes, and if it's \ non-zero, jump to MA23S to skip the following, as we \ are too far from the planet to bump into a space \ station \ We now want to spawn a space station, so first we \ need to set up a ship data block for the station in \ INWK that we can then pass to NWSPS to add a new \ station to our bubble of universe. We do this by \ copying the planet data block from K% to INWK so we \ can work on it, but we only need the first 29 bytes, \ as we don't need to worry about bytes #29 to #35 \ for planets (as they don't have rotation counters, \ AI, explosions, missiles, a ship line heap or energy \ levels) LDX #28 \ So we set a counter in X to copy 29 bytes from K%+0 \ to K%+28 .MAL4 LDA K%,X \ Load the X-th byte of K% and store in the X-th byte STA INWK,X \ of the INWK workspace DEX \ Decrement the loop counter BPL MAL4 \ Loop back for the next byte until we have copied the \ first 28 bytes of K% to INWK \ We now check the distance from our ship (at the \ origin) towards the planet's surface, by adding the \ planet's nosev vector to the planet's centre at \ (x, y, z) and checking our distance to the end \ point along the relevant axis INX \ Set X = 0 (as we ended the above loop with X as &FF) LDY #9 \ Call MAS1 with X = 0, Y = 9 to do the following: JSR MAS1 \ \ (x_sign x_hi x_lo) += (nosev_x_hi nosev_x_lo) * 2 \ \ A = |x_hi| BNE MA23S \ If A > 0, jump to MA23S to skip the following, as we \ are too far from the planet in the x-direction to \ bump into a space station LDX #3 \ Call MAS1 with X = 3, Y = 11 to do the following: LDY #11 \ JSR MAS1 \ (y_sign y_hi y_lo) += (nosev_y_hi nosev_y_lo) * 2 \ \ A = |y_hi| BNE MA23S \ If A > 0, jump to MA23S to skip the following, as we \ are too far from the planet in the y-direction to \ bump into a space station LDX #6 \ Call MAS1 with X = 6, Y = 13 to do the following: LDY #13 \ JSR MAS1 \ (z_sign z_hi z_lo) += (nosev_z_hi nosev_z_lo) * 2 \ \ A = |z_hi| BNE MA23S \ If A > 0, jump to MA23S to skip the following, as we \ are too far from the planet in the z-direction to \ bump into a space station LDA #192 \ Call FAROF2 to compare x_hi, y_hi and z_hi with 192, JSR FAROF2 \ which will set the C flag if all three are < 192, or \ clear the C flag if any of them are >= 192 BCC MA23S \ Jump to MA23S if any one of x_hi, y_hi or z_hi are \ >= 192 (i.e. they must all be < 192 for us to be near \ enough to the planet to bump into a space station) JSR WPLS \ Call WPLS to remove the sun from the screen, as we \ can't have both the sun and the space station at the \ same time JSR NWSPS \ Add a new space station to our local bubble of \ universe .MA23S JMP MA23 \ Jump to MA23 to skip the following planet and sun \ altitude checks
Name: Main flight loop (Part 15 of 16) [View individually] Type: Subroutine [Compare versions] Category: Main loop Summary: Perform altitude checks with the planet and sun and process fuel scooping if appropriate Deep dive: Program flow of the main game loop Scheduling tasks with the main loop counter
The main flight loop covers most of the flight-specific aspects of Elite. This section covers the following: * Perform an altitude check with the planet (every 32 iterations of the main loop, on iteration 10 of each 32) * Perform an an altitude check with the sun and process fuel scooping (every 32 iterations of the main loop, on iteration 20 of each 32)
.MA22 LDA MJ \ If we are in witchspace, jump down to MA23S to skip BNE MA23S \ the following, as there are no planets or suns to \ bump into in witchspace LDA MCNT \ Fetch the main loop counter and calculate MCNT mod 32, AND #31 \ which tells us the position of this loop in each block \ of 32 iterations .MA93 CMP #10 \ If this is the tenth iteration in this block of 32, BNE MA29 \ do the following, otherwise jump to MA29 to skip the \ planet altitude check and move on to the sun distance \ check LDA #50 \ If our energy bank status in ENERGY is >= 50, skip CMP ENERGY \ printing the following message (so the message is BCC P%+6 \ only shown if our energy is low) ASL A \ Print recursive token 100 ("ENERGY LOW{beep}") as an JSR MESS \ in-flight message LDY #&FF \ Set our altitude in ALTIT to &FF, the maximum STY ALTIT INY \ Set Y = 0 JSR m \ Call m to calculate the maximum distance to the \ planet in any of the three axes, returned in A BNE MA23 \ If A > 0 then we are a fair distance away from the \ planet in at least one axis, so jump to MA23 to skip \ the rest of the altitude check JSR MAS3 \ Set A = x_hi^2 + y_hi^2 + z_hi^2, so using Pythagoras \ we now know that A now contains the square of the \ distance between our ship (at the origin) and the \ centre of the planet at (x_hi, y_hi, z_hi) BCS MA23 \ If the C flag was set by MAS3, then the result \ overflowed (was greater than &FF) and we are still a \ fair distance from the planet, so jump to MA23 as we \ haven't crashed into the planet SBC #36 \ Subtract 36 from x_hi^2 + y_hi^2 + z_hi^2. The radius \ of the planet is defined as 6 units and 6^2 = 36, so \ A now contains the high byte of our altitude above \ the planet surface, squared BCC MA28 \ If A < 0 then jump to MA28 as we have crashed into \ the planet STA R \ We are getting close to the planet, so we need to JSR LL5 \ work out how close. We know from the above that A \ contains our altitude squared, so we store A in R \ and call LL5 to calculate: \ \ Q = SQRT(R Q) = SQRT(A Q) \ \ Interestingly, Q doesn't appear to be set to 0 for \ this calculation, so presumably this doesn't make a \ difference LDA Q \ Store the result in ALTIT, our altitude STA ALTIT BNE MA23 \ If our altitude is non-zero then we haven't crashed, \ so jump to MA23 to skip to the next section .MA28 JMP DEATH \ If we get here then we just crashed into the planet \ or got too close to the sun, so jump to DEATH to start \ the funeral preparations and return from the main \ flight loop using a tail call .MA29 CMP #15 \ If this is the 15th iteration in this block of 32, BNE MA33 \ do the following, otherwise jump to MA33 to skip the \ docking computer manoeuvring LDA auto \ If auto is zero, then the docking computer is not BEQ MA23 \ activated, so jump to MA33 to skip the \ docking computer manoeuvring LDA #123 \ Set A = 123 and jump down to MA34 to print token 123 BNE MA34 \ ("DOCKING COMPUTERS ON") as an in-flight message .MA33 CMP #20 \ If this is the 20th iteration in this block of 32, BNE MA23 \ do the following, otherwise jump to MA23 to skip the \ sun altitude check LDA #30 \ Set CABTMP to 30, the cabin temperature in deep space STA CABTMP \ (i.e. one notch on the dashboard bar) LDA SSPR \ If we are inside the space station safe zone, jump to BNE MA23 \ MA23 to skip the following, as we can't have both the \ sun and space station at the same time, so we clearly \ can't be flying near the sun LDY #NI% \ Set Y to NI%, which is the offset in K% for the sun's \ data block, as the second block at K% is reserved for \ the sun (or space station) JSR MAS2 \ Call MAS2 to calculate the largest distance to the BNE MA23 \ sun in any of the three axes, and if it's non-zero, \ jump to MA23 to skip the following, as we are too far \ from the sun for scooping or temperature changes JSR MAS3 \ Set A = x_hi^2 + y_hi^2 + z_hi^2, so using Pythagoras \ we now know that A now contains the square of the \ distance between our ship (at the origin) and the \ heart of the sun at (x_hi, y_hi, z_hi) EOR #%11111111 \ Invert A, so A is now small if we are far from the \ sun and large if we are close to the sun, in the \ range 0 = far away to &FF = extremely close, ouch, \ hot, hot, hot! ADC #30 \ Add the minimum cabin temperature of 30, so we get \ one of the following: \ \ * If the C flag is clear, A contains the cabin \ temperature, ranging from 30 to 255, that's hotter \ the closer we are to the sun \ \ * If the C flag is set, the addition has rolled over \ and the cabin temperature is over 255 STA CABTMP \ Store the updated cabin temperature BCS MA28 \ If the C flag is set then jump to MA28 to die, as \ our temperature is off the scale CMP #&E0 \ If the cabin temperature < 224 then jump to MA23 to BCC MA23 \ to skip fuel scooping, as we aren't close enough LDA BST \ If we don't have fuel scoops fitted, jump to BA23 to BEQ MA23 \ skip fuel scooping, as we can't scoop without fuel \ scoops LDA DELT4+1 \ We are now successfully fuel scooping, so it's time LSR A \ to work out how much fuel we're scooping. Fetch the \ high byte of DELT4, which contains our current speed \ divided by 4, and halve it to get our current speed \ divided by 8 (so it's now a value between 1 and 5, as \ our speed is normally between 1 and 40). This gives \ us the amount of fuel that's being scooped in A, so \ the faster we go, the more fuel we scoop, and because \ the fuel levels are stored as 10 * the fuel in light \ years, that means we just scooped between 0.1 and 0.5 \ light years of free fuel ADC QQ14 \ Set A = A + the current fuel level * 10 (from QQ14) CMP #70 \ If A > 70 then set A = 70 (as 70 is the maximum fuel BCC P%+4 \ level, or 7.0 light years) LDA #70 STA QQ14 \ Store the updated fuel level in QQ14 LDA #160 \ Set A to token 160 ("FUEL SCOOPS ON") .MA34 JSR MESS \ Print the token in A as an in-flight message
Name: Main flight loop (Part 16 of 16) [View individually] Type: Subroutine [Compare versions] Category: Main loop Summary: Process laser pulsing, E.C.M. energy drain, call stardust routine Deep dive: Program flow of the main game loop
The main flight loop covers most of the flight-specific aspects of Elite. This section covers the following: * Process laser pulsing * Process E.C.M. energy drain * Jump to the stardust routine if we are in a space view * Return from the main flight loop
.MA23 LDA LAS2 \ If the current view has no laser, jump to MA16 to skip BEQ MA16 \ the following LDA LASCT \ If LASCT >= 8, jump to MA16 to skip the following, so CMP #8 \ for a pulse laser with a LASCT between 8 and 10, the BCS MA16 \ the laser stays on, but for a LASCT of 7 or less it \ gets turned off and stays off until LASCT reaches zero \ and the next pulse can start (if the fire button is \ still being pressed) \ \ For pulse lasers, LASCT gets set to 10 in ma1 above, \ and it decrements every vertical sync (50 times a \ second), so this means it pulses five times a second, \ with the laser being on for the first 3/10 of each \ pulse and off for the rest of the pulse \ \ If this is a beam laser, LASCT is 0 so we always keep \ going here. This means the laser doesn't pulse, but it \ does get drawn and removed every cycle, in a slightly \ different place each time, so the beams still flicker \ around the screen JSR LASLI2 \ Redraw the existing laser lines, which has the effect \ of removing them from the screen LDA #0 \ Set LAS2 to 0 so if this is a pulse laser, it will STA LAS2 \ skip over the above until the next pulse (this has no \ effect if this is a beam laser) .MA16 LDA ECMP \ If our E.C.M is not on, skip to MA69, otherwise keep BEQ MA69 \ going to drain some energy JSR DENGY \ Call DENGY to deplete our energy banks by 1 BEQ MA70 \ If we have no energy left, jump to MA70 to turn our \ E.C.M. off .MA69 LDA ECMA \ If an E.C.M is going off (our's or an opponent's) then BEQ MA66 \ keep going, otherwise skip to MA66 DEC ECMA \ Decrement the E.C.M. countdown timer, and if it has BNE MA66 \ reached zero, keep going, otherwise skip to MA66 .MA70 JSR ECMOF \ If we get here then either we have either run out of \ energy, or the E.C.M. timer has run down, so switch \ off the E.C.M. .MA66 LDA QQ11 \ If this is not a space view (i.e. QQ11 is non-zero) BNE oh \ then jump to oh to return from the main flight loop \ (as oh is an RTS) JMP STARS \ This is a space view, so jump to the STARS routine to \ process the stardust, and return from the main flight \ loop using a tail call
Name: SPIN [View individually] Type: Subroutine [Compare versions] Category: Universe Summary: Randomly spawn cargo from a destroyed ship
Arguments: Y The type of cargo to consider spawning (typically #PLT or #OIL) Other entry points: oh Contains an RTS SPIN2 Remove any randomness: spawn cargo of a specific type (given in X), and always spawn the number given in A
.SPIN JSR DORND \ Fetch a random number, and jump to oh if it is BPL oh \ positive (50% chance) PHA \ Store A on the stack so we can restore it after the \ following transfers TYA \ Copy the cargo type from Y into A and X TAX PLA \ Restore A from the stack LDY #0 \ Fetch the first byte of the hit ship's blueprint, AND (XX0),Y \ which determines the maximum number of bits of \ debris shown when the ship is destroyed, and AND \ with the random number we just fetched AND #15 \ Reduce the random number in A to the range 0-15 .SPIN2 STA CNT \ Store the result in CNT, so CNT contains a random \ number between 0 and the maximum number of bits of \ debris that this ship will release when destroyed \ (to a maximum of 15 bits of debris) .spl BEQ oh \ We're going to go round a loop using CNT as a counter \ so this checks whether the counter is zero and jumps \ to oh when it gets there (which might be straight \ away) LDA #0 \ Call SFS1 to spawn the specified cargo from the now JSR SFS1 \ deceased parent ship, giving the spawned canister an \ AI flag of 0 (no AI, no E.C.M., non-hostile) DEC CNT \ Decrease the loop counter BNE spl+2 \ Jump back up to the LDA &0 instruction above (this BPL \ is effectively a JMP as CNT will never be negative) .oh RTS \ Return from the subroutine
Save output/ELTA.bin
PRINT "ELITE A" PRINT "Assembled at ", ~CODE% PRINT "Ends at ", ~P% PRINT "Code size is ", ~(P% - CODE%) PRINT "Execute at ", ~LOAD% PRINT "Reload at ", ~LOAD_A% PRINT "S.ELTA ", ~CODE%, " ", ~P%, " ", ~LOAD%, " ", ~LOAD_A% SAVE "output/D.ELTA.bin", CODE%, P%, LOAD%