-
Notifications
You must be signed in to change notification settings - Fork 0
/
jetboat-commented.asm
6397 lines (5408 loc) · 199 KB
/
jetboat-commented.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
; Disassembly and annotation of Jet Boat from Software Invasion
;
; Originally written by Robin J. Leatherbrow (c) Copyright 1984
;
; Disassembly labels and comments by Andy Barnes (c) Copyright 2021
;
; Twitter @ajgbarnes
; Notes on the game
; =================
;
; Code
; ----
; - Relocation code is from fn_start_point ($5DE1) onwards (all thrown away when game starts)
; - Main game entry code is at fn_game_start ($0BF8)
; - Main game loop is at main_game_loop ($0D16)
; - Seems well structured and through through
; - No overloadng of zero page locations (used for single purposes)
;
; Timers
; ------
; - "Interval timer crossing 0" used to decrement time remaining every 64 centiseconds
; - Pauses achieved by using the System VIA CA1 interrupts to wait 20ms * n
; (where n is the multiplier to give the required wait time e.g. 100 for 2 seconds)
;
; Screen
; ------
; - Intro screen(s) and high score screens are in MODE 7
; - Main game runs in MODE 5 with default configuration
; - Screen start address is $5800 and end address $7FFF
; - Screen is scrolled using the 6845 CRTC video controller (R12,R13)
;
; Game
; ----
; - There are no baddies - the only thing that moves around the map is the boat
; - Boat runs slower when it runs aground (doesn't get damaged)
; - Boat always appears in the centre of the screen and the screen scrolls around it
; - Boat can move in 16 compass directions and has a graphic for each
; - No other icon is animated (other than during colour cycling)
;
; Stages/Laps
; -----------
; - There are 13 stages in the game
; - Each new stage is a different colour (from one of four possible palettes)
; - Each new stage reduces the time available to complete a lap
; - Each stage is 11 laps - all having the same stage completion time
; - Each new lap adds additional hazards
; - The 14th stage has a zero time to complete so you automatically die
; - To complete a lap you must cross both a checkpoint in the centre of the map
; and also a lap marker
; - Centre checkpoint is satisfied for boat position (x,y) if 94<= x <110 and y= 14
; - Lap checkpoint is satisfied for boat position (x,y) if 24<= x <37 and y= 12
; - Centre checkpoint stops you cutting across the map or just looping back
; - "Prepare to enter the next stage" is shown between stages instead of the
; repeating Jetboat text at the start of the game
; - Lap times as stored are auto decremented by 1 before the game properly starts
; - Stage Lap times are therefore
; -> 70, 60, 51, 46, 41, 38, 36, 33, 31, 28, 26, 23, 21, 0
;
; Controls
; --------
; - Regardless of how you start the game, both joystick and keyboard inputs are checked
; - Keyboard is read using OSBYTE &81 rather than directly
; - Joystick x/y axis read via the ADC chip using OSBYTE &80
; - Joystick button read via the System VIA using OSBYTE &80
;
; Map
; ---
; - Map is 128 (x-axis) x 80 (y-tiles) tiles
; - Map is stored from $3000 and serialised by row
; - Each map position identifies a tile id
;
; Tiles
; -----
; - There are 256 ($00-$FF) possible different tile types
; - Each map tile is 8 bytes (4 pixels wide and 8 pixels high)
; - Tiles are stored sequentially at $2800 to $2FFF
; - Tile source graphics can be looked up using $2800 + (tile id * 8)
;
; Boat Graphics
; -------------
; - There are sixteen full boat sprites
; - One boat sprite for each point on the compass (N, NNW, W, WNW...)
; - Boat is EOR'd on and off the screen
; - Graphics are stored from $1E00 to $2FFF
; - In MDOE 5 a screen byte is 4 pixels wide
; - In MDOE 5 a screen byte is 1 pixel high
; - A boat sprite is 5 bytes wide
; - A boat sprite is 3 x 8 bytes high = 24 bytes high
; - A boat sprite is (5 x 24) = 120 bytes in total
; - A boat sprite is therefore (5 x 4) 20 pixels wide
; - A boat sprite is therefore (24 x 1) 24 pixels high
; - A boat sprite is therefore (24 x 20) 480 pixels in total
; - Boat sprites are stored from $1E00 to $27FF
; - Each boat sprite is 120 ($A0) bytes
; - Lookup table at boat_sprite_location_lsb/msb gives memory location for compass point
; - Boat moves speed is from $0A (slowest) to $00 (fastest), used also as duration for second
; "put" sound so useful to have it in this order
;
; Other Graphics
; --------------
; - Get Ready sprite is shown in the same position as the boat
; - Get Ready sprite is stored in $04A0 - $053F (relocated there when the game loads)
; - Get Ready sprite is the same size as the boat
; - Times Up! sprite is shown in the same position as the boat
; - Times Up! sprite is stored in $0400 - %04BF (relocated there when the game loads)
; - Times Up! sprite is the same size as the boat
;
; Movement
; --------
; - Compass direction that boat is facing determines speed and direction
; - Lookup table used to lookup compass direction of boat against speed/movement
; - Lookup table is at lookup_table_boat_direction_fns with each fn underneath
; - Each function determines how much up/down or left/right movement there should be
; - NNW wouldn't move W as fast as WNW as an example but faster N than WNW
; - N would have zero E or W movement but maximum N movement
; - E would have zero N or S movement but maximum E movement
; - Boat decelerates every third game loop
;
; Collision Detection
; -------------------
; - Flashing when run aground is achieved by colour cycling the logical/physical colours
; - Colour resets every 4th time around game loop
; - Boat is immediately slowed to slowest speed ($0A)
; - Logical colour 3 is cycled through the colours at palette_colour_cycle
; - Colour only changed and sound played every fourth time around the game loop
; - Magic happens in fn_toggle_boat_or_time_graphic
; - Tile to be written is EOR'd with what's already there and compared to original tile
; If it's the same, then no collision, if it's different then collision flag set
; Water is 0x00000000 so won't affect the EOR
; Blank tiles are not compared (ones with byte values of $00)
;
; Time remaining
; --------------
; - Time remaining is in 0.64 second units
; - Time remaining is decremented using the "interval timer crossing 0" timer
; - "Interval timer crossing 0" event is processed by setting the EVNTV vector to custom handler
; - Custom handler checks the event time is "Interval timer crossing 0" ($05) before doing anything
; - Interval timer is always set to 64 centiseconds (to decrement remaining time)
; - Interval timer is switched off when game not playing
; - Interval timer switched back on when game begins (after Jetboat repeating text has scrolled away)
;
; Hazards
; -------
; - Hazards are cumulative per stage lap (reset on new stage)
; - Hazards are stored in memory as described in hazards-formatted.asm but as a summary:
; - <# tiles wide>,<# tiles high>,<1st tile id>,<2nd tile id>...<nth tile id>,<instances>,<x0>,<x1>...<x>,<y0><y1>...<yn>
; - Hazard configuration for each hazard type is stored $1C00 to $1D0F
; - There a lookup table into this Hazard configuration for each configuration type
; - Hazard lookup table for each lap is held in hazard_lookup_table_lsb/msb
; - Hazards update the map to contain replace water with the hazard tiles
;
; Game Colours
; ------------
; - Bottom two bits of the stage number drive the palette colours
; - Four different colour schemes to choose from, used in rotation
; - Colour schemes stored at colour_bank_1/2/3
; - Logical colour 0 is always blue
;
; Sounds
; ------
; - Boat makes a 'put-put' sound - duration is inversely proportional to boat speed
; This is played on Channel 0 and set in fn_play_boat_sounds (two consecutive sounds)
; - Times up sound sounds like an alarm clock and uses Envelope 1 on Channel 1
; (see check_time_remaining)
; - Completed lap sound is like a short hornpipe tune using Envelope 2 on Channel 2
; (see completed_lap_next_sound)
; - Boat aground sound is two sounds and envelopes
; (see sound_boat_aground_first/second)
;
; Score
; -----
; - Score is updates every 16th time around the game loop (for just being alive)
; - Score can only be updated to a maximum of 2,000 per lap
; - On lap completion, remaining time is added to the score (time * 10)
; Runtime Memory Map
; ------------------
; From To Bytes Type Description
;
; 0400 049F 159 Graphics Load time times Up Clock Graphic
; 04A0 053F 159 Graphics Load time Get Ready Graphic
; 0540 0567 39 Graphics Score graphic
; 0568 0587 31 Graphics Time graphic
; 0588 5A7 31 Graphics Lap graphic
; 05A8 05AF 7 Graphics Blank graphic
; 05B0 05E0 48 Unused
; 05E1 05FF
; 0600 073F 319 Graphics Map tile buffer for row
; 0740 07E0 160 Graphics 0-9 number graphics
; 0800 08FF 511 Unused OS SOUND workspace
; 0900 09FF 255 Graphics Map tile buffer for column
; 0A00 0A07 7 Graphics Blank spacer
; 0A08 0A27 31 Graphics Runtime copy of time graphic
; 0A28 0A47 31 Graphics Blank spacer
; 0A48 0A4F 7 Graphics Runtime copy of the blank graphic
; 0A68 0A8F 39 Graphics Score icon
; 0A90 0ADF 79 Graphics Blank spacer (never written to)
; 0AE0 0AF7 23 Graphics Blank spacer (never written to)
; 0AF8 0B17 31 Graphics Runtime copy of lap graphic
; 0B18 0B37 31 Graphics Blank spacer (never written to)
; 0B38 0B3F 7 Graphics Runtime copy of the blank graphic
; 0B40 1DFF 4288 Code Main game code (see below)
; 1C00 1D0F 272 Data Hazards data
; 1D10 1DFF 240 Data high_score_screen
; 1E00 27FF 2560 Graphics Boat graphics
; 2800 2FFF 2048 Graphics Tile graphics
; 3000 57FF 10240 Data Map (co-ordinates to tile id)
; 5800 7FFF 10240 Screen Mode 5 screen memory
;
; Relocated Game Code Sub-routine Reference
; -----------------------------------------
;
; Once relocated, the main entry point is fn_game_start
;
; From To Bytes Sub-routine name
;
; 0B40 0B6C 45 fn_write_y_tiles_to_off_screen_buffer
; 0B6D 0B7B 15 fn_check_screen_start_address
; 0B7C 0BAB 48 fn_get_xy_tile_graphic_address
; 0BAC 0BDC 49 fn_write_x_tiles_to_off_screen_buffer
; 0BDD 0BF7 27 fn_break_handler
; 0BF8 0D90 409 fn_game_start
; 0D91 0D97 7 fn_read_key
; 0D98 0EBA 291 fn_scroll_screen_and_update
; 0EBB 0EDB 33 fn_set_6845_screen_start_address
; 0EDC 0EEB 16 fn_wait_20_ms
; 0EEC 0F2E 67 fn_copy_tile_column_to_screen
; 0F2F 0F3B 13 fn_check_joystick_left
; 0F3C 0F4C 17 fn_check_joystick_right
; 0F4D 0F5A 14 fn_check_joystick_button
; 0F5B 1013 185 fn_copy_tile_row_to_screen
; 1014 101D 10 fn_wait_for_n_interrupts
; 101E 1067 74 fn_copy_time_score_lap_to_screen_to_screen
; 1068 107F 24 fn_hide_cursor
; 1080 10B5 54 fn_set_game_colours
; 10B6 10C3 14 fn_change_colour_palette
; 10C4 10C7 4 colour_bank_1
; 10C8 10CB 4 colour_bank_2
; 10CC 10CF 4 colour_bank_3
; 10D0 10D4 5 colour_palette_block
; 10D5 10FB 39 fn_update_score
; 10FC 117F 132 fn_toggle_get_ready_icon
; 118A 120E 133 fn_screen_scroll_rotate_boat_flash_screen
; 120F 122E 32 boat_sprite_location lookup
; 122F 128C 94 fn_toggle_boat_on_screen
; 128D 1307 123 fn_check_keys_and_joystick
; 1308 1319 18 fn_calc_boat_direction_of_motion
; 131A 132F 22 lookup_table_boat_direction_fns
; 133A 138F 86 fn_boat_direction_N/NNE/NE/ENE/E/ESE/SE/SSE/S/SSW/SW/WSW/W/WNW/NW/NNW
; 139A 13A1 8 fn_accelerate_south
; 13A2 13A9 8 fn_move_to_half_south
; 13AA 13B1 8 fn_accelerate_east
; 13B2 13B9 8 fn_move_to_half_east
; 13BA 13C1 8 fn_accelerate_north
; 13C2 13C9 8 fn_move_to_half_north
; 13CA 13D1 8 fn_accelerate_west
; 13D2 13D9 8 fn_move_to_half_west
; 13DA 13E5 12 fn_adjust_east_west_for_full_north_or_south
; 13E6 13EF 10 fn_adjust_north_south_for_full_east_or_west
; 13F0 1411 37 Utility functions for above
; 1412 1414 3 Unused
; 1415 1450 60 fn_check_if_moving_up_or_down
; 1451 148C 60 fn_check_if_moving_left_or_right
; 148D 14E6 90 fn_colour_cycle_screen
; 14E7 14EE 8 sound_boat_aground_first
; 14EF 14F6 8 sound_boat_aground_second
; 14F7 14FE 8 palette_colour_cycle
; 14FF 1543 69 fn_init_graphics_buffers
; 1543 15AB 105 fn_calc_digits_for_display
; 15AC 15B7 12 fn_print_high_score_numbers
; 15B8 15DD 38 fn_draw_current_score
; 15DE 15F1 20 fn_draw_lap_counter
; 15F2 1602 17 fn_draw_time_counter
; 1603 1625 35 fn_set_timer_64ms
; 1626 162A 5 var_int_timer_value
; 162B 1632 8 sound_times_up
; 1633 163B 9 fn_enable_interval_timer
; 163C 1644 9 fn_disable_interval_timer
; 1645 16AC 104 fn_check_checkpoint_or_lap_complete
; 16AD 16BA 14 lap_times
; 16BB 16CD 19 fn_scroll_screen_up
; 16CE 16F2 37 fn_check_sound_keys
; 16F3 171E 44 fn_check_freeze_continue_keys
; 171F 174F 49 fn_add_time_to_score_and_display
; 1750 1754 5 pitch_table_completed_lap
; 1755 1759 5 duration_table_completed_lap
; 175A 1761 8 sound_completed_lap
; 1762 177B 26 fn_play_boat_sounds
; 177C 1783 8 sound_boat_move_first
; 1784 178B 8 sound_boat_move_second
; 178C 1796 11 duration_lookup_sound_table
; 1797 181E 136 fn_did_score_make_high_score_table
; 181F 18B1 147 fn_display_high_score_table
; 18B2 191E 109 fn_enter_high_score
; 191F 192C 14 fn_show_cursor
; 192D 1936 10 vdu_23_show_cursor_params
; 1937 193E 8 high_score_lsb
; 193F 1946 8 high_score_msb
; 1947 194E 8 high_score_name_lsb
; 194F 1956 8 high_score_name_msb
; 1957 19F7 161 high_score_names
; 19F8 1A2C 53 fn_display_press_space
; 1A2D 1A3E 18 fn_wait_for_intro_input
; 1A3F 1A6C 46 fn_show_player_score_below_high_scores
; 1A6D 1A8B 31 string_press_space_or_fire
; 1A8C 1AA4 25 string_enter_name
; 1AA5 1AB0 12 string_you_scored
; 1AB1 1ADC 44 fn_fill_screen_with_jet_boat
; 1ADD 1AE3 7 jet_boat_string
; 1AE4 1AF4 17 fn_set_colours_to_black
; 1AF5 1B02 14 fn_print_next_stage_text
; 1B03 1B46 68 string_next_stage
; 1B47 1BDA 148 fn_apply_or_reset_hazard_set
; 1BDB 1BE9 15 fn_setup_read_lookup_table
; 1BEA 1BF4 11 hazard_lookup_table_lsb
; 1BF5 1BFF 11 hazard_lookup_table_msb
; 1C00 1D0F 272 Hazards data
; 1D10 1DFF 240 high_score_screen
;
; Interesting pokes
; =================
; - Stop screen time decrementing
; Set timer_poke+1 to a high value to ignore all events
; e.g. ?&1603=&FF
;
; Evelopes from basic loader:
; ENVELOPE 1, 1,70,16,2,2,0,0,126, 0,0,-126,110,110
; ENVELOPE 2,129, 2, 0,0,0,0,0, 40,-8,0, -2,126, 45
; ENVELOPE 3,129, 1,-1,0,0,0,0, 0, 0,0, 0, 0, 0
; OSWRCH uses VDU values
; Write character (to screen) from Accumulator
OSWRCH = $FFEE
; Perfrom miscellaneous OS opferation using control block to pass parameters
OSWORD = $FFF1
; Perfrom miscellaneous OS operation using registers to pass parameters
OSBYTE = $FFF4
; Address of the memory mapped hardware
; for the 6845 CRTC video controller
SHEILA_6845_ADDRESS=$FE00
SHEILA_6845_DATA=$FE01
;System VIA Interrupt Flag Register
SYS_VIA_INT_REGISTER = $FE4D
;System VIA Interrupt Enable Register
SYS_VIA_INT_ENABLE = $FE4E
; VDU Variable for current screen mode
VDU_CURRENT_SCREEN_MODE = $0355
; Event vector for handling the interval
; timing crossing zero events
evntv_lsb_vector = $0220
evntv_msb_vector = $0221
; Start of the mode 7 screen memory address
mode7_start_addr = $7C00
; Dummy screen start address that is changed
; programatically in the LDA/STAs but defaults
; to this value at load
dummy_screen_start = $8000
; Dummy graphics start address that is changed
; programatically in the LDA/STAs but defaults
; to this value at load
dummy_graphics_load_start = $8000
; Screen graphics buffer (from $0A00 to $0B3F)
graphics_buffer_start = $0A00
; Unscrolled default memory address of the centre of the screen
mode_5_screen_centre = $6A10
; Zero page variables
; Indicates the direction the boat is facing
; and to what degree (can get inbetween values)
; 0 - going fully west
; 2 - going partly west
; 4 - heading neither west or east
; 6 - going partly east
; 8 - going fully east
zp_boat_east_west_amount = $0000
; Indicates the direction the boat is facing
; and to what degree (can get inbetween values)
; 0 - going fully north
; 2 - going partly north
; 4 - heading neither north or south
; 6 - going partly south
; 8 - going fully south
zp_boat_north_south_amount = $0001
; Compass direction that the boat is facing
; 0 - N
; 1 - NNE
; 2 - NE
; 3 - ENE
; 4 - E
; 5 - ESE
; 6 - SE
; 7 - SSE
; 8 - S
; 9 - SSW
; 10 - SW
; 11 - WSW
; 12 - W
; 13 - WNW
; 14 - NW
; 15 - NNW
zp_boat_direction = $0002
; Used to detect six subsequent left key events
; before processing it to prevent the boat turning
; too fast
zp_turn_left_counter = $0003
; Used to detect six subsequent right key events
; before processing it to prevent the boat turning
; too fast
zp_turn_right_counter = $0004
; Current speed of the boat - starts at $0A and to
; go faster the value decrements, fastest is zero
zp_boat_speed = $0005
; Used to detect six subsequent acceleration key events
; before processing it to prevent the boat accelerating
; too fast
zp_acceleration_counter = $0006
; Used to decelerate every third time around the game
; loop (reaches a maximum of $03)
zp_decelerate_counter = $0007
; Status flag used to indiciate if the boat is currently
; aground
; $00 - not aground
; $FF - aground
zp_boat_aground_status = $0008
; Used to throttle the colour cycling when the boat has
; run aground - only flashes every 4th time around
; the game loop
zp_aground_colour_cycle_counter=$0009
; Caches the required number of System VIA CA1 interrupts
; to wait for. One interrupt every 20 ms. Takes the value
; from the accumulator from the caller
zp_wait_interrupt_count = $000A
; Number of "chunks" remianing to copy into the
; offscreen buffer of the clock or boat
zp_graphics_chunks_remaining = $000B
; Flag to indicate whether the score has already been
; updated this game loop - gets updated when the
; screen cycles when aground as well as in the game loop so
; only update once
zp_score_already_updated_status = $000C
; Used to hold the value that needs to be converted into
; individual graphic digits e.g. score or lap or time remaining
zp_number_for_digits_lsb = $000D
zp_number_for_digits_msb = $000E
; Indicates whether the intro screen is showing
; Set to $FF is intro screen (Jet Boat Jet Boat...)
; is showing otherwise $00
zp_intro_screen_status = $000F
; Holds the current score - note this on screen
; it is suffixed with an extra 0
zp_score_lsb = $0010
zp_score_msb = $0011
; Stores the current lap for the current stage
; It's zero based not one based but displayed as
; one based
zp_current_lap = $0012
; Used by the generic routine that generates
; the number of graphics to display on the screen
; Score will be 5 digits, Lap 2, Time 2 etc
zp_display_digits = $0013
; Countdown timer for the number of time units (0.64 seconds)
; remaining for the current lap - game ends on
; zero. Lap time decreaes per stage
zp_time_remaining_secs = $0014
; Where the graphics 0 - 9 are held in memory
zp_graphics_numbers_lsb = $0015
zp_graphics_numbers_msb = $0016
; Offscreen buffer for the digits generated to be
; put on screen later
zp_graphics_numbers_target_storage_lsb = $0017
zp_graphics_numbers_target_storage_msb = $0018
; Limits the rate that the score updates to n game loops
zp_score_update_rate_limiter = $0019
; Maximum score increment per lap (excluding time bonus)
zp_score_max_lap_limit = $001A
; Address of the centre of the screen - used to place
; the boat and the start / times up clock - constantly
; recalculated as the screen scrolls
zp_screen_centre_lsb = $001B
zp_screen_centre_msb = $001C
; Number of horizintal bytes to scroll the jet boat or next
; stage screen to fully show the map - set to 40 / $27 because
; it's mode 5
zp_scroll_map_steps = $001D
; Flag to indicate if the boat has been through the
; checkpoint half way around the map - new lap won't start
; unless this is set
zp_checkpoint_status = $001F
; Players position in the high score table - working
; variable just used to find where to put the player's score
; and name
zp_high_score_position = $0020
; Used to display the high score names and to allow
; the player to enter their name (where it gets written)
zp_high_score_name_lsb = $0021
zp_high_score_name_msb = $0022
; Used to stop the score being updated when the jet boat or
; new stage text is on the screen and scrolling off
zp_pre_game_scrolling_status = $0023
; Used as a flag to indicate if a scroll down or up should happen
; during this game loop - if the boat isn't facing fully down or up
; i.e. only partially then this is used to only scroll / move down or up
; every other game loop
zp_north_or_south_on_this_loop_status = $0024
; Used as a flag to indicate if a scroll left or right should happen
; during this game loop - if the boat isn't facing fully left or right
; i.e. only partially then this is used to only scroll / move left or right
; every other game loop
zp_east_or_west_on_this_loop_status = $0025
; Set to the location of the get ready, times up or boat graphic
; and generic routine called to draw that item in the middle of the
; screen
zp_graphics_source_lsb = $0026
zp_graphics_source_msb = $0027
; At the start of a new game or stage, this is used to
; indicate that the hazard tiles should be reset to water tiles
; on the map
zp_reset_hazards_status = $002A
; Holds the location in memory of the current hazard configuration set
zp_hazard_config_lsb = $002B
zp_hazard_config_msb = $002C
; Working index used to add all the hazard tile rows to the map
; Gets initially set to zp_hazard_num_tiles_height and then decremented
zp_hazard_height_index = $002D
; Width (in tiles) of the current hazard
zp_hazard_num_tiles_width = $002E
; Height (in tiles) of the current hazard
zp_hazard_num_tiles_height = $002F
; Used to copy all the tiles from the configuration in normal
; memory into zero page memory - used as a max in the copying loop
zp_total_tiles_for_hazard = $0030
; Working index used to add all the hazard tiles on the current
; hazard row to the map e.g. islands are 9 tiles wide so have to copy
; 9 tiles to the map
; Gets initially set to zp_hazard_num_tiles_width and then decremented
zp_hazard_width_index = $0031
; How many of this hazard need to be added to the map
zp_total_hazard_occurrences = $0032
; Cache of the current hazard's tile types
zp_hazard_first_tile_type = $0033
; Cache of the current hazard's (x,y) co-ordinates
; Can have up to 14 instances - copied from the
; normal memory configuration
zp_hazard_first_x_coordinate = $0045
zp_hazard_first_y_coordinate = $0053
; Used to colour the Jet Boat text at the start
; of a new game - alternates between red and yellow
zp_text_colour = $0061
; Which stage the player is currently on
zp_current_stage = $0062
; Which lap in the current stage the player is on
zp_laps_for_current_stage = $0063
; Indicates if all the laps in the the current
; stage have been completed
; $00 not complete
; $FF complete
zp_stage_completed_status = $0064
; Based on the direction that the boat is facing
; this is used to determine which function to call to
; adjust the speed and direction to move - lookup
; table called and function address cached here
zp_addr_fn_boat_direction_lsb = $0065
zp_addr_fn_boat_direction_msb = $0066
; Used for two purposes - where to copy the tile graphics onto the
; screen and also where on the map in memory to update the tile type
; for a hazard
zp_graphics_tiles_storage_lsb = $0070
zp_graphics_tiles_storage_msb = $0071
; Used to store working values for memory addresses
zp_general_purpose_lsb = $0072
zp_general_purpose_msb = $0073
; Centre point of the map on the screen
; Defaults to (x) $75 (y) $0B
zp_map_pos_x = $0074
zp_map_pos_y = $0075
; Stores the low byte of the screen start address
; that has been divided by 8
zp_screen_start_div_8_lsb = $0076
; Position of the boat on the screen in (x,y) map co-ordinates
zp_boat_xpos = $0077
zp_boat_ypos = $0078
; Depending on the direction the boat is facing, these
; flags are set to the scroll the screen in the right
; direction
zp_scroll_east_status = $0079
zp_scroll_west_status = $007A
zp_scroll_north_status = $007B
zp_scroll_south_status = $007C
; Screen start address - used in the 6845 R12,R13
; for hardware scrolling
zp_screen_start_msb = $007E
zp_screen_start_lsb = $007D
; Break Intercept vectors
break_intercept_jmp_vector = $0287
break_intercept_lsb_vector = $0288
break_intercept_msb_vector = $0289
; Used to relocate the game and graphics when the game
; first loads
copy_from_lsb = $0000
copy_from_msb = $0001
copy_to_lsb = $0002
copy_to_msb = $0003
copy_size = $0004
copy_num_pages = $0005
; Where in memory the BASIC loader puts the
; user selectd keyboard control INKEY values
left_key_value = $7BC0
right_key_value = $7BC1
accel_key_value = $7BC2
; Where in memory the BASIC loader puts the
; user selected keyboard control descriptions
left_key_string_from_loader = $7BD0
right_key_string_from_loader = $7BE0
accel_key_string_from_loader = $7BF0
; Main game code executes at $0B40 onwards
; Compile here and move later to where it gets loaded above
; $1100
ORG &0B40
.main_code_block
;0B40
.fn_write_y_tiles_to_off_screen_buffer
; ---------------------------------------------------------
; Gets a vertical column of tile graphics and
; puts them in the off screen buffer (to either)
; scroll east or west - they are not written to the screen
; here
; ---------------------------------------------------------
; Define the off screen buffer where we'll
; assemble the right tile graphics for a new column
; in this case at $0900 - only used for y scrolling
LDA #$00
STA zp_graphics_tiles_storage_lsb
LDA #$09
STA zp_graphics_tiles_storage_msb
; 32 tiles are required (one for each row in the column)
LDX #$1F
;0B4A
.loop_get_next_y_tile
; Get the memory address of the nth tile's
; source graphic
JSR fn_get_xy_tile_graphic_address
; Copy all 8 bytes of the graphic...
LDY #$07
.loop_next_tile_byte
; ...to the off screen buffer
LDA (zp_general_purpose_lsb),Y
STA (zp_graphics_tiles_storage_lsb),Y
DEY
; If there are still some bytes left to copy
; loop around
BPL loop_next_tile_byte
; Increment the write address of the off screen
; buffer by 8 bytes
LDA zp_graphics_tiles_storage_lsb
CLC
ADC #$08
STA zp_graphics_tiles_storage_lsb
; Increment the y position in the (x,y)
; coordinates
INC zp_map_pos_y
LDA zp_map_pos_y
; The y position can only go up to $4F / 79
CMP #$50
BNE get_next_tile
; Reset the y position in the (x,y)
; coordinates to 0 when greater than or equal
; to $50 / 80
LDA #$00
STA zp_map_pos_y
.get_next_tile
; Do we still have some of the ($1F) 32 tiles to get?
DEX
BPL loop_get_next_y_tile
RTS
; L0B6D
.fn_check_screen_start_address
; ---------------------------------------------------------
; Check that the screen start address is between
; $5800 and $7FFF and, if not, adjust it
; ---------------------------------------------------------
; When scrolling down,
; if the screen start address is > $7FFF
; then we need to wrap it back to $5800
; which is achieved by subtracting $2800
CMP #$80
BCS reset_screen_to_start
; When scrolling up,
; if the screen start address is < $5800
; then we need to wrap it back to $8000
; which is achieved by adding $2800
CMP #$58
BCC reset_screen_to_end
RTS
.reset_screen_to_start
; Subtract $2800 to wrap it around
SBC #$28
RTS
.reset_screen_to_end
; Add $2800 to wrap it around
ADC #$28
RTS
;0B7C
.fn_get_xy_tile_graphic_address
; ---------------------------------------------------------
; This routine is called with an (x,y) tile coordinates
; stored in zero page zp_map_pos_x/zp_map_pos_y
;
; This routine does two key things:
; 1. Works out the tile type for the (x,y)
; 2. Looks up where the tile graphic data is held in memory;;
;
; All the tile type data for all (x,y) coordinates is held
; starting at $3000.
;
; 0 =< x < 128
; 0 =< y < 80
;
; So 128 tiles across the map
; So 80 tiles down the map
;
; Simple algorithm for (x,y) tile type lookup
;
; Tile type memory address = $3000 + (y * 128) + x
; or
; Code does this = $3000 + ($y00 / 2) + x
;
; So first x row (y=0) is stored $3000 to $307F
; Next x row (y=1) is stored $3080 to $30FF
; ...
; Last x row (y=80) is stored $5780 to $57FF
;
; This is then used to look up the tile graphic
; ---------------------------------------------------------
; Treats y as $y00 and divides by 2 and adds x
LDA zp_map_pos_y
LSR A
STA zp_general_purpose_msb
LDA #$00
ROR A
ADC zp_map_pos_x
STA zp_general_purpose_lsb
; If carry was set adding to the lsb
; branch and increment the MSB
BCS increment_tile_lookup_msb
.get_tile_type_and_graphic_address
; Add $3000 to the address
LDA #$30
ADC zp_general_purpose_msb
STA zp_general_purpose_msb
LDY #$00
; Find the tile at this (x,y) co-ordinate
; using the table at $3000+
LDA (zp_general_purpose_lsb),Y
; Now we have the tile type
; reuse the same zero page locations
; to store the tile graphic location
;
; Reset the MSB to zero
; Simple algorithm for tile type to memory location
;
; tile graphic address = $2800 + (type * 8)
; Set MSB to zero from Y
STY zp_general_purpose_msb
; Multiple type by eight
ASL A
ROL zp_general_purpose_msb
ASL A
ROL zp_general_purpose_msb
ASL A
ROL zp_general_purpose_msb
; Store LSB and MSB
STA zp_general_purpose_lsb
LDA zp_general_purpose_msb
; Add $2800 to address
ADC #$28
STA zp_general_purpose_msb
; Finished
RTS
.increment_tile_lookup_msb
; Move to the next page of memory
INC zp_general_purpose_msb
; Carry can never be set here, this just ends the function
BCC get_tile_type_and_graphic_address
;0BAC
.fn_write_x_tiles_to_off_screen_buffer
; ---------------------------------------------------------
; Gets a horizontal row of tile graphics and
; puts them in the off screen buffer (to either)
; scroll up or down - they are not written to the screen
; here
; ---------------------------------------------------------
; Set the Tile graphic off screen buffer - $0600
; This is used for rows of tiles only
LDA #$00
STA zp_graphics_tiles_storage_lsb
LDA #$06
STA zp_graphics_tiles_storage_msb
; In Mode 5 the screen has $27 / 39 columns of bytes
; So we need tiles for all of those bytes
LDX #$27
.loop_get_next_x_tile
; Find the source address for the tile
; The tile graphics at this address
; are going to be copied into the off
; screen buffer - address will be held
; in zp_general_pupose_lsb/msb
JSR fn_get_xy_tile_graphic_address
; MODE 5 screen is blocks of 8 bytes per x/y
; position
LDY #$07
.loop_copy_map_tile_block
; Load the first map tile (it's 8 bytes)
; and store it in the graphic buffer storage
; location
LDA (zp_general_purpose_lsb),Y
; Store the tile in $06xx
STA (zp_graphics_tiles_storage_lsb),Y
; If we don't have all 8 bytes then loop again
DEY
BPL loop_copy_map_tile_block
; Calculate next tile address by adding
; 8 bytes to the LSB
LDA zp_graphics_tiles_storage_lsb
CLC
ADC #$08
STA zp_graphics_tiles_storage_lsb
; Increment the MSB if it carried
LDA zp_graphics_tiles_storage_msb
ADC #$00
STA zp_graphics_tiles_storage_msb
; x axis only goes to 128 so if we reach
; 128 we need to reset to zero
INC zp_map_pos_x
BIT zp_map_pos_x
BPL skip_x_reset
; Reset the y position to 0 as it went above 128
LDA #$00
STA zp_map_pos_x
.skip_x_reset
; Loop until we have loaded all the map tiles
; in the offscreen buffer
DEX
BPL loop_get_next_x_tile
RTS
; 0BDD
.fn_break_handler
; ---------------------------------------------------------
; Break intercept vector routine - although NEVER
; called in the game because the JMP vector is set to
; $00 and not $4C - also fn_game_start performs
; a *FX 200,3 which clears memory on break
; ---------------------------------------------------------
;
; Check to see if the CTRL key was also pressed
LDX #$FE
CLI
JSR fn_read_key
; Just break not ctrl-break so restart the game
CPX #$00
BEQ fn_game_start
; Otherwise clear the break intercept handler (remove the JMP instruction)
LDA #$00
STA break_intercept_jmp_vector
; Set memory to be cleared on Break (*FX 200,2)
LDA #$C8
LDX #$02
LDY #$00
JSR OSBYTE
;0BF5
; Hang on break with an infinite loop
.break_infinite_loop
JMP break_infinite_loop
;0BF8
.fn_game_start
; --------------------------------------------