-
Notifications
You must be signed in to change notification settings - Fork 12
Expand file tree
/
Copy pathjetpac.skool
More file actions
6003 lines (5670 loc) · 225 KB
/
jetpac.skool
File metadata and controls
6003 lines (5670 loc) · 225 KB
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
; SkoolKit disassembly for JETPAC (cartridge)
; (https://github.com/mrcook/jetpac-disassembly)
;
; Copyright (c) 2020 Michael R. Cook (this disassembly)
; Copyright (c) 1983 Ultimate Play the Game (JETPAC)
; JETPAC was designed and developed by Tim Stamper and Chris Stamper
@start=$6000
; Frame counter.
;
; These lower two bytes of frame counter are incremented every 20 ms.
@equ=SYSVAR_FRAMES=$5c78
@org
; Stack: 37 bytes of memory allocated for use as the system stack.
@label=stack_memory
s$5ccb defs $25
; High score for current game session.
;
; A 3-byte decimal representation of the score. Maximum value is 999999.
@label=hi_score
b$5cf0 defs $03
; Game options.
;
; #TABLE(default,centre,:w)
; { =h Bits(n) | =h Option }
; { 0 | Players (reset=1, set=2) }
; { 1 | Input Type (reset=Keyboard, set=Joystick) }
; TABLE#
@label=game_options
b$5cf3 defb $00
; Player one score.
;
; A 3-byte decimal representation of the score. Maximum value is 999999.
@label=p1_score
b$5cf4 defs $03
; Player two score.
;
; A 3-byte decimal representation of the score. Maximum value is 999999.
@label=p2_score
b$5cf7 defs $03
; Padding to make block from hi_score to here 16 bytes in length.
s$5cfa defs $06
; Jetman's motion state.
;
; Indicates when walking or flying, and in which direction.
; #TABLE(default,centre,:w)
; { =h Bits(n) | =h State }
; { 7 | 0=fly up, 1=walk/fly down }
; { 6 | 0=right, 1=left }
; { 1 | 1=walking (default) }
; { 0 | 1=flying }
; TABLE#
@label=jetman_motion
b$5d00 defb $00
; Jetman X position.
;
; Default start position is $80.
@label=jetman_pos_x
b$5d01 defb $00
; Jetman Y position.
;
; Default start position is $B7.
@label=jetman_pos_y
b$5d02 defb $00
; Jetman sprite colour attribute.
;
; Initialised to $47 on new player.
@label=jetman_colour
b$5d03 defb $00
; Jetman's current state.
;
; #TABLE(default,centre,:w)
; { =h Bits(n) | =h State }
; { 7 | 0=up/standing still, 1=down }
; { 6 | 0=right, 1=left }
; { 2 | 1=item collected }
; { 1 | 1=carrying something }
; { 0 | 0=horizontal, 1=vertical }
; TABLE#
@label=jetman_state
b$5d04 defb $00
; Jetman Velocity: Horizontal.
;
; Max Walking: $20. Max Flying: $40.
@label=jetman_velocity_x
b$5d05 defb $00
; Jetman Velocity: Vertical.
;
; Max: $3F.
@label=jetman_velocity_y
b$5d06 defb $00
; Jetman sprite height, which is always $24, as set by the defaults.
@label=jetman_height
b$5d07 defb $00
; Laser beams
;
; #TABLE(default,centre,:w)
; { =h Bytes(n) | =h Variable }
; { 0 | Unused=$00, Used=$10 }
; { 1 | Y Position }
; { 2 | X position pulse #1 }
; { 3 | X position pulse #2 }
; { 4 | X position pulse #3 }
; { 5 | X position pulse #4 }
; { 6 | Beam length }
; { 7 | Colour attribute }
; TABLE#
@label=laser_beam_params
b$5d08 defb $00,$00,$00,$00,$00,$00,$00,$00 ; laser beam #1
$5d10 defb $00,$00,$00,$00,$00,$00,$00,$00 ; laser beam #2
$5d18 defb $00,$00,$00,$00,$00,$00,$00,$00 ; laser beam #3
$5d20 defb $00,$00,$00,$00,$00,$00,$00,$00 ; laser beam #4
; Sound type parameters for explosions.
;
; Byte 1=Frequency, byte 2=Duration.
@label=explosion_sfx_params
b$5d28 defb $00 ; Frequency is $0C or $0D
$5d29 defb $00 ; Length is always set to $04
; Explosion params padding, making 8 bytes total. Unused.
b$5d2a defs $06
; Rocket object attributes.
;
; #TABLE(default,centre,:w)
; { =h Bytes(n) | =h Variable }
; { 0 | Movement: $09=on pad, $0A=up, $0B=down }
; { 1 | X Position (pixels) }
; { 2 | Y Position (pixels) (base module) }
; { 3 | Colour Attribute }
; { 4 | Modules on Pad: $01 (new level default) to $03 }
; { 5 | Fuel Pods collected: 0-6 }
; { 6 | Unused }
; { 7 | Always $1C }
; TABLE#
@label=rocket_state
b$5d30 defb $00,$00,$00,$00,$00,$00,$00,$00
; Rocket module state (fuel/part).
;
; NOTE: Used for top module at level start, then only fuel pods.
; #TABLE(default,centre,:w)
; { =h Bytes(n) | =h Variable }
; { 0 | Type: $00=Unused, $04=Ship/Fuel Pod }
; { 1 | X Position (pixels) }
; { 2 | Y Position (pixels) }
; { 3 | Colour Attribute }
; { 4 | State: 1=new, 3=collected, 5=free-fall, 7=dropped }
; { 5 | Unused }
; { 6 | Sprite jump table offset }
; { 7 | Sprite Height }
; TABLE#
@label=rocket_module_state
b$5d38 defb $00,$00,$00,$00,$00,$00,$00,$00
; Current Collectible object.
;
; Used for the middle ship module at level start, then only collectibles. The
; "state" field is not used for collectibles (remains $00).
; #TABLE(default,centre,:w)
; { =h Bytes(n) | =h Variable }
; { 0 | Type: $00=Unused, $04=Rocket, $0E=Collectible }
; { 1 | X Position (pixels) }
; { 2 | Y Position (pixels) }
; { 3 | Colour Attribute }
; { 4 | State: 1=new, 3=collected, 5=free-fall, 7=dropped }
; { 5 | Unused }
; { 6 | Sprite jump table offset }
; { 7 | Sprite Height }
; TABLE#
@label=item_state
b$5d40 defb $00,$00,$00,$00,$00,$00,$00,$00
; Thruster/Explosion animation sprite state.
;
; Holds the sprite state for the current animation frame being displayed for
; Jetman's jetpac thruster "smoke". Note: each animation loop uses a (random)
; two colour pair from the 4 possible colours.
; #TABLE(default,centre,:w)
; { =h Bytes(n) | =h Variable }
; { 0 | Animating: 00=no, 03=anim done, 08=animating }
; { 1 | Last Jetman X location }
; { 2 | Last Jetman Y location }
; { 3 | Colour: Red, Magenta, Yellow, White }
; { 4 | Frame: 0-7 }
; { 5 | Unused }
; { 6 | Unknown (set to $03 on first use) }
; { 7 | Unused }
; TABLE#
@label=jetman_thruster_anim_state
b$5d48 defb $00,$00,$00,$00,$00,$00,$00,$00
; Alien state objects.
;
; There are a maximum of 6 aliens on the screen at one time, and those states
; are stored here in this data block. See Jetman object for more details.
; #TABLE(default,centre,:w)
; { =h Bytes(n) | =h Variable }
; { 00 | Direction }
; { 01 | X location (pixels) }
; { 02 | Y location (pixels) }
; { 03 | Colour attribute }
; { 04 | Moving direction }
; { 05 | X Speed (default: $04) }
; { 06 | Y Speed }
; { 07 | Sprite Height }
; TABLE#
@label=alien_states
b$5d50 defb $00,$00,$00,$00,$00,$00,$00,$00 ; slot #1
$5d58 defb $00,$00,$00,$00,$00,$00,$00,$00 ; slot #2
$5d60 defb $00,$00,$00,$00,$00,$00,$00,$00 ; slot #3
$5d68 defb $00,$00,$00,$00,$00,$00,$00,$00 ; slot #4
$5d70 defb $00,$00,$00,$00,$00,$00,$00,$00 ; slot #5
$5d78 defb $00,$00,$00,$00,$00,$00,$00,$00 ; slot #6
; Jetman exploding animation object.
;
; Holds the sprite state for the current animation frame being displayed for
; the explosion sprite when Jetman is killed. Note: each animation loop uses a
; (random) two colour pair from the 4 possible colours.
; #TABLE(default,centre,:w)
; { =h Bytes(n) | =h Variable }
; { 0 | Animating: 00=no, 08=yes }
; { 1 | Jetman X location (pixels) }
; { 2 | Jetman Y location (pixels) }
; { 3 | Colour: Red, Magenta, Yellow, White }
; { 4 | Frame: 0-7 }
; { 5 | State (set=animating) }
; { 6 | Jetman direction }
; { 7 | Unused }
; TABLE#
@label=jetman_exploding_anim_state
b$5d80 defb $00,$00,$00,$00,$00,$00,$00,$00
; Jetman object backup for the inactive player.
@label=inactive_jetman_state
b$5d88 defb $00,$00,$00,$00,$00,$00,$00,$00
@defs=$5D90:$08,$00
; Unused padding.
s$5d90 defs $08
; Rocket/collectible object backup for the inactive player.
@label=inactive_rocket_state
b$5d98 defb $00,$00,$00,$00,$00,$00,$00,$00 ; Rocket object
$5da0 defb $00,$00,$00,$00,$00,$00,$00,$00 ; Rocket module (fuel/part)
$5da8 defb $00,$00,$00,$00,$00,$00,$00,$00 ; Collectible/Rocket middle
@defs=$5DB0:$06,$00
; Unused padding.
s$5db0 defs $08
@defs=$5DB8:$06,$00
; Unused padding.
s$5db8 defs $08
; Temporary actor state.
;
; Many actor routines use this to hold state temporarily during updates.
; #TABLE(default,centre,:w)
; { =h Bytes(n) | =h Variable }
; { 0 | X location }
; { 1 | Y location }
; { 2 | Movement direction }
; { 3 | Height (pixels) }
; { 4 | Width (tiles) }
; { 5 | Current sprite height value (?) }
; { 6 | Sprite GFX data height value (?) }
; { 7 | Unknown flying movement/direction (used only for Jetman?) }
; TABLE#
@label=actor
b$5dc0 defb $00,$00,$00,$00,$00,$00,$00,$00
; Value only changes while Jetman is moving up/down - has no obvious pattern.
@label=jetman_fly_counter
b$5dc8 defb $00
; Alien direction update flag for: Squidgy, UFO, Sphere, Crossed Ship.
;
; Each alien update routine first resets the value, then after the first check,
; increments the value, which triggers the draw alien routine.
@label=alien_new_dir_flag
b$5dc9 defb $00
; Jetman velocity modifier.
;
; Initialised to $04 by initialise game routine, otherwise value is $00 during
; game play.
@label=jetman_velocity_modifier
b$5dca defb $00
; Current alien ID being updated?
;
; Values are $00 (no alien update?) up to the max number of aliens: $01 to $06.
; Used by all alien update routines and in a few other places.
@label=current_alien_number
b$5dcb defb $00
; Game timer.
;
; 16-bit counter starting at 0x0000 and counting +1 (each time a sprite is
; moved or redrawn?), although sometimes it will increment +2. This continues
; until the whole game is over - for both 1 and 2 player games. Counter loops
; around after reaching 0xFFFF.
@label=game_timer
w$5dcc defw $0000
; Random Number.
;
; Value is calculated using the 16-bit game timer LSB value, which is used to
; fetch a byte from the ROM (between addresses $00 and $FF), then by adding the
; current #REGr.
@label=random_number
b$5dce defb $00
; Temporary actor coordinates.
;
; Coordinates (Y,X) used when colouring a sprite. Set by the Actor, along with
; being inc/decremented during the Rocket launch/land phase.
@label=actor_coords
b$5dcf defb $00 ; Y location (pixels)
$5dd0 defb $00 ; X location (pixels)
; Current active player.
;
; $00=player #1, $FF=player #2.
@label=current_player_number
b$5dd1 defb $00
; Jetman Rocket module attached success.
;
; Set to $01 at the start of each new life/level. When one of the two modules
; becomes attached to the Rocket (top or middle, but not fuel) then this is
; changed to $00.
@label=jetman_rocket_mod_connected
b$5dd2 defb $00
; Rocket modules attached.
;
; Set to $04 at the start of each new level. When one of the two modules
; becomes attached to the Rocket (top or middle, but not fuel) then this is
; changed to $02.
@label=rocket_mod_attached
b$5dd3 defb $00
; Holds a copy of the last SYSVAR_FRAMES counter.
@label=last_frame
b$5dd4 defb $00
; Has a frame ticked over.
;
; $00=no, $01=yes.
@label=frame_ticked
b$5dd5 defb $00
; Current menu item colour attribute.
@label=current_colour_attr
b$5dd6 defb $00
; "Get Ready" delay timer.
;
; At the beginning of each player turn there is a delay to allow the player to
; be ready for play. Values are $80 for a 1 player game, $FF for a two player
; game. The larger delay is useful for swapping players controls.
@label=begin_play_delay_counter
b$5dd7 defb $00
@defs=$5DD8:$06,$00
; Unused padding.
s$5dd8 defs $18
; Game level for current player.
;
; Level #1 starts at $00.
@label=player_level
b$5df0 defb $00
; Current player lives remaining.
@label=player_lives
b$5df1 defb $00
@defs=$5DF2:$08,$00
; Unused padding for player level/lives object (8 bytes total).
s$5df2 defs $06
; Game level for inactive player.
;
; Level #1 starts at $00.
@label=inactive_player_level
b$5df8 defb $00
; Inactive player lives remaining.
@label=inactive_player_lives
b$5df9 defb $00
@defs=$5DFA:$08,$00
; Unused padding for inactive player level/lives object (8 bytes total).
s$5dfa defs $06
; Buffers for Alien sprites.
;
; 4 buffers representing left/right facing aliens, with 2 animation frames
; each.
; #TABLE(default,centre,:w)
; { =h Bytes(n) | =h Meaning }
; { $00 | Header byte - always NULL? }
; { $01 | Width value - always $03 }
; { $02 | Height value }
; { $03-$33 | Pixel data }
; TABLE#
@label=buffers_aliens_R1
b$5e00 defs $33 ; right facing, anim frame 1
@label=buffers_aliens_R2
$5e33 defs $33 ; right facing, anim frame 2
@label=buffers_aliens_L1
$5e66 defs $33 ; left facing, anim frame 1
@label=buffers_aliens_L2
$5e99 defs $33 ; left facing, anim frame 2
; Buffers for Collectible/Rocket sprites.
;
; Buffer to hold 4 item sprites.
; #TABLE(default,centre,:w)
; { =h Bytes(n) | =h Meaning }
; { $00 | Header byte }
; { $01 | Width value - always $03? }
; { $02 | Height value }
; { $03-$33 | Pixel data }
; TABLE#
@label=buffers_item_1
b$5ecc defs $33 ; sprite 1
@label=buffers_item_2
$5eff defs $33 ; sprite 2
@label=buffers_item_3
$5f32 defs $33 ; sprite 3
@label=buffers_item_4
$5f65 defs $33 ; sprite 4
@defs=$5F98:$68,$00
; Unused padding.
s$5f98 defs $68
; #REGpc starts here, after game load.
@label=EntryPoint
c$6000 jp $61bf ;
; Platform positions and widths (in pixels).
;
; #TABLE(default,centre,:w)
; { =h Bytes(n) | =h Variable }
; { 1 | Colour Attribute }
; { 2 | X location }
; { 3 | Y location }
; { 4 | Width }
; TABLE#
@label=gfx_params_platforms
b$6003 defb $04,$80,$60,$1b ; Middle
$6007 defb $06,$78,$b8,$88 ; Bottom (ground)
$600b defb $04,$30,$48,$23 ; Left
$600f defb $04,$d0,$30,$23 ; Right
; Default player object state.
@label=default_player_state
b$6013 defb $01,$80,$b7,$47,$00,$00,$00,$24
; Default Rocket and module objects state.
@label=default_rocket_state
b$601b defb $09,$a8,$b7,$02,$01,$00,$00,$1c ; Rocket state
$6023 defb $04,$30,$47,$47,$00,$00,$10,$18 ; Top module state
$602b defb $04,$80,$5f,$47,$01,$00,$08,$18 ; Middle module state
; Default Rocket module state is a Fuel Pod.
@label=default_rocket_module_state
b$6033 defb $04,$00,$20,$43,$01,$00,$18,$18
; Default collectible item state.
@label=default_item_state
b$603b defb $0e,$00,$20,$00,$00,$00,$00,$18
; Main menu copyright message.
@label=menu_copyright
b$6043 defb $47 ; Text colour attribute
$6044 defb $5b ; Font code for © symbol
$6045 defm "1983 A.C.G. ALL RIGHTS RESERVE"
$6063 defb $c4 ; ASCII "D" & $80 (EOL)
; Reset the screen to its default state.
;
; Used by the routines at #R$6094, #R$60b7 and #R$61c9.
@label=ResetScreen
c$6064 xor a ;
$6065 out ($fe),a ; Set screen border to black
$6067 call $7180 ; Clear the screen
$606a call $718e ; Reset the screen colours
$606d call $715a ; Display score labels
; Display score labels text at the top of the screen.
$6070 ld hl,$5820 ; #REGhl=attribute file location
$6073 ld bc,$2046 ; #REGb=tile count, and #REGc=yellow colour
*$6076 ld (hl),c ; {Now set the tile colours
$6077 inc l ;
$6078 djnz $6076 ; }
$607a call $70e5 ; Update display with player 1 score
$607d call $70ed ; Update display with player 2 score
$6080 jp $70f5 ; Update display with high score
; Initialises a new level.
;
; A new Rocket is generated every 4 levels, otherwise it's a normal fuel
; collecting level. Used by the routines at #R$62fe and #R$6690.
@label=LevelNew
c$6083 ld a,($5df0) ; {Check if player level is a MOD of 4?
$6086 and $03 ; }
$6088 jr nz,$6094 ; If not, initialise the level normally
; Initialisation for a new rocket level.
$608a call $60a7 ; Reset all rocket modules with defaults
$608d ld hl,$5df1 ; {Jetman has boarded the rocket; increment lives count.
$6090 inc (hl) ; Used for display purposes only}
$6091 call $6174 ; Initialise the player for the next level
; Initialise the level.
;
; Used by the routines at #R$6083 and #R$60b7.
@label=LevelInit
c$6094 call $68f2 ; Initialise alien buffers
$6097 call $6064 ; Initialise the screen
$609a call $7638 ; Draw the platforms
$609d call $706d ; Display all player lives
$60a0 ld a,($5c78) ; {Set last_frame to current SYSVAR_FRAMES
$60a3 ld ($5dd4),a ; }
$60a6 ret ;
; Reset all rocket module states to their defaults.
;
; Set object data to their defaults and copy to buffers. Used by the routines
; at #R$6083 and #R$62da.
@label=RocketReset
c$60a7 ld hl,$601b ; #REGhl=default rocket data
$60aa ld de,$5d30 ; #REGde=start of rocket structs
$60ad ld bc,$0018 ; 24 bytes of rocket data to copy
$60b0 ldir ;
$60b2 ld a,$08 ;
$60b4 jp $6ec2 ; Copy sprite data to the buffers.
; End of turn for the current player.
;
; Resets level states/buffers, and checks if it's game over for a player. Used
; by the routine at #R$687a.
@label=PlayerTurnEnds
c$60b7 ld hl,$5d48 ; #REGhl=Jetman thruster animation object
$60ba ld b,$0a ; {Reset all object states to be inactive
$60bc call $6629 ; }
@ssub=ld hl,$5d38+$04 ; #REGhl=Rocket module "state" field
$60bf ld hl,$5d3c ;
$60c2 res 1,(hl) ; Set to unused state
@ssub=ld hl,$5d40+$04 ; #REGhl=Collectible item "state" field
$60c4 ld hl,$5d44 ;
$60c7 res 1,(hl) ; Set to unused state
; Check if current and inactive player has lives, if not it is game over.
$60c9 ld a,($5cf3) ; Game Options
$60cc and $01 ;
$60ce jr nz,$60dd ; Jump if two player
*$60d0 ld a,($5df1) ; Current player lives
$60d3 and a ;
$60d4 jp z,$612f ; Game over if no lives remaining
$60d7 call $6094 ; Initialise a new level
$60da jp $6174 ; Initialise next player
*$60dd ld a,($5df9) ; Inactive player lives
$60e0 and a ;
$60e1 jr z,$60d0 ; Game over if no lives remaining
$60e3 ld a,($5df1) ; Current player lives
$60e6 and a ;
$60e7 call z,$6127 ; Game over if no lives remaining
$60ea call $6144 ; Switch players
$60ed ld a,($5dd1) ; {Change current player (flip bits between $00 and $FF)
$60f0 cpl ;
$60f1 ld ($5dd1),a ; }
; Switch rocket objects data for this new player
@ssub=ld a,($5d30+$04) ; Rocket module "state" field
$60f4 ld a,($5d34) ;
$60f7 rlca ; {Calculate the offset
$60f8 rlca ;
$60f9 rlca ;
$60fa and $38 ; }
$60fc call $6ec2 ; Copy rocket sprite to buffer
$60ff call $6094 ; Initialise level
$6102 jp $6174 ; Initialise player
; Display the GAME OVER message for a player.
*$6105 ld a,$b1 ; ASCII character for the number "1" + EOL bit
@ssub=ld ($6161+$12),a ; Append the number to game over text
*$6107 ld ($6173),a ;
$610a call $6064 ; Initialise level screen
$610d ld de,$6161 ; Game Over message
@keep
$6110 ld hl,$7038 ; Y,X coords in the display file
$6113 call $7134 ; Draw text to the screen
; After displaying the text, pause for a while.
$6116 ld b,$04 ;
$6118 ld hl,$0000 ;
*$611b dec hl ;
$611c ld a,h ;
$611d or l ;
$611e jr nz,$611b ;
$6120 djnz $611b ;
$6122 ret ;
; Handle message for player #2.
*$6123 ld a,$b2 ; ASCII character for the number "2" + EOL bit
$6125 jr $6107 ; Append the number to the text, the display it
; Choose which player to show Game Over message for.
*$6127 ld a,($5dd1) ; {Jump if current player is #1
$612a and a ;
$612b jr z,$6105 ; }
$612d jr $6123 ; else, player is #2.
; Game Over: update scores, show game over message, and initialise system.
*$612f call $6361 ; Update the high score
$6132 ld a,($5dd1) ; {Jump if current player is #2
$6135 and a ;
$6136 jr nz,$613e ; }
$6138 call $6105 ; Display game over for player #1
$613b jp $61c9 ; Reset the game
*$613e call $6123 ; Display game over for player #2
$6141 jp $61c9 ; Reset the game
; Swap current/inactive player/rocket states.
;
; Used by the routines at #R$60b7 and #R$62da.
@label=PlayersSwap
c$6144 ld hl,$5df0 ; Current player level/lives
$6147 ld de,$5df8 ; Inactive player level/lives
$614a ld b,$02 ;
$614c call $6157 ; Swap 2 bytes
; Now swap the current/inactive rocket states.
$614f ld hl,$5d30 ; Current player rocker state
$6152 ld de,$5d98 ; Inactive player rocker state
$6155 ld b,$18 ; We will be swapping 24 bytes
; Sub-routine for swapping HL/DE bytes.
*$6157 ld a,(de) ;
$6158 ld c,(hl) ;
$6159 ld (hl),a ;
$615a ld a,c ;
$615b ld (de),a ;
$615c inc hl ;
$615d inc de ;
$615e djnz $6157 ;
$6160 ret ;
; Text for game over message.
@label=game_over_text
b$6161 defb $47 ; Colour attribute
$6162 defm "GAME OVER PLAYER "
$6173 defb $b1 ; Player # (ASCII $31/$32) + $80 (EOL)
; Initialise player for new turn.
;
; Player has died, or started a new level, so Jetman object should be updated
; with default values. Used by the routines at #R$6083, #R$60b7 and #R$66b4.
@label=PlayerInit
c$6174 ld hl,$6013 ; Default Jetman values
$6177 ld de,$5d00 ; Jetman object
$617a ld bc,$0008 ;
$617d ldir ;
; Set default "begin play" delay period.
$617f ld a,$80 ; 1 player delay
$6181 ld hl,$5cf3 ; Game options
$6184 bit 0,(hl) ;
$6186 jr z,$618a ; Jump if one player game
$6188 add a,$7f ; else, double delay for 2 player game
*$618a ld ($5dd7),a ; Update delay: 1 Player=$80, 2 Player=$FF
; Decrement current player lives and update display.
$618d ld a,($5df1) ; Current player lives
$6190 dec a ;
$6191 ld ($5df1),a ;
$6194 jp $706d ; Display player lives
; Flash 1UP or 2UP score label for active player.
;
; Used by the routine at #R$737d.
@label=ScoreLabelFlash
c$6197 ld a,($5dd1) ; Current player number
$619a and a ;
$619b jr nz,$61ba ; If player #2, flash 2UP text
$619d ld hl,$0018 ; else #REGhl=1UP column position in attr file
; Set flash state for the 3-attributes of the score label.
;
; Used by the routine at #R$61ba.
;
; Input:HL screen coordinate.
@label=FlashText
c$61a0 call $71d6 ; #REGhl=coord to attribute file address (using #REGhl)
$61a3 ld b,$03 ; Loop counter for 3 characters
*$61a5 ld a,(hl) ; {Set FLASH on for each attribute
$61a6 or $80 ;
$61a8 ld (hl),a ;
$61a9 inc hl ;
$61aa djnz $61a5 ; }
$61ac ret ;
; Turn off flashing of 1UP or 2UP score label for active player.
;
; Used by the routine at #R$737d.
;
; Input:HL screen coordinate.
@label=ScoreLabelUnflash
c$61ad call $71d6 ; #REGhl=coord to attribute file address (using #REGhl)
$61b0 ld b,$03 ; Loop counter for 3 characters
*$61b2 ld a,(hl) ; {Set FLASH=off on for each attribute
$61b3 and $7f ;
$61b5 ld (hl),a ;
$61b6 inc hl ;
$61b7 djnz $61b2 ; }
$61b9 ret ;
; Flash 2UP score label.
;
; Used by the routine at #R$6197.
@label=FlashScoreLabel2UP
c$61ba ld hl,$00d8 ; 2UP column position in attribute file
$61bd jr $61a0 ;
; Game initialisation for first run.
;
; Reset all scores, sets the SP, initialises the screen, and displays the main
; menu. Used by the routine at #R$6000.
@label=StartGame
c$61bf ld hl,$5cf0 ; {Reset all scores
$61c2 ld bc,$0a00 ;
*$61c5 ld (hl),c ;
$61c6 inc hl ;
$61c7 djnz $61c5 ; }
; Reset system and show menu screen.
;
; Used by the routine at #R$60b7.
@label=ResetGame
c$61c9 di ; Interrupts are disabled for the core engine code
@ssub=ld sp,$5ccb+$25 ; Set the stack pointer
$61ca ld sp,$5cf0 ;
$61cd call $6064 ; Reset the screen
$61d0 ld a,$04 ;
$61d2 ld ($5dca),a ; Reset velocity modifier to its default
; Show menu screen and handle menu selection.
@label=MenuScreen
c$61d5 call $6234 ; Draw the menu entries
$61d8 ld a,($5cf3) ; {#REGd=Game options
$61db ld d,a ; }
; Read the keyboard and perform menu selection.
$61dc ld a,$f7 ; Row: 1,2,3,4,5
$61de out ($fd),a ; Set port for reading keyboard
$61e0 in a,($fe) ; ...and read that row of keys
$61e2 cpl ; Flip bits so a `1` means a key is pressed.
$61e3 bit 0,a ; Key #1 pressed? ("1 PLAYER GAME")
$61e5 jr z,$61e9 ; No key pressed? Jump
$61e7 res 0,d ; else, Player count = 1
*$61e9 bit 1,a ; Key #2 pressed? ("2 PLAYER GAME")
$61eb jr z,$61ef ; No key pressed? Jump
$61ed set 0,d ; else, Player count = 2
*$61ef bit 2,a ; Key #3 pressed? ("KEYBOARD")
$61f1 jr z,$61f5 ; No key pressed? Jump
$61f3 res 1,d ; else, Input type = keyboard
*$61f5 bit 3,a ; Key #4 pressed? ("JOYSTICK")
$61f7 jr z,$61fb ; No key pressed? Jump
$61f9 set 1,d ; else, Input type = joystick
*$61fb bit 4,a ; {Key #5 pressed? ("START GAME")
$61fd jp nz,$62fe ; }
$6200 ld a,d ; {Update the Game options
$6201 ld ($5cf3),a ; }
; Update flashing state of the menu items.
@ssub=ld hl,$6261+$01
$6204 ld hl,$6262 ; Point #REGhl to main menu colour attributes list.
$6207 ld a,($5cf3) ; {#REGc=Game options
$620a ld c,a ; }
$620b bit 0,c ; {Jump if player count = 2
$620d jr nz,$621c ; }
$620f call $6226 ; Set flashing state for a one player game
*$6212 bit 1,c ; {Jump if input type = joystick
$6214 jr nz,$6221 ; }
$6216 call $6226 ; Set flashing state for keyboard input
*$6219 jp $61d5 ; Loop and process again main menu input
*$621c call $622d ; Set flashing state for a two player game
$621f jr $6212 ; Check input type
*$6221 call $622d ; Set flashing state for joystick input
$6224 jr $6219 ; Loop and process again menu selection
; Set flashing state for "1 PLAYER GAME" and "KEYBOARD" menu items.
*$6226 set 7,(hl) ;
$6228 inc hl ;
$6229 res 7,(hl) ;
$622b inc hl ;
$622c ret ;
; Set "2 PLAYER GAME" and "JOYSTICK" menu items flashing.
*$622d res 7,(hl) ;
$622f inc hl ;
$6230 set 7,(hl) ;
$6232 inc hl ;
$6233 ret ;
; Display the main menu items to the screen.
;
; Used by the routine at #R$61d5.
@label=MenuDrawEntries
c$6234 ld de,$6261 ; Point #REGde to main menu colour attributes
$6237 exx ;
$6238 ld hl,$6267 ; #REGhl'=Y (y-position of the menu item)
$623b ld de,$626d ; #REGde'=to the beginning of the menu strings
$623e ld b,$06 ; #REGb'=loop counter for the 6 colour attribute bytes
; Flip-flop between normal/shadow registers: meaning one time we hit this EXX
; we are using the shadow registers, the next the normal registers.
*$6240 exx ;
$6241 ld a,(de) ; #REGa=current colour attribute
$6242 ld ($5dd6),a ; Store menu colour attribute
$6245 inc de ;
$6246 exx ;
$6247 push bc ;
$6248 ld a,(hl) ;
$6249 inc hl ;
$624a push hl ;
$624b ld h,a ;
$624c ld l,$30 ; #REGl'=indentation
$624e call $62ca ; Write line of text to screen
$6251 exx ;
$6252 pop hl ;
$6253 pop bc ;
$6254 inc de ;
$6255 djnz $6240 ; Duel purpose loop: both colour attrs and menu items
@keep
$6257 ld hl,$b800 ; Set Y/X coords
$625a ld de,$6043 ; Point #REGde to the copyright string
$625d call $7134 ; Now display the copyright message
$6260 ret ;
; Colour attributes for main menu.
;
; #TABLE(default,centre,:w)
; { =h Bytes(n) | =h Menu Item }
; { 1 | Jetpac Game Selection }
; { 2 | 1 Player Game }
; { 3 | 2 Player Game }
; { 4 | Keyboard }
; { 5 | Joystick }
; { 6 | Start Game }
; TABLE#
@label=menu_colour_table
b$6261 defb $47,$47,$47,$47,$47,$47
; Vertical position of each line of text in the main menu.
;
; #TABLE(default,centre,:w)
; { =h Byte(n) | =h Menu Item }
; { 1 | Jetpac Game Selection }
; { 2 | 1 Player Game }
; { 3 | 2 Player Game }
; { 4 | Keyboard }
; { 5 | Joystick }
; { 6 | Start Game }
; TABLE#
@label=menu_position_table
b$6267 defb $20,$38,$48,$58,$68,$98
; Text displayed on the main menu screen
@label=menu_text
t$626d defm "JETPAC GAME SELECTIO"
$6281 defb $ce ; ASCII "N" & $80 (EOL)
$6282 defm "1 1 PLAYER GAM"
$6292 defb $c5 ; ASCII "E" & $80 (EOL)
$6293 defm "2 2 PLAYER GAM"
$62a3 defb $c5 ; ASCII "E" & $80 (EOL)
$62a4 defm "3 KEYBOAR"
$62af defb $c4 ; ASCII "D" & $80 (EOL)
$62b0 defm "4 JOYSTIC"
$62bb defb $cb ; ASCII "K" & $80 (EOL)
$62bc defm "5 START GAM"
$62c9 defb $c5 ; ASCII "E" & $80 (EOL)
; Write a single line of text on the main menu screen.
;
; Used by the routine at #R$6234.
;
; Input:HL Coordinate on the screen to display the string.
@label=MenuWriteText
c$62ca push hl ; Backup coordinate
$62cb call $72d0 ; #REGhl=coord to screen address (using #REGhl)
$62ce ld a,($5dd6) ; Current colour attribute
$62d1 ex af,af' ;
$62d2 exx ;
$62d3 pop hl ; Restore coordinate
$62d4 call $71d6 ; #REGhl=coord to attribute file address (using #REGhl)
$62d7 jp $7140 ; Display text string at #REGhl, using #REGa' colour
; Reset current and inactive player data on new game.
;
; Used by the routine at #R$62fe.
@label=ResetPlayerData
c$62da ld b,$02 ; Loop counter: current then inactive player
*$62dc push bc ;
$62dd xor a ;
$62de ld ($5df0),a ; Reset player level
$62e1 ld a,$04 ;
$62e3 ld ($5df1),a ; First player has 4 "remaining" lives
$62e6 call $60a7 ; Reset the rocket modules
$62e9 call $6144 ; Swap player game states
$62ec pop bc ;
$62ed djnz $62dc ; Repeat again for inactive player
$62ef ld a,$05 ; {But now update inactive player to have 5 "remaining"
$62f1 ld ($5df9),a ; lives, not 4}
$62f4 ld a,($5cf3) ; Game options
$62f7 and $01 ;
$62f9 ret nz ; Return if two player game
$62fa ld ($5df9),a ; else one player game, so inactive player has no lives
$62fd ret ;
; Start a new game.
;
; Resets all player, alien, and level data, then start a new game. Used by the
; routine at #R$61d5.
@label=NewGame
c$62fe ld hl,$5cf4 ; Starting at the Player 1 score
@nowarn
@keep
$6301 ld bc,$6000 ; #REGb = counter, #REGc = fill byte
$6304 call $7185 ; Clear memory, with null byte
$6307 call $62da ; Reset the player data
$630a call $6954 ; Reset the self-modifying code
$630d call $6083 ; Initialise a new level
; Reset stack pointer and enable interrupts before running main loop.
;
; If new item/alien was generated, this routine is called instead of MainLoop.
; .
; Used by the routine at #R$6971.
@label=MainLoopResetStack
@ssub=ld sp,$5ccb+$25 ; Set the stack pointer
c$6310 ld sp,$5cf0 ;
$6313 ei ;
$6314 ld ix,$5d30 ; #REGix=Rocket object
$6318 xor a ;
$6319 ld ($5dcb),a ; Reset current alien number
; The main game loop.
;
; This routine is called until a new item/alien is generated, then #R$6310 is
; called.
; .
; Used by the routines at #R$6310, #R$692e and #R$6971.
;
; Input:IX address of main jump table
@label=MainLoop
c$631c ld a,($5c78) ; {Compare SYSVAR_FRAMES and last_frame
$631f ld c,a ;
$6320 ld a,($5dd4) ;
$6323 cp c ; }
; Note: if we have EI here, then #R$692e will be called and DI executed.
$6324 call nz,$692e ; If they're not equal, do frame update
; When one of the `main_jump_table` update routines RETurns, the new game actor
; routine will be called.
@nowarn
$6327 ld hl,$6971 ; #REGhl=generate new actor routine
$632a push hl ; ...and push `ret` address to the stack.
; Execute one of the update routines using the value in IX.
$632b ld hl,$633d ; #REGhl=main jump table
$632e ld a,(ix+$00) ; {Calculate the jump table offset
$6331 rlca ;
$6332 and $7e ; }
; Performs a main loop update jump.
;
; Used by the routines at #R$631c and #R$648b.
;
; Input:A Offset for jump table address.
; HL Address to the jump table.
@label=PerformJump
c$6334 ld c,a ;
$6335 ld b,$00 ; #REGbc=offset: 34 max (size of jump table)
$6337 add hl,bc ; Set #REGhl to jump table address using offset
$6338 ld a,(hl) ; {Assign the jump address back to #REGhl
$6339 inc hl ;
$633a ld h,(hl) ;
$633b ld l,a ; }
$633c jp (hl) ; Use `jp` so `ret` calls the new actor/timer routine
; Main game loop jump table.
;
; Addresses for all the main routines to be updated per game loop.
@label=main_jump_table
w$633d defw $68e4 ; Frame rate limiter