Skip to navigation

Elite on the BBC Micro

Elite A parasite source [Elite-A]

ELITE A FILE
CODE% = &1000 LOAD% = &1000 ORG CODE% LOAD_A% = LOAD%
Name: S1% [Show more] Type: Variable Category: Save and load Summary: The drive and directory number used when saving or loading a commander file Deep dive: Commander save files
Context: See this variable on its own page References: No direct references to this variable in this source file

The drive part of this string (the "0") is updated with the chosen drive in the QUS1 routine, but the directory part (the "E") is fixed. The variable is followed directly by the commander file at NA%, which starts with the commander name, so the full string at S1% is in the format ":0.E.JAMESON", which gives the full filename of the commander file.
.S1% EQUS ":0.E."
Name: NA% [Show more] Type: Variable Category: Save and load Summary: The data block for the last saved commander Deep dive: Commander save files The competition code
Context: See this variable on its own page References: This variable is used as follows: * CHECK calls NA% * DFAULT calls NA% * GTNMEW calls NA% * LOD calls NA% * SVE calls NA% * TR1 calls NA% * TRNME calls NA% * cmn calls NA%

Contains the last saved commander data, with the name at NA% and the data at NA%+8 onwards. The size of the data block is given in NT% (which also includes the two checksum bytes that follow this block). This block is initially set up with the default commander, which can be maxed out for testing purposes by setting Q% to TRUE. The commander's name is stored at NA%, and can be up to 7 characters long (the DFS filename limit). It is terminated with a carriage return character, ASCII 13. The offset of each byte within a saved commander file is also shown as #0, #1 and so on, so the kill tally, for example, is in bytes #71 and #72 of the saved file. The related variable name from the current commander block is also shown.
.NA% EQUS "NEWCOME" \ The current commander name, which defaults to NEWCOME EQUB 13 \ \ The commander name can be up to 7 characters (the DFS \ limit for filenames), and is terminated by a carriage \ return \ NA%+8 is the start of the commander data block \ \ This block contains the last saved commander data \ block. As the game is played it uses an identical \ block at location TP to store the current commander \ state, and that block is copied here when the game is \ saved. Conversely, when the game starts up, the block \ here is copied to TP, which restores the last saved \ commander when we die \ \ The initial state of this block defines the default \ commander. Q% can be set to TRUE to give the default \ commander lots of credits and equipment EQUB 0 \ TP = Mission status, #0 EQUB 20 \ QQ0 = Current system X-coordinate (Lave), #1 EQUB 173 \ QQ1 = Current system Y-coordinate (Lave), #2 EQUW &5A4A \ QQ21 = Seed s0 for system 0, galaxy 0 (Tibedied), #3-4 EQUW &0248 \ QQ21 = Seed s1 for system 0, galaxy 0 (Tibedied), #5-6 EQUW &B753 \ QQ21 = Seed s2 for system 0, galaxy 0 (Tibedied), #7-8 IF Q% EQUD &00CA9A3B \ CASH = Amount of cash (100,000,000 Cr), #9-12 ELSE EQUD &88130000 \ CASH = Amount of cash (500 Cr), #9-12 ENDIF EQUB 60+(15 AND Q%) \ QQ14 = Fuel level, #13 EQUB 0 \ COK = Competition flags, #14 EQUB 0 \ GCNT = Galaxy number, 0-7, #15 EQUB &9C AND Q% \ LASER = Front laser, #16 EQUB &9C AND Q% \ LASER+1 = Rear laser, #17 EQUB 0 \ LASER+2 = Left laser, #18 EQUB 0 \ LASER+3 = Right laser, #19 EQUB 0 \ This byte appears to be unused, #20 EQUB 8 AND Q% \ cmdr_type = Type of our current ship, #21 EQUB Q% \ CRGO = I.F.F. system, #22 EQUB 0 \ QQ20+0 = Amount of food in cargo hold, #23 EQUB 0 \ QQ20+1 = Amount of textiles in cargo hold, #24 EQUB 0 \ QQ20+2 = Amount of radioactives in cargo hold, #25 EQUB 0 \ QQ20+3 = Amount of slaves in cargo hold, #26 EQUB 0 \ QQ20+4 = Amount of liquor/Wines in cargo hold, #27 EQUB 0 \ QQ20+5 = Amount of luxuries in cargo hold, #28 EQUB 0 \ QQ20+6 = Amount of narcotics in cargo hold, #29 EQUB 0 \ QQ20+7 = Amount of computers in cargo hold, #30 EQUB 0 \ QQ20+8 = Amount of machinery in cargo hold, #31 EQUB 0 \ QQ20+9 = Amount of alloys in cargo hold, #32 EQUB 0 \ QQ20+10 = Amount of firearms in cargo hold, #33 EQUB 0 \ QQ20+11 = Amount of furs in cargo hold, #34 EQUB 0 \ QQ20+12 = Amount of minerals in cargo hold, #35 EQUB 0 \ QQ20+13 = Amount of gold in cargo hold, #36 EQUB 0 \ QQ20+14 = Amount of platinum in cargo hold, #37 EQUB 0 \ QQ20+15 = Amount of gem-stones in cargo hold, #38 EQUB 0 \ QQ20+16 = Amount of alien items in cargo hold, #39 EQUB Q% \ ECM = E.C.M. system, #40 EQUB Q% \ BST = Fuel scoops ("barrel status"), #41 EQUB Q% \ BOMB = Hyperspace unit, #42 EQUB Q% AND 1 \ ENGY = Energy/shield level, #43 EQUB Q% \ DKCMP = Docking computer, #44 EQUB Q% \ GHYP = Galactic hyperdrive, #45 EQUB Q% \ ESCP = Escape pod, #46 EQUW 0 \ cmdr_cour = Special cargo mission timer, #47 EQUB 0 \ cmdr_courx = Special cargo destination x-coord, #49 EQUB 0 \ cmdr_coury = Special cargo destination y-coord, #50 EQUB 0 \ NOMSL = Number of missiles, #51 EQUB 0 \ FIST = Legal status ("fugitive/innocent status"), #52 EQUB 0 \ AVL+0 = Market availability of food, #53 EQUB 15 \ AVL+1 = Market availability of textiles, #54 EQUB 17 \ AVL+2 = Market availability of radioactives, #55 EQUB 0 \ AVL+3 = Market availability of slaves, #56 EQUB 3 \ AVL+4 = Market availability of liquor/Wines, #57 EQUB 28 \ AVL+5 = Market availability of luxuries, #58 EQUB 14 \ AVL+6 = Market availability of narcotics, #59 EQUB 0 \ AVL+7 = Market availability of computers, #60 EQUB 0 \ AVL+8 = Market availability of machinery, #61 EQUB 10 \ AVL+9 = Market availability of alloys, #62 EQUB 0 \ AVL+10 = Market availability of firearms, #63 EQUB 17 \ AVL+11 = Market availability of furs, #64 EQUB 58 \ AVL+12 = Market availability of minerals, #65 EQUB 7 \ AVL+13 = Market availability of gold, #66 EQUB 9 \ AVL+14 = Market availability of platinum, #67 EQUB 8 \ AVL+15 = Market availability of gem-stones, #68 EQUB 0 \ AVL+16 = Market availability of alien items, #69 EQUB 0 \ QQ26 = Random byte that changes for each visit to a \ system, for randomising market prices, #70 EQUW 0 \ TALLY = Number of kills, #71-72 EQUB 32 \ SVC = Save count, #73
Name: CHK2 [Show more] Type: Variable Category: Save and load Summary: Second checksum byte for the saved commander data file Deep dive: Commander save files The competition code
Context: See this variable on its own page References: This variable is used as follows: * SVE calls CHK2

