-
Notifications
You must be signed in to change notification settings - Fork 17
/
Copy pathelite-source-bank-0.asm
24513 lines (18726 loc) · 960 KB
/
elite-source-bank-0.asm
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
; ******************************************************************************
;
; NES ELITE GAME SOURCE (BANK 0)
;
; NES Elite was written by Ian Bell and David Braben and is copyright D. Braben
; and I. Bell 1991/1992
;
; The code in this file has been reconstructed from a disassembly of the version
; released on Ian Bell's personal website at http://www.elitehomepage.org/
;
; The commentary is copyright Mark Moxon, and any misunderstandings or mistakes
; in the documentation are entirely my fault
;
; The terminology and notations used in this commentary are explained at
; https://elite.bbcelite.com/terminology
;
; The deep dive articles referred to in this commentary can be found at
; https://elite.bbcelite.com/deep_dives
;
; ------------------------------------------------------------------------------
;
; This source file contains the game code for ROM bank 0 of NES Elite.
;
; ------------------------------------------------------------------------------
;
; This source file produces the following binary file:
;
; * bank0.bin
;
; ******************************************************************************
; ******************************************************************************
;
; ELITE BANK 0
;
; Produces the binary file bank0.bin.
;
; ******************************************************************************
ORG CODE%
; ******************************************************************************
;
; Name: ResetMMC1_b0
; Type: Subroutine
; Category: Start and end
; Summary: The MMC1 mapper reset routine at the start of the ROM bank
; Deep dive: Splitting NES Elite across multiple ROM banks
;
; ------------------------------------------------------------------------------
;
; When the NES is switched on, it is hardwired to perform a JMP ($FFFC). At this
; point, there is no guarantee as to which ROM banks are mapped to $8000 and
; $C000, so to ensure that the game starts up correctly, we put the same code
; in each ROM at the following locations:
;
; * We put $C000 in address $FFFC in every ROM bank, so the NES always jumps
; to $C000 when it starts up via the JMP ($FFFC), irrespective of which
; ROM bank is mapped to $C000.
;
; * We put the same reset routine (this routine, ResetMMC1) at the start of
; every ROM bank, so the same routine gets run, whichever ROM bank is mapped
; to $C000.
;
; This ResetMMC1 routine is therefore called when the NES starts up, whatever
; the bank configuration ends up being. It then switches ROM bank 7 to $C000 and
; jumps into bank 7 at the game's entry point BEGIN, which starts the game.
;
; ******************************************************************************
.ResetMMC1_b0
SEI ; Disable interrupts
INC $C006 ; Reset the MMC1 mapper, which we can do by writing a
; value with bit 7 set into any address in ROM space
; (i.e. any address from $8000 to $FFFF)
;
; The INC instruction does this in a more efficient
; manner than an LDA/STA pair, as it:
;
; * Fetches the contents of address $C006, which
; contains the high byte of the JMP destination
; below, i.e. the high byte of BEGIN, which is $C0
;
; * Adds 1, to give $C1
;
; * Writes the value $C1 back to address $C006
;
; $C006 is in the ROM space and $C1 has bit 7 set, so
; the INC does all that is required to reset the mapper,
; in fewer cycles and bytes than an LDA/STA pair
;
; Resetting MMC1 maps bank 7 to $C000 and enables the
; bank at $8000 to be switched, so this instruction
; ensures that bank 7 is present
JMP BEGIN ; Jump to BEGIN in bank 7 to start the game
; ******************************************************************************
;
; Name: Interrupts_b0
; Type: Subroutine
; Category: Start and end
; Summary: The IRQ and NMI handler while the MMC1 mapper reset routine is
; still running
;
; ******************************************************************************
.Interrupts_b0
IF _NTSC
RTI ; Return from the IRQ interrupt without doing anything
;
; This ensures that while the system is starting up and
; the ROM banks are in an unknown configuration, any IRQ
; interrupts that go via the vector at $FFFE and any NMI
; interrupts that go via the vector at $FFFA will end up
; here and be dealt with
;
; Once bank 7 is switched into $C000 by the ResetMMC1
; routine, the vector is overwritten with the last two
; bytes of bank 7, which point to the IRQ routine
ENDIF
; ******************************************************************************
;
; Name: versionNumber_b0
; Type: Variable
; Category: Text
; Summary: The game's version number in bank 0
;
; ******************************************************************************
IF _NTSC
EQUS " 5.0"
ELIF _PAL
EQUS "<2.8>"
ENDIF
; ******************************************************************************
;
; Name: ResetShipStatus
; Type: Subroutine
; Category: Flight
; Summary: Reset the ship's speed, hyperspace counter, laser temperature,
; shields and energy banks
;
; ******************************************************************************
.ResetShipStatus
LDA #0 ; Reduce the speed to 0
STA DELTA
STA QQ22+1 ; Reset the on-screen hyperspace counter
LDA #0 ; Cool down the lasers completely
STA GNTMP
LDA #$FF ; Recharge the forward and aft shields
STA FSH
STA ASH
STA ENERGY ; Recharge the energy banks
RTS ; Return from the subroutine
; ******************************************************************************
;
; Name: DOENTRY
; Type: Subroutine
; Category: Flight
; Summary: Dock at the space station, show the ship hangar and work out any
; mission progression
; Deep dive: The Constrictor mission
; The Thargoid Plans mission
; The Trumbles mission
;
; ******************************************************************************
.DOENTRY
LDX #$FF ; Set the stack pointer to $01FF, which is the standard
TXS ; location for the 6502 stack, so this instruction
; effectively resets the stack
JSR RES2 ; Reset a number of flight variables and workspaces
JSR LAUN ; Show the space station docking tunnel
JSR ResetShipStatus ; Reset the ship's speed, hyperspace counter, laser
; temperature, shields and energy banks
JSR HALL_b1 ; Show the ship hangar
LDY #44 ; Wait until 44 NMI interrupts have passed (i.e. the
JSR DELAY ; next 44 VBlanks)
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, or we are Competent but have not
; yet earned a grand total of at least 256 kill points),
; 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 then mission 1 hasn't started, we have
; reached a combat rank of at least Competent plus 128
; kill points, 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 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 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
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 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 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
LDA COK ; If bit 7 of COK is set, then cheat mode has been
BMI EN6 ; applied, so jump to EN6
LDA CASH+1 ; If the second most significant byte of CASH(0 1 2 3)
BEQ EN6 ; is zero then the cash amount is less than $010000
; (6553.6 credits), so jump to EN6
LDA TP ; If bit 4 of TP is set, then the Trumbles mission has
AND #%00010000 ; already been completed, so jump to EN6
BNE EN6
; If we get here then cheat mode has not been applied,
; we have at least 6553.6 credits and the Trumble
; mission has not yet been offered, so we do that now
JMP TBRIEF ; Jump to TBRIEF to offer the Trumble mission, returning
; from the subroutine using a tail call
.EN6
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)
RTS ; Return from the subroutine
; ******************************************************************************
;
; Name: Main flight loop (Part 4 of 16)
; Type: Subroutine
; 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
; Splitting the main loop in the NES version
;
; ------------------------------------------------------------------------------
;
; 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
;
; ******************************************************************************
.MAL1
STX XSAV ; Store the current slot number in XSAV
STA TYPE ; Store the ship type in TYPE
SETUP_PPU_FOR_ICON_BAR ; If the PPU has started drawing the icon bar, configure
; the PPU to use nametable 0 and pattern table 0
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
SETUP_PPU_FOR_ICON_BAR ; If the PPU has started drawing the icon bar, configure
; the PPU to use nametable 0 and pattern table 0
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
CMP #SST ; If this is not the space station, jump to main32
BNE main32
LDA spasto ; Copy the address of the space station's ship blueprint
STA XX0 ; from spasto(1 0) to XX0(1 0), which we set up in NWSPS
LDA spasto+1 ; when calculating the correct station type (Coriolis or
STA XX0+1 ; Dodo)
LDY #SST * 2 ; Set Y = ship type * 2
BNE main33 ; Jump to main33 (this BNE is effectively a JMP as Y is
; never zero)
.main32
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
.main33
; We now check whether this ship prevents us from
; performing an in-system jump
CPY #ESC * 2 ; If this is an escape pod, jump to main36 to skip the
BEQ main36 ; following, as it doesn't prevent jumping
CPY #TGL * 2 ; If this is a Thargon, jump to main36 to skip the
BEQ main36 ; following, as it doesn't prevent jumping
CPY #SST * 2 ; If this is the space station, jump to main35 to check
BEQ main35 ; whether it is hostile
LDA INWK+32 ; If bit 7 of the ship's byte #32 is clear, then AI is
BPL main36 ; not enabled, so jump to main36 to skip the following,
; as it doesn't prevent jumping
CPY #MSL * 2 ; If this is a missile, jump to main34 to skip the
BEQ main34 ; aggression level check (as this doesn't apply to
; missiles)
AND #%00111110 ; If bits 1-5 of the ship's byte #32 are clear, then the
BEQ main36 ; ship's aggression level is zero, so jump to main36 to
; skip the following, as it doesn't prevent jumping
.main34
LDA INWK+31 ; If either bit 5 or 7 of the ship's byte #31 are set,
AND #%10100000 ; then the ship is exploding or has been killed, so jump
BNE main36 ; to main36 to skip the following, as it doesn't prevent
; jumping
.main35
LDA NEWB ; If bit 2 of the ship's NEWB flag is clear then the
AND #%00000100 ; ship is not hostile, so jump to main36 to skip the
BEQ main36 ; following, as it doesn't prevent jumping
; If we get here then this is one of the following:
;
; * A missile
;
; * A hostile space station
;
; * An aggressive ship with AI enabled
;
; and it isn't an escape pod or Thargon, and it hasn't
; been killed and isn't exploding
;
; So this ship prevents us from performing an in-system
; jump, so we need to set bit 7 of allowInSystemJump
; to do just that
ASL allowInSystemJump ; Set bit 7 of allowInSystemJump to prevent us from
SEC ; being able to perform an in-system jump
ROR allowInSystemJump
.main36
; ******************************************************************************
;
; Name: Main flight loop (Part 5 of 16)
; Type: Subroutine
; 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
CPY #2*THG ; If the ship in Y is a Thargoid, jump to BA21 as energy
BEQ MA21 ; bombs have no effect against Thargoids
CPY #2*CON ; If the ship in Y is the Constrictor, jump to BA21
BCS MA21 ; as energy bombs are useless against the Constrictor
; (the Constrictor is the target of mission 1, and it
; would be too easy if it could just be blown out of
; the sky with a single key press)
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
LDX TYPE ; Set X to the type of the ship that was killed so the
; following call to EXNO2 can award us the correct
; number of fractional kill points
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)
; 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
SETUP_PPU_FOR_ICON_BAR ; If the PPU has started drawing the icon bar, configure
; the PPU to use nametable 0 and pattern table 0
; 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
SETUP_PPU_FOR_ICON_BAR ; If the PPU has started drawing the icon bar, configure
; the PPU to use nametable 0 and pattern table 0
; ******************************************************************************
;
; Name: Main flight loop (Part 7 of 16)
; Type: Subroutine
; 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
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
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
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
BMI P%+5 ; If the result is negative, skip the following
; instruction
JMP 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)
; Type: Subroutine
; 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
CPX #ESC ; If this is an escape pod, jump to MA58 to skip all the
BEQ MA58 ; docking and scooping checks
LDY #0 ; Fetch byte #0 of the ship's blueprint
JSR GetShipBlueprint
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 high nibbles in their blueprint byte #0
; so if we get here, our ship is one of those, and the
; high nibble gives the market item number of the item
; when scooped, less 1
ADC #1 ; Add 1 to the high 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 + Y 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
JSR MakeScoopSound ; Make the sound of the fuel scoops working
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)
; Type: Subroutine
; 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
;
; ------------------------------------------------------------------------------
;
; 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%+NIK%+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 MA622 ; 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 MA622 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
; This version of Elite omits check 3 (which would check
; the sign of the z-axis)
CMP #89 ; 4. If z-axis < 89, jump to MA62 to fail docking, as
BCC MA62 ; we are not in the 22.0 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, we just docked successfully
JSR ResetMusicAfterNMI ; Wait for the next NMI before resetting the current
; tune to 0 (no tune) and stopping the music
JMP DOENTRY ; Go to the docking bay (i.e. show the ship hangar)
.MA62
; If we arrive here, docking has just failed
LDA auto ; If the docking computer is engaged, ensure we dock
BNE GOIN ; successfully even if the approach isn't correct, as
; the docking computer algorithm isn't perfect (so this
; fixes the issue in the other versions of Elite where
; the docking computer can kill you)
.MA622
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)
; 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 scooping attempts
;
; * 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
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
; 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)
; Type: Subroutine
; 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 QQ11 ; If this is not a space view, jump to MA15 to skip
BEQ P%+5 ; missile and laser locking
JMP MA15
JSR PLUT ; Call PLUT to update the geometric axes in INWK to
; match the view (front, rear, left, right)
LDA LAS ; If we are firing our laser then LAS will contain the
BNE main37 ; laser power (which will be non-zero), so jump to
; main37 to check if the current ship is in the
; crosshairs, to see if we are hitting it
LDA MSAR ; If the active missile is not looking for a target then
BEQ main38 ; MSAR will be zero, so jump to main38 to skip the