Second commander checksum byte. If the default commander is changed, a new checksum will be calculated and inserted by the elite-checksum.py script. The offset of this byte within a saved commander file is also shown (it's at byte #74).
.CHK2 EQUB &58 EOR &A9 \ The checksum value for the default commander, EOR'd \ with &A9 to make it harder to tamper with the checksum \ byte, #74
Name: CHK [Show more] Type: Variable Category: Save and load Summary: First checksum byte for the saved commander data file Deep dive: Commander save files The competition code
Context: See this variable on its own page References: This variable is used as follows: * DFAULT calls CHK * SVE calls CHK

Commander checksum byte. If the default commander is changed, a new checksum will be calculated and inserted by the elite-checksum.py script. The offset of this byte within a saved commander file is also shown (it's at byte #75).
.CHK EQUB &58 \ The checksum value for the default commander, #75
Name: tube_write [Show more] Type: Subroutine Category: Tube Summary: As the parasite, send a byte across the Tube to the I/O processor Deep dive: Tube communication in Elite-A
Context: See this subroutine on its own page References: This subroutine is called as follows: * CATS calls tube_write * CHPR calls tube_write * CLYNS calls tube_write * CPIX2 calls tube_write * DET1 calls tube_write * DIL2 calls tube_write * DILX calls tube_write * DKS1 calls tube_write * DKS4 calls tube_write * ECBLB calls tube_write * HANGER calls tube_write * HLOIN calls tube_write * LL30 calls tube_write * MSBAR calls tube_write * MT26 calls tube_write * PIXEL calls tube_write * RDKEY calls tube_write * SCAN calls tube_write * SPBLB calls tube_write * TT217 calls tube_write * TTX66 calls tube_write * UNWISE calls tube_write * WSCAN calls tube_write * read_0346 calls tube_write * scan_fire calls tube_write * update_pod calls tube_write * write_0346 calls tube_write

Tube communication in Elite-A uses the following protocol: Parasite -> I/O processor * Uses the FIFO 1 status and data registers to transmit the data * The parasite calls tube_write to send a byte to the I/O processor * The I/O processor calls tube_get to receive that byte from the parasite I/O processor -> Parasite * Uses the FIFO 2 status and data registers to transmit the data * The I/O processor calls tube_put to send a byte to the parasite * The parasite calls tube_read to receive that byte from the I/O processor This routine is called by the parasite to send a byte to the I/O processor. The code is identical to Acorn's MOS routine that runs on the parasite to implement OSWRCH across the Tube.
.tube_write BIT tube_r1s \ Check whether FIFO 1 is available for use, so we can \ use it to transmit a byte to the I/O processor. We do \ this by checking bit 6 of the FIFO 1 status register NOP \ Pause while the register is checked BVC tube_write \ If FIFO 1 is available for use then bit 6 of the \ status register will be set, so this loops back to \ tube_write until FIFO 1 is available for us to use STA tube_r1d \ FIFO 1 is available for use, so store the value we \ want to transmit in the FIFO 1 data register, so it \ gets sent to the I/O processor RTS \ Return from the subroutine
Name: tube_read [Show more] Type: Subroutine Category: Tube Summary: As the parasite, fetch a byte that's been sent over the Tube from the I/O processor Deep dive: Tube communication in Elite-A
Context: See this subroutine on its own page References: This subroutine is called as follows: * DKS1 calls tube_read * DKS4 calls tube_read * MT26 calls tube_read * RDKEY calls tube_read * TT217 calls tube_read * WSCAN calls tube_read * read_0346 calls tube_read * scan_fire calls tube_read

Tube communication in Elite-A uses the following protocol: Parasite -> I/O processor * Uses the FIFO 1 status and data registers to transmit the data * The parasite calls tube_write to send a byte to the I/O processor * The I/O processor calls tube_get to receive that byte from the parasite I/O processor -> Parasite * Uses the FIFO 2 status and data registers to transmit the data * The I/O processor calls tube_put to send a byte to the parasite * The parasite calls tube_read to receive that byte from the I/O processor This routine is called by the parasite to receive a byte from the I/O processor. The code is identical to Acorn's MOS routine that runs on the parasite to implement OSWRCH across the Tube (except this uses FIFO 2 instead of FIFO 1).
.tube_read BIT tube_r2s \ Check whether FIFO 2 has received a byte from the I/O \ processor (which it will have sent by calling its own \ tube_put routine). We do this by checking bit 7 of the \ FIFO 2 status register NOP \ Pause while the register is checked BPL tube_read \ If FIFO 2 has received a byte then bit 7 of the status \ register will be set, so this loops back to tube_read \ until FIFO 2 contains the byte transmitted from the \ I/O processor LDA tube_r2d \ Fetch the transmitted byte by reading the FIFO 2 data \ register into A RTS \ Return from the subroutine
Name: DOENTRY [Show more] Type: Subroutine Category: Flight Summary: Dock at the space station, show the ship hanger and work out any mission progression
Context: See this subroutine on its own page References: This subroutine is called as follows: * DOENTRYS calls DOENTRY
.DOENTRY LDA #0 \ Set dockedp = 0 to indicate we are docked STA dockedp LDA #&FF \ Call SCRAM to set save_lock to &FF (i.e. we have just JSR SCRAM \ docked and have unsaved changes) and set the break \ handler JSR RES2 \ Reset a number of flight variables and workspaces JSR HFS1 \ Show the space station docking tunnel JSR HALL \ Show the ship hanger LDY #44 \ Wait for 44/50 of a second (0.88 seconds) JSR DELAY JSR cour_dock \ Update the current special cargo delivery mission LDA TP \ Fetch bits 0 and 1 of TP, and if they are non-zero AND #%00000011 \ (i.e. mission 1 is either in progress or has been BNE EN1 \ completed), skip to EN1 LDA TALLY+1 \ If the high byte of TALLY is zero (so we have a combat BEQ EN4 \ rank below Competent), jump to EN4 as we are not yet \ good enough to qualify for a mission LDA GCNT \ Fetch the galaxy number into A, and if any of bits 1-7 LSR A \ are set (i.e. A > 1), jump to EN4 as mission 1 can BNE EN4 \ only be triggered in the first two galaxies JMP BRIEF \ If we get here, mission 1 hasn't started, we have \ reached a combat rank of Competent, and we are in \ galaxy 0 or 1 (shown in-game as galaxy 1 or 2), so \ it's time to start mission 1 by calling BRIEF .EN1 \ If we get here then mission 1 is either in progress or \ has been completed CMP #%00000011 \ If bits 0 and 1 are not both set, then jump to EN2 BNE EN2 JMP DEBRIEF \ Bits 0 and 1 are both set, so mission 1 is both in \ progress and has been completed, which means we have \ only just completed it, so jump to DEBRIEF to end the \ mission get our reward .EN2 \ Mission 1 has been completed, so now to check for \ mission 2 LDA TP \ Extract bits 0-3 of TP into A AND #%00001111 CMP #%00000010 \ If mission 1 is complete and no longer in progress, BNE EN3 \ and mission 2 is not yet started, then bits 0-3 of TP \ will be %0010, so this jumps to EN3 if this is not the \ case LDA TALLY+1 \ If the high byte of TALLY is < 5 (so we have a combat CMP #5 \ rank that is less than 3/8 of the way from Dangerous BCC EN4 \ to Deadly), jump to EN4 as our rank isn't high enough \ for mission 2 LDA GCNT \ Fetch the galaxy number into A CMP #2 \ If this is not galaxy 2 (shown in-game as galaxy 3), BNE EN4 \ jump to EN4 as we can only start mission 2 in the \ third galaxy JMP BRIEF2 \ If we get here, mission 1 is complete and no longer in \ progress, mission 2 hasn't started, we have reached a \ combat rank of 3/8 of the way from Dangerous to \ Deadly, and we are in galaxy 2 (shown in-game as \ galaxy 3), so it's time to start mission 2 by calling \ BRIEF2 .EN3 CMP #%00000110 \ If mission 1 is complete and no longer in progress, BNE EN5 \ and mission 2 has started but we have not yet been \ briefed and picked up the plans, then bits 0-3 of TP \ will be %0110, so this jumps to EN5 if this is not the \ case LDA GCNT \ Fetch the galaxy number into A CMP #2 \ If this is not galaxy 2 (shown in-game as galaxy 3), BNE EN4 \ jump to EN4 as we can only start mission 2 in the \ third galaxy LDA QQ0 \ Set A = the current system's galactic x-coordinate CMP #215 \ If A <> 215 then jump to EN4 BNE EN4 LDA QQ1 \ Set A = the current system's galactic y-coordinate CMP #84 \ If A <> 84 then jump to EN4 BNE EN4 JMP BRIEF3 \ If we get here, mission 1 is complete and no longer in \ progress, mission 2 has started but we have not yet \ picked up the plans, and we have just arrived at \ Ceerdi at galactic coordinates (215, 84), so we jump \ to BRIEF3 to get a mission brief and pick up the plans \ that we need to carry to Birera .EN5 CMP #%00001010 \ If mission 1 is complete and no longer in progress, BNE EN4 \ and mission 2 has started and we have picked up the \ plans, then bits 0-3 of TP will be %1010, so this \ jumps to EN5 if this is not the case LDA GCNT \ Fetch the galaxy number into A CMP #2 \ If this is not galaxy 2 (shown in-game as galaxy 3), BNE EN4 \ jump to EN4 as we can only start mission 2 in the \ third galaxy LDA QQ0 \ Set A = the current system's galactic x-coordinate CMP #63 \ If A <> 63 then jump to EN4 BNE EN4 LDA QQ1 \ Set A = the current system's galactic y-coordinate CMP #72 \ If A <> 72 then jump to EN4 BNE EN4 JMP DEBRIEF2 \ If we get here, mission 1 is complete and no longer in \ progress, mission 2 has started and we have picked up \ the plans, and we have just arrived at Birera at \ galactic coordinates (63, 72), so we jump to DEBRIEF2 \ to end the mission and get our reward .EN4 JMP BAY \ If we get here them we didn't start or any missions, \ so jump to BAY to go to the docking bay (i.e. show the \ Status Mode screen)
Name: SCRAM [Show more] Type: Subroutine Category: Loader Summary: Set the save_lock variable and break handler
Context: See this subroutine on its own page References: This subroutine is called as follows: * DOENTRY calls SCRAM

Arguments: A Set the save_lock flag as follows: * 0 = this is a new game, so there are no unsaved changes in the commander file * &FF = we just docked, so there are unsaved changes in the commander file
.SCRAM STA save_lock \ Set the save_lock variable to the value in A (which \ will be either 0 or &FF) \ Fall through into BRKBK to set the standard BRKV \ handler for the game and return from the subroutine
Name: BRKBK [Show more] Type: Subroutine Category: Save and load Summary: Set the standard BRKV handler for the game
Context: See this subroutine on its own page References: This subroutine is called as follows: * BEGIN calls BRKBK * INBAY calls BRKBK * SVE calls BRKBK
.BRKBK LDA #LO(BRBR) \ Set BRKV to point to the BRBR routine STA BRKV LDA #HI(BRBR) STA BRKV+1 RTS \ Return from the subroutine
Name: write_msg3 [Show more] Type: Subroutine Category: Text Summary: Print an extended recursive token from the msg_3 token table Deep dive: The Encyclopedia Galactica
Context: See this subroutine on its own page References: This subroutine is called as follows: * controls calls write_msg3 * equip_data calls write_msg3 * menu calls write_msg3 * ships_ag calls write_msg3 * write_card calls write_msg3

Arguments: A The recursive token to be printed, in the range 0-255 Returns: A A is preserved Y Y is preserved V(1 0) V(1 0) is preserved
.write_msg3 PHA \ Store A on the stack, so we can retrieve it later TAX \ Copy the token number from A into X TYA \ Store Y on the stack PHA LDA V \ Store V(1 0) on the stack PHA LDA V+1 PHA LDA #LO(msg_3) \ Set V to the low byte of msg_3 STA V LDA #HI(msg_3) \ Set A to the high byte of msg_3 BNE DTEN \ Call DTEN to print token number X from the msg_3 \ table and restore the values of A, Y and V(1 0) from \ the stack, returning from the subroutine using a tail \ call (this BNE is effectively a JMP as A is never \ zero)
Name: DETOK3 [Show more] Type: Subroutine Category: Text Summary: Print an extended recursive token from the RUTOK token table Deep dive: Extended system descriptions Extended text tokens
Context: See this subroutine on its own page References: This subroutine is called as follows: * PDESC calls DETOK3

Arguments: A The recursive token to be printed, in the range 0-255 Returns: A A is preserved Y Y is preserved V(1 0) V(1 0) is preserved
.DETOK3 PHA \ Store A on the stack, so we can retrieve it later TAX \ Copy the token number from A into X TYA \ Store Y on the stack PHA LDA V \ Store V(1 0) on the stack PHA LDA V+1 PHA LDA #LO(RUTOK) \ Set V to the low byte of RUTOK STA V LDA #HI(RUTOK) \ Set A to the high byte of RUTOK BNE DTEN \ Call DTEN to print token number X from the RUTOK \ table and restore the values of A, Y and V(1 0) from \ the stack, returning from the subroutine using a tail \ call (this BNE is effectively a JMP as A is never \ zero)
Name: MT27 [Show more] Type: Subroutine Category: Text Summary: Print the captain's name during mission briefings Deep dive: Extended text tokens
Context: See this subroutine on its own page References: This subroutine is called as follows: * JMTB calls MT27

This routine prints the following tokens, depending on the galaxy number: * Token 217 ("CURRUTHERS") in galaxy 0 * Token 218 ("FOSDYKE SMYTHE") in galaxy 1 * Token 219 ("FORTESQUE") in galaxy 2 This is used when printing extended token 213 as part of the mission briefings, which looks like this when printed: Commander {commander name}, I am Captain {mission captain's name} of Her Majesty's Space Navy where {mission captain's name} is replaced by one of the names above.
.MT27 LDA #217 \ Set A = 217, so when we fall through into MT28, the \ 217 gets added to the current galaxy number, so the \ extended token that is printed is 217-219 (as this is \ only called in galaxies 0 through 2) EQUB &2C \ Skip the next instruction by turning it into \ &2C &A9 &DC, or BIT &DCA9, which does nothing apart \ from affect the flags
Name: MT28 [Show more] Type: Subroutine Category: Text Summary: Print the location hint during the mission 1 briefing Deep dive: Extended text tokens
Context: See this subroutine on its own page References: This subroutine is called as follows: * JMTB calls MT28

This routine prints the following tokens, depending on the galaxy number: * Token 220 ("WAS LAST SEEN AT {single cap}REESDICE") in galaxy 0 * Token 221 ("IS BELIEVED TO HAVE JUMPED TO THIS GALAXY") in galaxy 1 This is used when printing extended token 10 as part of the mission 1 briefing, which looks like this when printed: It went missing from our ship yard on Xeer five months ago and {mission 1 location hint} where {mission 1 location hint} is replaced by one of the names above.
.MT28 LDA #220 \ Set A = galaxy number in GCNT + 220, which is in the CLC \ range 220-221, as this is only called in galaxies 0 ADC GCNT \ and 1 \ Fall through into DETOK to print extended token \ 220-221
Name: DETOK [Show more] Type: Subroutine Category: Text Summary: Print an extended recursive token from the TKN1 token table Deep dive: Extended text tokens
Context: See this subroutine on its own page References: This subroutine is called as follows: * BRIS calls DETOK * BRP calls DETOK * CATS calls DETOK * DELT calls DETOK * DETOK2 calls DETOK * GTDRV calls DETOK * GTNMEW calls DETOK * HME2 calls DETOK * MT17 calls DETOK * PDESC calls DETOK * STATUS calls DETOK * SVE calls DETOK * TITLE calls DETOK * TT102 calls DETOK * confirm calls DETOK * cour_buy calls DETOK * cour_dock calls DETOK * sell_yn calls DETOK * DETOK3 calls entry point DTEN * write_msg3 calls entry point DTEN

Arguments: A The recursive token to be printed, in the range 1-255 Returns: A A is preserved Y Y is preserved V(1 0) V(1 0) is preserved Other entry points: DTEN Print recursive token number X from the token table pointed to by (A V), used to print tokens from the RUTOK table via calls to DETOK3
.DETOK PHA \ Store A on the stack, so we can retrieve it later TAX \ Copy the token number from A into X TYA \ Store Y on the stack PHA LDA V \ Store V(1 0) on the stack PHA LDA V+1 PHA LDA #LO(TKN1) \ Set V to the low byte of TKN1 STA V LDA #HI(TKN1) \ Set A to the high byte of TKN1, so when we fall \ through into DTEN, V(1 0) gets set to the address of \ the TKN1 token table .DTEN STA V+1 \ Set the high byte of V(1 0) to A, so V(1 0) now points \ to the start of the token table to use LDY #0 \ First, we need to work our way through the table until \ we get to the token that we want to print. Tokens are \ delimited by #VE, and VE EOR VE = 0, so we work our \ way through the table in, counting #VE delimiters \ until we have passed X of them, at which point we jump \ down to DTL2 to do the actual printing. So first, we \ set a counter Y to point to the character offset as we \ scan through the table .DTL1 LDA (V),Y \ Load the character at offset Y in the token table, \ which is the next character from the token table BNE DT1 \ If the result is non-zero, then this is a character \ in a token rather than the delimiter (which is #VE), \ so jump to DT1 DEX \ We have just scanned the end of a token, so decrement \ X, which contains the token number we are looking for BEQ DTL2 \ If X has now reached zero then we have found the token \ we are looking for, so jump down to DTL2 to print it .DT1 INY \ Otherwise this isn't the token we are looking for, so \ increment the character pointer BNE DTL1 \ If Y hasn't just wrapped around to 0, loop back to \ DTL1 to process the next character INC V+1 \ We have just crossed into a new page, so increment \ V+1 so that V points to the start of the new page BNE DTL1 \ Jump back to DTL1 to process the next character (this \ BNE is effectively a JMP as V+1 won't reach zero \ before we reach the end of the token table) .DTL2 INY \ We just detected the delimiter byte before the token \ that we want to print, so increment the character \ pointer to point to the first character of the token, \ rather than the delimiter BNE P%+4 \ If Y hasn't just wrapped around to 0, skip the next \ instruction INC V+1 \ We have just crossed into a new page, so increment \ V+1 so that V points to the start of the new page LDA (V),Y \ Load the character at offset Y in the token table, \ which is the next character from the token we want to \ print BEQ DTEX \ If the result is zero, then this is the delimiter at \ the end of the token to print (which is #VE), so jump \ to DTEX to return from the subroutine, as we are done \ printing JSR DETOK2 \ Otherwise call DETOK2 to print this part of the token JMP DTL2 \ Jump back to DTL2 to process the next character .DTEX PLA \ Restore V(1 0) from the stack, so it is preserved STA V+1 \ through calls to this routine PLA STA V PLA \ Restore Y from the stack, so it is preserved through TAY \ calls to this routine PLA \ Restore A from the stack, so it is preserved through \ calls to this routine RTS \ Return from the subroutine
Name: DETOK2 [Show more] Type: Subroutine Category: Text Summary: Print an extended text token (1-255) Deep dive: Extended text tokens
Context: See this subroutine on its own page References: This subroutine is called as follows: * DETOK calls DETOK2 * PDESC calls DETOK2 * write_card calls entry point DT3 * MT18 calls entry point DTS * write_card calls entry point DTS * write_card calls entry point msg_pairs

Arguments: A The token to be printed (1-255) Returns: A A is preserved Y Y is preserved V(1 0) V(1 0) is preserved Other entry points: DTS Print a single letter in the correct case DT3 Print the jump token given in A (where A is in the range 0 to 31) msg_pairs Print the extended two-letter token in A (where A is in the range 215 to 255)
.DETOK2 CMP #32 \ If A < 32 then this is a jump token, so skip to DT3 to BCC DT3 \ process it BIT DTW3 \ If bit 7 of DTW3 is clear, then extended tokens are BPL DT8 \ enabled, so jump to DT8 to process them \ If we get there then this is not a jump token and \ extended tokens are not enabled, so we can call the \ standard text token routine at TT27 to print the token TAX \ Copy the token number from A into X TYA \ Store Y on the stack PHA LDA V \ Store V(1 0) on the stack PHA LDA V+1 PHA TXA \ Copy the token number from X back into A JSR TT27 \ Call TT27 to print the text token JMP DT7 \ Jump to DT7 to restore V(1 0) and Y from the stack and \ return from the subroutine .DT8 \ If we get here then this is not a jump token and \ extended tokens are enabled CMP #'[' \ If A < ASCII "[" (i.e. A <= ASCII "Z", or 90) then BCC DTS \ this is a printable ASCII character, so jump down to \ DTS to print it CMP #129 \ If A < 129, so A is in the range 91-128, jump down to BCC DT6 \ DT6 to print a randomised token from the MTIN table CMP #215 \ If A < 215, so A is in the range 129-214, jump to BCC DETOK \ DETOK as this is a recursive token, returning from the \ subroutine using a tail call \ If we get here then A >= 215, so this is a two-letter \ token from the extended TKN2/QQ16 table .msg_pairs SBC #215 \ Subtract 215 to get a token number in the range 0-12 \ (the C flag is set as we passed through the BCC above, \ so this subtraction is correct) ASL A \ Set A = A * 2, so it can be used as a pointer into the \ two-letter token tables at TKN2 and QQ16 PHA \ Store A on the stack, so we can restore it for the \ second letter below TAX \ Fetch the first letter of the two-letter token from LDA TKN2,X \ TKN2, which is at TKN2 + X JSR DTS \ Call DTS to print it PLA \ Restore A from the stack and transfer it into X TAX LDA TKN2+1,X \ Fetch the second letter of the two-letter token from \ TKN2, which is at TKN2 + X + 1, and fall through into \ DTS to print it .DTS CMP #'A' \ If A < ASCII "A", jump to DT9 to print this as ASCII BCC DT9 BIT DTW6 \ If bit 7 of DTW6 is set, then lower case has been BMI DT10 \ enabled by jump token 13, {lower case}, so jump to \ DT10 to apply the lower case and single cap masks BIT DTW2 \ If bit 7 of DTW2 is set, then we are not currently BMI DT5 \ printing a word, so jump to DT5 so we skip the setting \ of lower case in Sentence Case (which we only want to \ do when we are already printing a word) .DT10 ORA DTW1 \ Convert the character to lower case if DTW1 is \ %00100000 (i.e. if we are in {sentence case} mode) .DT5 AND DTW8 \ Convert the character to upper case if DTW8 is \ %11011111 (i.e. after a {single cap} token) .DT9 JMP DASC \ Jump to DASC to print the ASCII character in A, \ returning from the routine using a tail call .DT3 \ If we get here then the token number in A is in the \ range 1 to 32, so this is a jump token that should \ call the corresponding address in the jump table at \ JMTB TAX \ Copy the token number from A into X TYA \ Store Y on the stack PHA LDA V \ Store V(1 0) on the stack PHA LDA V+1 PHA TXA \ Copy the token number from X back into A ASL A \ Set A = A * 2, so it can be used as a pointer into the \ jump table at JMTB, though because the original range \ of values is 1-32, so the doubled range is 2-64, we \ need to take the offset into the jump table from \ JMTB-2 rather than JMTB TAX \ Copy the doubled token number from A into X LDA JMTB-2,X \ Set DTM(2 1) to the X-th address from the table at STA DTM+1 \ JTM-2, which modifies the JSR DASC instruction at LDA JMTB-1,X \ label DTM below so that it calls the subroutine at the STA DTM+2 \ relevant address from the JMTB table TXA \ Copy the doubled token number from X back into A LSR A \ Halve A to get the original token number .DTM JSR DASC \ Call the relevant JMTB subroutine, as this instruction \ will have been modified by the above to point to the \ relevant address .DT7 PLA \ Restore V(1 0) from the stack, so it is preserved STA V+1 \ through calls to this routine PLA STA V PLA \ Restore Y from the stack, so it is preserved through TAY \ calls to this routine RTS \ Return from the subroutine .DT6 \ If we get here then the token number in A is in the \ range 91-128, which means we print a randomly picked \ token from the token range given in the corresponding \ entry in the MTIN table STA SC \ Store the token number in SC TYA \ Store Y on the stack PHA LDA V \ Store V(1 0) on the stack PHA LDA V+1 PHA JSR DORND \ Set X to a random number TAX LDA #0 \ Set A to 0, so we can build a random number from 0 to \ 4 in A plus the C flag, with each number being equally \ likely CPX #51 \ Add 1 to A if X >= 51 ADC #0 CPX #102 \ Add 1 to A if X >= 102 ADC #0 CPX #153 \ Add 1 to A if X >= 153 ADC #0 CPX #204 \ Set the C flag if X >= 204 LDX SC \ Fetch the token number from SC into X, so X is now in \ the range 91-128 ADC MTIN-91,X \ Set A = MTIN-91 + token number (91-128) + random (0-4) \ = MTIN + token number (0-37) + random (0-4) JSR DETOK \ Call DETOK to print the extended recursive token in A JMP DT7 \ Jump to DT7 to restore V(1 0) and Y from the stack and \ return from the subroutine using a tail call
Name: MT1 [Show more] Type: Subroutine Category: Text Summary: Switch to ALL CAPS when printing extended tokens Deep dive: Extended text tokens
Context: See this subroutine on its own page References: This subroutine is called as follows: * JMTB calls MT1 * controls calls MT1 * equip_data calls MT1 * menu calls MT1 * ships_ag calls MT1 * write_card calls MT1

This routine sets the following: * DTW1 = %00000000 (do not change case to lower case) * DTW6 = %00000000 (lower case is not enabled)
.MT1 LDA #%00000000 \ Set A = %00000000, so when we fall through into MT2, \ both DTW1 and DTW6 get set to %00000000 EQUB &2C \ Skip the next instruction by turning it into \ &2C &A9 &20, or BIT &20A9, which does nothing apart \ from affect the flags
Name: MT2 [Show more] Type: Subroutine Category: Text Summary: Switch to Sentence Case when printing extended tokens Deep dive: Extended text tokens
Context: See this subroutine on its own page References: This subroutine is called as follows: * JMTB calls MT2 * TTX66 calls MT2 * controls calls MT2 * equip_data calls MT2 * menu calls MT2 * write_card calls MT2

This routine sets the following: * DTW1 = %00100000 (apply lower case to the second letter of a word onwards) * DTW6 = %00000000 (lower case is not enabled)
.MT2 LDA #%00100000 \ Set DTW1 = %00100000 STA DTW1 LDA #00000000 \ Set DTW6 = %00000000 STA DTW6 RTS \ Return from the subroutine
Name: MT8 [Show more] Type: Subroutine Category: Text Summary: Tab to column 6 and start a new word when printing extended tokens Deep dive: Extended text tokens
Context: See this subroutine on its own page References: This subroutine is called as follows: * JMTB calls MT8

This routine sets the following: * XC = 6 (tab to column 6) * DTW2 = %11111111 (we are not currently printing a word)
.MT8 LDA #6 \ Move the text cursor to column 6 STA XC LDA #%11111111 \ Set all the bits in DTW2 STA DTW2 RTS \ Return from the subroutine
Name: MT9 [Show more] Type: Subroutine Category: Text Summary: Clear the screen and set the current view type to 1 Deep dive: Extended text tokens
Context: See this subroutine on its own page References: This subroutine is called as follows: * JMTB calls MT9

This routine sets the following: * XC = 1 (tab to column 1) before calling TT66 to clear the screen and set the view type to 1.
.MT9 LDA #1 \ Move the text cursor to column 1 STA XC JMP TT66 \ Jump to TT66 to clear the screen and set the current \ view type to 1, returning from the subroutine using a \ tail call
Name: MT13 [Show more] Type: Subroutine Category: Text Summary: Switch to lower case when printing extended tokens Deep dive: Extended text tokens
Context: See this subroutine on its own page References: This subroutine is called as follows: * JMTB calls MT13 * MT29 calls MT13 * equip_data calls MT13

This routine sets the following: * DTW1 = %00100000 (apply lower case to the second letter of a word onwards) * DTW6 = %10000000 (lower case is enabled)
.MT13 LDA #%10000000 \ Set DTW6 = %10000000 STA DTW6 LDA #%00100000 \ Set DTW1 = %00100000 STA DTW1 RTS \ Return from the subroutine
Name: MT6 [Show more] Type: Subroutine Category: Text Summary: Switch to standard tokens in Sentence Case Deep dive: Extended text tokens
Context: See this subroutine on its own page References: This subroutine is called as follows: * JMTB calls MT6

This routine sets the following: * QQ17 = %10000000 (set Sentence Case for standard tokens) * DTW3 = %11111111 (print standard tokens) Other entry points: set_token Switch to standard tokens, keeping the current case
.MT6 LDA #%10000000 \ Set bit 7 of QQ17 to switch standard tokens to STA QQ17 \ Sentence Case .set_token LDA #%11111111 \ Set A = %11111111, so when we fall through into MT5, \ DTW3 gets set to %11111111 and calls to DETOK print \ standard tokens EQUB &2C \ Skip the next instruction by turning it into \ &2C &A9 &00, or BIT &00A9, which does nothing apart \ from affect the flags
Name: MT5 [Show more] Type: Subroutine Category: Text Summary: Switch to extended tokens Deep dive: Extended text tokens
Context: See this subroutine on its own page References: This subroutine is called as follows: * JMTB calls MT5

This routine sets the following: * DTW3 = %00000000 (print extended tokens)
.MT5 LDA #%00000000 \ Set DTW3 = %00000000, so that calls to DETOK print STA DTW3 \ extended tokens RTS \ Return from the subroutine
Name: MT14 [Show more] Type: Subroutine Category: Text Summary: Switch to justified text when printing extended tokens Deep dive: Extended text tokens
Context: See this subroutine on its own page References: This subroutine is called as follows: * HME2 calls MT14 * JMTB calls MT14 * PDESC calls MT14

This routine sets the following: * DTW4 = %10000000 (justify text, print buffer on carriage return) * DTW5 = 0 (reset line buffer size)
.MT14 LDA #%10000000 \ Set A = %10000000, so when we fall through into MT15, \ DTW4 gets set to %10000000 EQUB &2C \ Skip the next instruction by turning it into \ &2C &A9 &00, or BIT &00A9, which does nothing apart \ from affect the flags
Name: MT15 [Show more] Type: Subroutine Category: Text Summary: Switch to left-aligned text when printing extended tokens Deep dive: Extended text tokens
Context: See this subroutine on its own page References: This subroutine is called as follows: * HME2 calls MT15 * JMTB calls MT15

This routine sets the following: * DTW4 = %00000000 (do not justify text, print buffer on carriage return) * DTW5 = 0 (reset line buffer size)
.MT15 LDA #0 \ Set DTW4 = %00000000 STA DTW4 ASL A \ Set DTW5 = 0 (even when we fall through from MT14 with STA DTW5 \ A set to %10000000) RTS \ Return from the subroutine
Name: MT17 [Show more] Type: Subroutine Category: Text Summary: Print the selected system's adjective, e.g. Lavian for Lave Deep dive: Extended text tokens
Context: See this subroutine on its own page References: This subroutine is called as follows: * JMTB calls MT17

The adjective for the current system is generated by taking the system name, removing the last character if it is a vowel, and adding "-ian" to the end, so: * Lave gives Lavian (as in "Lavian tree grub") * Leesti gives Leestian (as in "Leestian Evil Juice") This routine is called by jump token 17, {system name adjective}, and it can only be used when justified text is being printed - i.e. following jump token 14, {justify} - because the routine needs to use the line buffer to work.
.MT17 LDA QQ17 \ Set QQ17 = %10111111 to switch to Sentence Case AND #%10111111 STA QQ17 LDA #3 \ Print control code 3 (selected system name) into the JSR TT27 \ line buffer LDX DTW5 \ Load the last character of the line buffer BUF into A LDA BUF-1,X \ (as DTW5 contains the buffer size, so character DTW5-1 \ is the last character in the buffer BUF) JSR VOWEL \ Test whether the character is a vowel, in which case \ this will set the C flag BCC MT171 \ If the character is not a vowel, skip the following \ instruction DEC DTW5 \ The character is a vowel, so decrement DTW5, which \ removes the last character from the line buffer (i.e. \ it removes the trailing vowel from the system name) .MT171 LDA #153 \ Print extended token 153 ("IAN"), returning from the JMP DETOK \ subroutine using a tail call
Name: MT18 [Show more] Type: Subroutine Category: Text Summary: Print a random 1-8 letter word in Sentence Case Deep dive: Extended text tokens
Context: See this subroutine on its own page References: This subroutine is called as follows: * JMTB calls MT18
.MT18 JSR MT19 \ Call MT19 to capitalise the next letter (i.e. set \ Sentence Case for this word only) JSR DORND \ Set A and X to random numbers and reduce A to a AND #3 \ random number in the range 0-3 TAY \ Copy the random number into Y, so we can use Y as a \ loop counter to print 1-4 words (i.e. Y+1 words) .MT18L JSR DORND \ Set A and X to random numbers and reduce A to an even AND #62 \ random number in the range 0-62 (as bit 0 of 62 is 0) TAX \ Copy the random number into X, so X contains the table \ offset of a random extended two-letter token from 0-31 \ which we can now use to pick a token from the combined \ tables at TKN2+2 and QQ16 (we intentionally exclude \ the first token in TKN2, which contains a newline) LDA TKN2+2,X \ Print the first letter of the token at TKN2+2 + X JSR DTS LDA TKN2+3,X \ Print the second letter of the token at TKN2+2 + X JSR DTS DEY \ Decrement the loop counter BPL MT18L \ Loop back to MT18L to print another two-letter token \ until we have printed Y+1 of them RTS \ Return from the subroutine
Name: MT19 [Show more] Type: Subroutine Category: Text Summary: Capitalise the next letter Deep dive: Extended text tokens
Context: See this subroutine on its own page References: This subroutine is called as follows: * JMTB calls MT19 * MT18 calls MT19 * cmn calls MT19

This routine sets the following: * DTW8 = %11011111 (capitalise the next letter)
.MT19 LDA #%11011111 \ Set DTW8 = %11011111 STA DTW8 RTS \ Return from the subroutine
Name: VOWEL [Show more] Type: Subroutine Category: Text Summary: Test whether a character is a vowel
Context: See this subroutine on its own page References: This subroutine is called as follows: * MT17 calls VOWEL

Arguments: A The character to be tested Returns: C flag The C flag is set if the character is a vowel, otherwise it is clear
.VOWEL ORA #%00100000 \ Set bit 5 of the character to make it lower case CMP #'a' \ If the letter is a vowel, jump to VRTS to return from BEQ VRTS \ the subroutine with the C flag set (as the CMP will CMP #'e' \ set the C flag if the comparison is equal) BEQ VRTS CMP #'i' BEQ VRTS CMP #'o' BEQ VRTS CMP #'u' BEQ VRTS CLC \ The character is not a vowel, so clear the C flag .VRTS RTS \ Return from the subroutine
Name: JMTB [Show more] Type: Variable Category: Text Summary: The extended token table for jump tokens 1-32 (DETOK) Deep dive: Extended text tokens
Context: See this variable on its own page References: This variable is used as follows: * DETOK2 calls JMTB
.JMTB EQUW MT1 \ Token 1: Switch to ALL CAPS EQUW MT2 \ Token 2: Switch to Sentence Case EQUW TT27 \ Token 3: Print the selected system name EQUW TT27 \ Token 4: Print the commander's name EQUW MT5 \ Token 5: Switch to extended tokens EQUW MT6 \ Token 6: Switch to standard tokens, in Sentence Case EQUW DASC \ Token 7: Beep EQUW MT8 \ Token 8: Tab to column 6 EQUW MT9 \ Token 9: Clear screen, tab to column 1, view type = 1 EQUW DASC \ Token 10: Line feed EQUW NLIN4 \ Token 11: Draw box around title (line at pixel row 19) EQUW DASC \ Token 12: Carriage return EQUW MT13 \ Token 13: Switch to lower case EQUW MT14 \ Token 14: Switch to justified text EQUW MT15 \ Token 15: Switch to left-aligned text EQUW MT16 \ Token 16: Print the character in DTW7 (drive number) EQUW MT17 \ Token 17: Print system name adjective in Sentence Case EQUW MT18 \ Token 18: Randomly print 1 to 4 two-letter tokens EQUW MT19 \ Token 19: Capitalise first letter of next word only EQUW DASC \ Token 20: Unused EQUW CLYNS \ Token 21: Clear the bottom few lines of the space view EQUW PAUSE \ Token 22: Display ship and wait for key press EQUW MT23 \ Token 23: Move to row 10, white text, set lower case EQUW PAUSE2 \ Token 24: Wait for a key press EQUW BRIS \ Token 25: Show incoming message screen, wait 2 seconds EQUW MT26 \ Token 26: Fetch line input from keyboard (filename) EQUW MT27 \ Token 27: Print mission captain's name (217-219) EQUW MT28 \ Token 28: Print mission 1 location hint (220-221) EQUW MT29 \ Token 29: Column 6, white text, lower case in words EQUW DASC \ Token 30: Unused EQUW DASC \ Token 31: Unused EQUW DASC \ Token 32: Unused
Name: TKN2 [Show more] Type: Variable Category: Text Summary: The extended two-letter token lookup table Deep dive: Extended text tokens
Context: See this variable on its own page References: This variable is used as follows: * DETOK2 calls TKN2 * MT18 calls TKN2

Two-letter token lookup table for extended tokens 215-227.
.TKN2 EQUB 12, 10 \ Token 215 = {crlf} EQUS "AB" \ Token 216 EQUS "OU" \ Token 217 EQUS "SE" \ Token 218 EQUS "IT" \ Token 219 EQUS "IL" \ Token 220 EQUS "ET" \ Token 221 EQUS "ST" \ Token 222 EQUS "ON" \ Token 223 EQUS "LO" \ Token 224 EQUS "NU" \ Token 225 EQUS "TH" \ Token 226 EQUS "NO" \ Token 227
Name: QQ16 [Show more] Type: Variable Category: Text Summary: The two-letter token lookup table Deep dive: Printing text tokens
Context: See this variable on its own page References: This variable is used as follows: * TT43 calls QQ16

Two-letter token lookup table for tokens 128-159. See the deep dive on "Printing text tokens" for details of how the two-letter token system works.
.QQ16 EQUS "AL" \ Token 128 EQUS "LE" \ Token 129 EQUS "XE" \ Token 130 EQUS "GE" \ Token 131 EQUS "ZA" \ Token 132 EQUS "CE" \ Token 133 EQUS "BI" \ Token 134 EQUS "SO" \ Token 135 EQUS "US" \ Token 136 EQUS "ES" \ Token 137 EQUS "AR" \ Token 138 EQUS "MA" \ Token 139 EQUS "IN" \ Token 140 EQUS "DI" \ Token 141 EQUS "RE" \ Token 142 EQUS "A?" \ Token 143 EQUS "ER" \ Token 144 EQUS "AT" \ Token 145 EQUS "EN" \ Token 146 EQUS "BE" \ Token 147 EQUS "RA" \ Token 148 EQUS "LA" \ Token 149 EQUS "VE" \ Token 150 EQUS "TI" \ Token 151 EQUS "ED" \ Token 152 EQUS "OR" \ Token 153 EQUS "QU" \ Token 154 EQUS "AN" \ Token 155 EQUS "TE" \ Token 156 EQUS "IS" \ Token 157 EQUS "RI" \ Token 158 EQUS "ON" \ Token 159
Name: MVEIT (Part 1 of 9) [Show more] Type: Subroutine Category: Moving Summary: Move current ship: Tidy the orientation vectors Deep dive: Program flow of the ship-moving routine Scheduling tasks with the main loop counter
Context: See this subroutine on its own page References: This subroutine is called as follows: * BRIEF calls MVEIT * PAS1 calls MVEIT * TITLE calls MVEIT * ships_ag calls MVEIT

This routine has multiple stages. This stage does the following: * Tidy the orientation vectors for one of the ship slots Arguments: INWK The current ship/planet/sun's data block XSAV The slot number of the current ship/planet/sun TYPE The type of the current ship/planet/sun
.MVEIT LDA INWK+31 \ If bit 5 of ship byte #31 is set, jump to MV3 as the AND #%00100000 \ ship is exploding, so we don't need to tidy its BNE MV3 \ orientation vectors LDA MCNT \ Fetch the main loop counter EOR XSAV \ Fetch the slot number of the ship we are moving, EOR AND #15 \ with the loop counter and apply mod 15 to the result. BNE MV3 \ The result will be zero when "counter mod 15" matches \ the slot number, so this makes sure we call TIDY 12 \ times every 16 main loop iterations, like this: \ \ Iteration 0, tidy the ship in slot 0 \ Iteration 1, tidy the ship in slot 1 \ Iteration 2, tidy the ship in slot 2 \ ... \ Iteration 11, tidy the ship in slot 11 \ Iteration 12, do nothing \ Iteration 13, do nothing \ Iteration 14, do nothing \ Iteration 15, do nothing \ Iteration 16, tidy the ship in slot 0 \ ... \ \ and so on JSR TIDY \ Call TIDY to tidy up the orientation vectors, to \ prevent the ship from getting elongated and out of \ shape due to the imprecise nature of trigonometry \ in assembly language .MV3 \ Fall through into part 7 (parts 2-6 are not required \ when we are docked)
Name: MVEIT (Part 7 of 9) [Show more] Type: Subroutine Category: Moving Summary: Move current ship: Rotate ship's orientation vectors by pitch/roll Deep dive: Orientation vectors Pitching and rolling
Context: See this subroutine on its own page References: No direct references to this subroutine in this source file

This routine has multiple stages. This stage does the following: * Rotate the ship's orientation vectors according to our pitch and roll As with the previous step, this is all about moving the other ships rather than us (even though we are the one doing the moving). So we rotate the current ship's orientation vectors (which defines its orientation in space), by the angles we are "moving" the rest of the sky through (alpha and beta, our roll and pitch), so the ship appears to us to be stationary while we rotate.
LDY #9 \ Apply our pitch and roll rotations to the current JSR MVS4 \ ship's nosev vector LDY #15 \ Apply our pitch and roll rotations to the current JSR MVS4 \ ship's roofv vector LDY #21 \ Apply our pitch and roll rotations to the current JSR MVS4 \ ship's sidev vector
Name: MVEIT (Part 8 of 9) [Show more] Type: Subroutine Category: Moving Summary: Move current ship: Rotate ship about itself by its own pitch/roll Deep dive: Orientation vectors Pitching and rolling by a fixed angle
Context: See this subroutine on its own page References: No direct references to this subroutine in this source file

This routine has multiple stages. This stage does the following: * If the ship we are processing is rolling or pitching itself, rotate it and apply damping if required
LDA INWK+30 \ Fetch the ship's pitch counter and extract the sign AND #%10000000 \ into RAT2 STA RAT2 LDA INWK+30 \ Fetch the ship's pitch counter and extract the value AND #%01111111 \ without the sign bit into A BEQ MV8 \ If the pitch counter is 0, then jump to MV8 to skip \ the following, as the ship is not pitching CMP #%01111111 \ If bits 0-6 are set in the pitch counter (i.e. the \ ship's pitch is not damping down), then the C flag \ will be set by this instruction SBC #0 \ Set A = A - 0 - (1 - C), so if we are damping then we \ reduce A by 1, otherwise it is unchanged ORA RAT2 \ Change bit 7 of A to the sign we saved in RAT2, so \ the updated pitch counter in A retains its sign STA INWK+30 \ Store the updated pitch counter in byte #30 LDX #15 \ Rotate (roofv_x, nosev_x) by a small angle (pitch) LDY #9 JSR MVS5 LDX #17 \ Rotate (roofv_y, nosev_y) by a small angle (pitch) LDY #11 JSR MVS5 LDX #19 \ Rotate (roofv_z, nosev_z) by a small angle (pitch) LDY #13 JSR MVS5 .MV8 LDA INWK+29 \ Fetch the ship's roll counter and extract the sign AND #%10000000 \ into RAT2 STA RAT2 LDA INWK+29 \ Fetch the ship's roll counter and extract the value AND #%01111111 \ without the sign bit into A BEQ MV5 \ If the roll counter is 0, then jump to MV5 to skip the \ following, as the ship is not rolling CMP #%01111111 \ If bits 0-6 are set in the roll counter (i.e. the \ ship's roll is not damping down), then the C flag \ will be set by this instruction SBC #0 \ Set A = A - 0 - (1 - C), so if we are damping then we \ reduce A by 1, otherwise it is unchanged ORA RAT2 \ Change bit 7 of A to the sign we saved in RAT2, so \ the updated roll counter in A retains its sign STA INWK+29 \ Store the updated pitch counter in byte #29 LDX #15 \ Rotate (roofv_x, sidev_x) by a small angle (roll) LDY #21 JSR MVS5 LDX #17 \ Rotate (roofv_y, sidev_y) by a small angle (roll) LDY #23 JSR MVS5 LDX #19 \ Rotate (roofv_z, sidev_z) by a small angle (roll) LDY #25 JSR MVS5
Name: MVEIT (Part 9 of 9) [Show more] Type: Subroutine Category: Moving Summary: Move current ship: Redraw on scanner, if it hasn't been destroyed
Context: See this subroutine on its own page References: No direct references to this subroutine in this source file

This routine has multiple stages. This stage does the following: * If the ship is exploding or being removed, hide it on the scanner * Otherwise redraw the ship on the scanner, now that it's been moved
.MV5 BIT dockedp \ If bit 7 of dockedp is clear, then we are docked, so BPL l_noradar \ jump to l_noradar to return from the subroutine as the \ scanner is not being used LDA INWK+31 \ Fetch the ship's exploding/killed state from byte #31 AND #%10100000 \ If we are exploding or removing this ship then jump to BNE MVD1 \ MVD1 to remove it from the scanner permanently LDA INWK+31 \ Set bit 4 to keep the ship visible on the scanner ORA #%00010000 STA INWK+31 JMP SCAN \ Display the ship on the scanner, returning from the \ subroutine using a tail call .MVD1 LDA INWK+31 \ Clear bit 4 to hide the ship on the scanner AND #%11101111 STA INWK+31 .l_noradar RTS \ Return from the subroutine
Name: MVS4 [Show more] Type: Subroutine Category: Moving Summary: Apply pitch and roll to an orientation vector Deep dive: Orientation vectors Pitching and rolling
Context: See this subroutine on its own page References: This subroutine is called as follows: * MVEIT (Part 7 of 9) calls MVS4

Apply pitch and roll angles alpha and beta to the orientation vector in Y. Specifically, this routine rotates a point (x, y, z) around the origin by pitch alpha and roll beta, using the small angle approximation to make the maths easier, and incorporating the Minsky circle algorithm to make the rotation more stable (though more elliptic). If that paragraph makes sense to you, then you should probably be writing this commentary! For the rest of us, there's a detailed explanation of all this in the deep dive on "Pitching and rolling". Arguments: Y Determines which of the INWK orientation vectors to transform: * Y = 9 rotates nosev: (nosev_x, nosev_y, nosev_z) * Y = 15 rotates roofv: (roofv_x, roofv_y, roofv_z) * Y = 21 rotates sidev: (sidev_x, sidev_y, sidev_z)
.MVS4 LDA ALPHA \ Set Q = alpha (the roll angle to rotate through) STA Q LDX INWK+2,Y \ Set (S R) = nosev_y STX R LDX INWK+3,Y STX S LDX INWK,Y \ These instructions have no effect as MAD overwrites STX P \ X and P when called, but they set X = P = nosev_x_lo LDA INWK+1,Y \ Set A = -nosev_x_hi EOR #%10000000 JSR MAD \ Set (A X) = Q * A + (S R) STA INWK+3,Y \ = alpha * -nosev_x_hi + nosev_y STX INWK+2,Y \ \ and store (A X) in nosev_y, so this does: \ \ nosev_y = nosev_y - alpha * nosev_x_hi STX P \ This instruction has no effect as MAD overwrites P, \ but it sets P = nosev_y_lo LDX INWK,Y \ Set (S R) = nosev_x STX R LDX INWK+1,Y STX S LDA INWK+3,Y \ Set A = nosev_y_hi JSR MAD \ Set (A X) = Q * A + (S R) STA INWK+1,Y \ = alpha * nosev_y_hi + nosev_x STX INWK,Y \ \ and store (A X) in nosev_x, so this does: \ \ nosev_x = nosev_x + alpha * nosev_y_hi STX P \ This instruction has no effect as MAD overwrites P, \ but it sets P = nosev_x_lo LDA BETA \ Set Q = beta (the pitch angle to rotate through) STA Q LDX INWK+2,Y \ Set (S R) = nosev_y STX R LDX INWK+3,Y STX S LDX INWK+4,Y STX P \ This instruction has no effect as MAD overwrites P, \ but it sets P = nosev_y LDA INWK+5,Y \ Set A = -nosev_z_hi EOR #%10000000 JSR MAD \ Set (A X) = Q * A + (S R) STA INWK+3,Y \ = beta * -nosev_z_hi + nosev_y STX INWK+2,Y \ \ and store (A X) in nosev_y, so this does: \ \ nosev_y = nosev_y - beta * nosev_z_hi STX P \ This instruction has no effect as MAD overwrites P, \ but it sets P = nosev_y_lo LDX INWK+4,Y \ Set (S R) = nosev_z STX R LDX INWK+5,Y STX S LDA INWK+3,Y \ Set A = nosev_y_hi JSR MAD \ Set (A X) = Q * A + (S R) STA INWK+5,Y \ = beta * nosev_y_hi + nosev_z STX INWK+4,Y \ \ and store (A X) in nosev_z, so this does: \ \ nosev_z = nosev_z + beta * nosev_y_hi RTS \ Return from the subroutine
Name: MVS5 [Show more] Type: Subroutine Category: Moving Summary: Apply a 3.6 degree pitch or roll to an orientation vector Deep dive: Orientation vectors Pitching and rolling by a fixed angle
Context: See this subroutine on its own page References: This subroutine is called as follows: * HAS1 calls MVS5 * MVEIT (Part 8 of 9) calls MVS5

Pitch or roll a ship by a small, fixed amount (1/16 radians, or 3.6 degrees), in a specified direction, by rotating the orientation vectors. The vectors to rotate are given in X and Y, and the direction of the rotation is given in RAT2. The calculation is as follows: * If the direction is positive: X = X * (1 - 1/512) + Y / 16 Y = Y * (1 - 1/512) - X / 16 * If the direction is negative: X = X * (1 - 1/512) - Y / 16 Y = Y * (1 - 1/512) + X / 16 So if X = 15 (roofv_x), Y = 21 (sidev_x) and RAT2 is positive, it does this: roofv_x = roofv_x * (1 - 1/512) + sidev_x / 16 sidev_x = sidev_x * (1 - 1/512) - roofv_x / 16 Arguments: X The first vector to rotate: * If X = 15, rotate roofv_x * If X = 17, rotate roofv_y * If X = 19, rotate roofv_z * If X = 21, rotate sidev_x * If X = 23, rotate sidev_y * If X = 25, rotate sidev_z Y The second vector to rotate: * If Y = 9, rotate nosev_x * If Y = 11, rotate nosev_y * If Y = 13, rotate nosev_z * If Y = 21, rotate sidev_x * If Y = 23, rotate sidev_y * If Y = 25, rotate sidev_z RAT2 The direction of the pitch or roll to perform, positive or negative (i.e. the sign of the roll or pitch counter in bit 7)
.MVS5 LDA INWK+1,X \ Fetch roofv_x_hi, clear the sign bit, divide by 2 and AND #%01111111 \ store in T, so: LSR A \ STA T \ T = |roofv_x_hi| / 2 \ = |roofv_x| / 512 \ \ The above is true because: \ \ |roofv_x| = |roofv_x_hi| * 256 + roofv_x_lo \ \ so: \ \ |roofv_x| / 512 = |roofv_x_hi| * 256 / 512 \ + roofv_x_lo / 512 \ = |roofv_x_hi| / 2 LDA INWK,X \ Now we do the following subtraction: SEC \ SBC T \ (S R) = (roofv_x_hi roofv_x_lo) - |roofv_x| / 512 STA R \ = (1 - 1/512) * roofv_x \ \ by doing the low bytes first LDA INWK+1,X \ And then the high bytes (the high byte of the right SBC #0 \ side of the subtraction being 0) STA S LDA INWK,Y \ Set P = nosev_x_lo STA P LDA INWK+1,Y \ Fetch the sign of nosev_x_hi (bit 7) and store in T AND #%10000000 STA T LDA INWK+1,Y \ Fetch nosev_x_hi into A and clear the sign bit, so AND #%01111111 \ A = |nosev_x_hi| LSR A \ Set (A P) = (A P) / 16 ROR P \ = |nosev_x_hi nosev_x_lo| / 16 LSR A \ = |nosev_x| / 16 ROR P LSR A ROR P LSR A ROR P ORA T \ Set the sign of A to the sign in T (i.e. the sign of \ the original nosev_x), so now: \ \ (A P) = nosev_x / 16 EOR RAT2 \ Give it the sign as if we multiplied by the direction \ by the pitch or roll direction STX Q \ Store the value of X so it can be restored after the \ call to ADD JSR ADD \ (A X) = (A P) + (S R) \ = +/-nosev_x / 16 + (1 - 1/512) * roofv_x STA K+1 \ Set K(1 0) = (1 - 1/512) * roofv_x +/- nosev_x / 16 STX K LDX Q \ Restore the value of X from before the call to ADD LDA INWK+1,Y \ Fetch nosev_x_hi, clear the sign bit, divide by 2 and AND #%01111111 \ store in T, so: LSR A \ STA T \ T = |nosev_x_hi| / 2 \ = |nosev_x| / 512 LDA INWK,Y \ Now we do the following subtraction: SEC \ SBC T \ (S R) = (nosev_x_hi nosev_x_lo) - |nosev_x| / 512 STA R \ = (1 - 1/512) * nosev_x \ \ by doing the low bytes first LDA INWK+1,Y \ And then the high bytes (the high byte of the right SBC #0 \ side of the subtraction being 0) STA S LDA INWK,X \ Set P = roofv_x_lo STA P LDA INWK+1,X \ Fetch the sign of roofv_x_hi (bit 7) and store in T AND #%10000000 STA T LDA INWK+1,X \ Fetch roofv_x_hi into A and clear the sign bit, so AND #%01111111 \ A = |roofv_x_hi| LSR A \ Set (A P) = (A P) / 16 ROR P \ = |roofv_x_hi roofv_x_lo| / 16 LSR A \ = |roofv_x| / 16 ROR P LSR A ROR P LSR A ROR P ORA T \ Set the sign of A to the opposite sign to T (i.e. the EOR #%10000000 \ sign of the original -roofv_x), so now: \ \ (A P) = -roofv_x / 16 EOR RAT2 \ Give it the sign as if we multiplied by the direction \ by the pitch or roll direction STX Q \ Store the value of X so it can be restored after the \ call to ADD JSR ADD \ (A X) = (A P) + (S R) \ = -/+roofv_x / 16 + (1 - 1/512) * nosev_x STA INWK+1,Y \ Set nosev_x = (1-1/512) * nosev_x -/+ roofv_x / 16 STX INWK,Y LDX Q \ Restore the value of X from before the call to ADD LDA K \ Set roofv_x = K(1 0) STA INWK,X \ = (1-1/512) * roofv_x +/- nosev_x / 16 LDA K+1 STA INWK+1,X RTS \ Return from the subroutine
Save 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.2.ELTA ", ~CODE%, " ", ~P%, " ", ~LOAD%, " ", ~LOAD_A% SAVE "3-assembled-output/2.ELTA.bin", CODE%, P%, LOAD%