;=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
;
; Auto-generated by Regenerator 2000 v0.9.17
; https://github.com/ricardoquesada/regenerator2000
;
; Exported from: c64_burnin_rubber.regen2000proj
;
; Assemble with 64tass:
; 64tass -o c64_burnin_rubber.prg c64_burnin_rubber.asm
;
;=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
; EXTERNAL LABELS
; zpa_ = Zero Page Absolute Address
; f_ = Field
; a_ = Absolute Address
; p_ = Pointer
; e_ = External Jump
; L_ = Other / User-defined
; (ext) = External File Label
zpa_01 = $01 ; x-ref: $1809, $180D, $1812, $1816
zp_p_tmp_lo = $49 ; x-ref: $130B, $1315, $131A, $1326, $132B, $1347, $134C, $135A, ...
zp_p_tmp_hi = $4a ; x-ref: $130F, $131C, $1320, $132F, $1336, $133B, $134E, $1352, ...
zp_rnd_car_type_byte = $8c ; x-ref: $4A14
zp_rnd_direction_byte = $8d ; x-ref: $4AEB
zp_rnd_speed_byte = $8e ; x-ref: $4AF2, $4D9E
zp_rnd_pos_byte = $8f ; x-ref: $4A4D, $4A5A, $4A67, $4A74, $4A81, $4AAD
zp_key_scan = $c5 ; x-ref: $3FD8, $5239, $523F, $5245, $5270, $530A, $534C, $5400, ...
zp_joy_state = $f5 ; x-ref: $11D6, $11E4, $17A6, $17AD, $1A00, $1D83, $4410, $49ED, ...
IRQ_VEC_LO = $0314 ; IRQ ; x-ref: $1298
IRQ_VEC_HI = $0315 ; IRQ ; x-ref: $1293
p_03D9 = $03d9 ; x-ref: $4DC3, $4DC7
SCREEN_RAM = $0400 ; x-ref: $1057, $1132, $1B10, $1B14, $3C2D, $3C31, $4D4F, $4D53
SCREEN_RAM_R0C3 = $0403 ; x-ref: $16FA
SCREEN_RAM_R0C14 = $040e ; x-ref: $1703
SCREEN_RAM_R0C25 = $0419 ; x-ref: $1FB6, $1FC6, $1FD6, $1FE2
SCREEN_RAM_R0C26 = $041a ; x-ref: $1FB1, $1FC1, $1FD1, $1FDD
SCREEN_RAM_R0C32 = $0420 ; x-ref: $16B6
SCREEN_RAM_R0C33 = $0421 ; x-ref: $16BF
SCREEN_RAM_R0C38 = $0426 ; x-ref: $16C8
SCREEN_RAM_R0C39 = $0427 ; x-ref: $16D1
SCREEN_RAM_R1C0 = $0428 ; x-ref: $135C, $1399, $1B8E, $50D5
SCREEN_RAM_R2C0 = $0450 ; x-ref: $4AA5, $4AA9
SCREEN_RAM_R3C11 = $0483 ; x-ref: $1413
SCREEN_RAM_R4C0 = $04a0 ; x-ref: $1B65
SCREEN_RAM_R5C8 = $04d0 ; x-ref: $111E
SCREEN_RAM_R5C10 = $04d2 ; x-ref: $1428
SCREEN_RAM_R5C23 = $04df ; x-ref: $143B
SCREEN_RAM_R5C24 = $04e0 ; x-ref: $1444
SCREEN_RAM_R6C16 = $0500 ; x-ref: $105D, $1121, $1138, $1717, $503D, $5069
SCREEN_RAM_R6C23 = $0507 ; x-ref: $5050
SCREEN_RAM_R7C12 = $0524 ; x-ref: $1452
SCREEN_RAM_R9C11 = $0573 ; x-ref: $1498
SCREEN_RAM_R9C12 = $0574 ; x-ref: $146E, $1481
SCREEN_RAM_R9C13 = $0575 ; x-ref: $148A
SCREEN_RAM_R9C16 = $0578 ; x-ref: $1B6B, $4615
SCREEN_RAM_R9C23 = $057f ; x-ref: $18C0
SCREEN_RAM_R9C26 = $0582 ; x-ref: $18CF
SCREEN_RAM_R9C27 = $0583 ; x-ref: $18D2
SCREEN_RAM_R11C3 = $05bb ; x-ref: $1E01
SCREEN_RAM_R11C17 = $05c9 ; x-ref: $14AD
SCREEN_RAM_R11C19 = $05cb ; x-ref: $1DD8, $1E2B
SCREEN_RAM_R11C20 = $05cc ; x-ref: $1DE1, $1E34
SCREEN_RAM_R12C32 = $0600 ; x-ref: $1063, $1124, $113E, $171D
SCREEN_RAM_R13C16 = $0618 ; x-ref: $1CA0, $1F11, $4685
SCREEN_RAM_R13C20 = $061c ; x-ref: $1CC8
SCREEN_RAM_R14C33 = $0651 ; x-ref: $5307, $5349
SCREEN_RAM_R14C34 = $0652 ; x-ref: $5302, $5344
SCREEN_RAM_R15C16 = $0668 ; x-ref: $1CA6, $1F30, $4695
SCREEN_RAM_R15C20 = $066c ; x-ref: $1CD1
SCREEN_RAM_R15C32 = $0678 ; x-ref: $1B71
SCREEN_RAM_R16C11 = $068b ; x-ref: $14C5
SCREEN_RAM_R16C23 = $0697 ; x-ref: $154E
SCREEN_RAM_R16C32 = $06a0 ; x-ref: $1127
SCREEN_RAM_R17C16 = $06b8 ; x-ref: $1CAC, $1F4F, $46A5
SCREEN_RAM_R17C20 = $06bc ; x-ref: $1CDA
SCREEN_RAM_R18C14 = $06de ; x-ref: $1567
SCREEN_RAM_R18C32 = $06f0 ; x-ref: $1069, $1144, $1723, $1B77
SCREEN_RAM_R19C16 = $0708 ; x-ref: $1CB2, $1F6E, $46B5
SCREEN_RAM_R19C20 = $070c ; x-ref: $1CE3
SCREEN_RAM_R20C39 = $0747 ; x-ref: $1505, $493D
SCREEN_RAM_R21C0 = $0748 ; x-ref: $4931
SCREEN_RAM_R21C1 = $0749 ; x-ref: $4937
SCREEN_RAM_R21C11 = $0753 ; x-ref: $490E
SCREEN_RAM_R21C14 = $0756 ; x-ref: $536A
SCREEN_RAM_R21C16 = $0758 ; x-ref: $1CB8, $1F89, $46C1
SCREEN_RAM_R21C20 = $075c ; x-ref: $1CEC
SCREEN_RAM_R22C0 = $0770 ; x-ref: $4925, $4934
SCREEN_RAM_R22C1 = $0771 ; x-ref: $492B, $493A
SCREEN_RAM_R22C2 = $0772 ; x-ref: $44C8
SCREEN_RAM_R22C3 = $0773 ; x-ref: $44CF
SCREEN_RAM_R22C10 = $077a ; x-ref: $44DE
SCREEN_RAM_R22C11 = $077b ; x-ref: $4908, $4911
SCREEN_RAM_R23C0 = $0798 ; x-ref: $4919, $4928
SCREEN_RAM_R23C1 = $0799 ; x-ref: $491F, $492E
SCREEN_RAM_R23C2 = $079a ; x-ref: $451D
SCREEN_RAM_R23C3 = $079b ; x-ref: $44B8
SCREEN_RAM_R23C6 = $079e ; x-ref: $4522
SCREEN_RAM_R23C7 = $079f ; x-ref: $44F2
SCREEN_RAM_R23C8 = $07a0 ; x-ref: $44F7
SCREEN_RAM_R23C9 = $07a1 ; x-ref: $44FC
SCREEN_RAM_R23C10 = $07a2 ; x-ref: $44E3
SCREEN_RAM_R23C11 = $07a3 ; x-ref: $4902, $490B
SCREEN_RAM_R24C0 = $07c0 ; x-ref: $491C
SCREEN_RAM_R24C1 = $07c1 ; x-ref: $4922
SCREEN_RAM_R24C2 = $07c2 ; x-ref: $44ED
SCREEN_RAM_R24C3 = $07c3 ; x-ref: $44D4
SCREEN_RAM_R24C10 = $07ca ; x-ref: $44E8
SCREEN_RAM_R24C11 = $07cb ; x-ref: $4905
sprite_ptr_0 = $07f8 ; x-ref: $104E, $10E4, $15EC, $1752, $1A2A, $1A87, $1A96, $1AAD, ...
sprite_ptr_1 = $07f9 ; x-ref: $10E9, $13BA, $49CD, $49D4, $49D9, $49DF, $49E4, $4A1F, ...
sprite_ptr_2 = $07fa ; x-ref: $10EE, $13C0
sprite_ptr_3 = $07fb ; x-ref: $10F3
sprite_ptr_4 = $07fc ; x-ref: $10F8
sprite_ptr_5 = $07fd ; x-ref: $10FD, $3CCD, $45E0
sprite_ptr_6 = $07fe ; x-ref: $1102
sprite_ptr_7 = $07ff ; x-ref: $1164, $46F3
level_nr = $0800 ; x-ref: $1202, $125A, $1303, $1574, $1577, $1FA7, $4878, $4F04, ...
level_block_idx = $0801 ; x-ref: $1207, $1306, $1378, $137B, $1583, $4898, $48B5
level_tile_y_offset = $0802 ; x-ref: $120C, $1340, $136D, $1375, $1588, $4875
season_nr = $0803 ; x-ref: $1211, $135F, $139C, $1542, $158B, $158E, $1597, $1726, ...
player_speed = $0804 ; x-ref: $1216, $1235, $1778, $3BE3, $3C02, $3E13, $3E1D, $3E42, ...
player_is_jumping = $0805 ; x-ref: $1230, $12C0, $1761, $182D, $1A08, $1A17, $1A3A, $1AD9, ...
jump_anim_frame = $0806 ; x-ref: $1A1C, $1AEB, $1AEE
player_x_offset = $0807 ; x-ref: $1247
player_y_offset = $0808 ; x-ref: $124A, $4404, $440C
jump_timer_base = $0810 ; x-ref: $1A1F, $1A45, $1AFB
jump_frame_timer = $0811 ; x-ref: $1A25, $1A40, $1A4B
crashed_cars_tens = $0820 ; x-ref: $121C, $1435, $145F, $147B, $16A3, $179C, $1885, $4E39
crashed_cars_ones = $0821 ; x-ref: $1226, $143E, $1464, $1484, $16A6, $16B9, $185B, $4E27, ...
lives_tens = $0822 ; x-ref: $16C2, $480F, $4812, $481B, $486B, $4985
lives_ones = $0823 ; x-ref: $122B, $16CB, $3FC7, $4800, $4803, $480C, $4861, $4979, ...
score_7digits = $0825 ; x-ref: $15AB, $15B7, $15BE, $15CB, $15D7, $15DE, $16F4, $17E2, ...
scroll_row_counter = $0827 ; x-ref: $4940, $4948, $4952, $498C
crashed_cars_bonus_10k = $0830 ; x-ref: $1852, $1866, $1872, $1879, $1890, $189C, $18A3, $18B1, ...
crashed_cars_bonus_1k = $0831 ; x-ref: $1855, $18FE
crashed_cars_bonus_100 = $0832 ; x-ref: $1858, $18DD
name_entry_substate = $0857 ; x-ref: $1BAE, $1C28, $1C40, $1C54, $1C68, $1C7C, $1CF7, $1D0F, ...
highscore_timer_tens = $0858 ; x-ref: $1D5F, $1DBF, $1DC5, $1DC8, $1DD2, $1E25, $46C9
highscore_timer_ones = $0859 ; x-ref: $1D64, $1DAD, $1DB3, $1DBC, $1DCD, $1DDB, $1E2E, $46CE
scroll_switch_timer_2 = $085a
pickup_mode_active = $085e ; x-ref: $124F, $46EC, $4709, $4712, $471F, $4728
pickup_display_timer = $085f ; x-ref: $470E, $4718
active_row = $0860 ; x-ref: $1D69, $1E48, $1E65, $1E6F, $1E72, $1E78, $1E82, $1E85, ...
active_col = $0861 ; x-ref: $1D6E, $1E43, $1E8B, $1E95, $1E98, $1E9B, $1EA1, $1EAB, ...
game_over_delay_ctr = $08c0 ; x-ref: $4624, $4631
collision_rel_x = $08d3 ; x-ref: $39B4, $39BD, $3A03, $3B2F, $3B47, $3B7B
collision_rel_y = $08d4 ; x-ref: $39E1, $39EA, $3A08, $3A27, $3B80, $3B9F, $3EF4
joy_poll_timeout = $08da ; x-ref: $51E3, $51F7
score_digits = $08e0 ; x-ref: $123A, $176B, $3E24, $3E2A, $3E33, $3E53, $3E59, $3E62, ...
speed_tens_digit = $08e1 ; x-ref: $1242, $1773, $44AC
speed_hundreds_digit = $08e2 ; x-ref: $123D, $176E, $445C, $44A7
busy_wait_delay_ctr = $08ff ; x-ref: $48E2, $48EF
f_0900 = $0900 ; x-ref: $1263, $3BD8, $3BF6, $4C68, $4C74, $4C83, $4CB1, $4CCB, ...
f_0904 = $0904 ; x-ref: $4AEF, $4C21, $4D6E, $4D83, $4D8A, $4D92
f_0908 = $0908 ; x-ref: $4AF6, $4C19, $4DA2
tbl_enemy_sprite_state = $090c ; x-ref: $3A52, $3C73, $3D07, $3D4C, $4B00, $4B0C, $4C02, $5230
tbl_enemy_sprite_direction = $0910 ; x-ref: $3A0F, $3A14, $3A1C, $3A21, $3A2E, $3A33, $3A3B, $3A40, ...
tbl_enemy_sprite_step_count = $0914 ; x-ref: $3A82, $3AA6, $3BCA, $3D21, $3D52, $3D6E, $3D8A, $4B06
f_0918 = $0918 ; x-ref: $4B09
tbl_enemy_sprite_lifetime = $0920 ; x-ref: $3AB2, $3ABA, $3AC6, $3ACE, $3BF0, $3D3F, $4B0F
tbl_enemy_sprite_active = $0924 ; x-ref: $3A43, $3A48, $3A5A, $3A5D, $3BBD, $3C6C, $3D02, $3D49, ...
tbl_enemy_car_state = $0928 ; x-ref: $177D, $3982, $3996, $3B07, $3C80, $3EEE, $4554, $49C6, ...
tbl_enemy_car_state_1 = $0929 ; x-ref: $1780
tbl_enemy_car_state_2 = $092a ; x-ref: $1783
tbl_enemy_car_state_3 = $092b ; x-ref: $1786
tbl_enemy_car_type = $092c ; x-ref: $3A64, $3A68, $3A89, $3A8D, $3AA9, $3ABD, $3BC3, $3C88, ...
tbl_npc_damage_timer = $0930 ; x-ref: $3C94, $45CD, $4E66
tbl_enemy_car_fresh_flag = $0934 ; x-ref: $4EF1, $4F25, $4FA9
tbl_score_sprite_active = $0980 ; x-ref: $1789, $3C99, $3CD2, $45D2, $45E5, $4E9A, $4EAC
tbl_score_sprite_active_1 = $0981 ; x-ref: $178C
tbl_score_sprite_active_2 = $0982 ; x-ref: $178F
f_0983 = $0983 ; x-ref: $3CAC, $4E3D, $4EA5
scroll_row_snapshot = $0986 ; x-ref: $1252, $4943, $494C, $4956, $498F
dist_substep = $0987 ; x-ref: $1255, $4961, $4967, $4970
col_quadrant = $0988 ; x-ref: $3B87, $3B94, $3BA6, $3BB3, $3DB6, $3E08, $3EA0
col_step_px = $0989 ; x-ref: $3BD0, $3DC1, $3DDE
col_active = $098a ; x-ref: $1792, $17A0, $17CE, $3BC0, $3DB0, $3DDA, $3DF7
col_frames_left = $098b ; x-ref: $3C0F, $3DD2, $3DEF
f_0A00 = $0a00 ; x-ref: $125D, $500C, $50AF, $51AC
buf_a_pending_cars_lo = $0a22 ; x-ref: $5116, $5181
buf_a_pending_cars_hi = $0a23 ; x-ref: $5111, $517C
f_0B00 = $0b00 ; x-ref: $1266, $5012, $50B5, $51B2
f_0C00 = $0c00 ; x-ref: $1260, $5025, $5096, $518B
buf_c_pending_cars_lo = $0c22 ; x-ref: $5123, $51A2
buf_c_pending_cars_hi = $0c23 ; x-ref: $511E, $519D
f_0D00 = $0d00 ; x-ref: $1269, $502B, $509C, $5191
number_of_players = $0f00 ; x-ref: $3FE7, $3FEF, $5003, $507B, $50BE, $5100
current_player_nr = $0f01 ; x-ref: $3FE4, $3FF4, $501C, $504A, $508E, $50A7, $50C8, $510A, ...
hi_score_7digits = $0f50 ; x-ref: $1198, $16FD, $17DF, $17F4
COLOR_RAM = $d800 ; x-ref: $1073, $1E3F, $4637
COLOR_RAM_R1C0 = $d828 ; x-ref: $1365, $13A2, $172C, $1B7C, $1B93
COLOR_RAM_R2C0 = $d850 ; x-ref: $1078
COLOR_RAM_R3C0 = $d878 ; x-ref: $107B
COLOR_RAM_R3C11 = $d883 ; x-ref: $1418
COLOR_RAM_R5C0 = $d8c8 ; x-ref: $1080
COLOR_RAM_R5C10 = $d8d2 ; x-ref: $142D
COLOR_RAM_R6C0 = $d8f0 ; x-ref: $114E
COLOR_RAM_R6C16 = $d900 ; x-ref: $172F, $1B7F, $5042, $5072
COLOR_RAM_R7C12 = $d924 ; x-ref: $1457
COLOR_RAM_R8C0 = $d940 ; x-ref: $1083
COLOR_RAM_R9C11 = $d973 ; x-ref: $149D
COLOR_RAM_R9C12 = $d974 ; x-ref: $1473
COLOR_RAM_R9C16 = $d978 ; x-ref: $461A
COLOR_RAM_R9C23 = $d97f ; x-ref: $18C5
COLOR_RAM_R9C26 = $d982 ; x-ref: $18D7
COLOR_RAM_R9C27 = $d983 ; x-ref: $18DA
COLOR_RAM_R11C0 = $d9b8 ; x-ref: $1086
COLOR_RAM_R11C3 = $d9bb ; x-ref: $1E06
COLOR_RAM_R11C17 = $d9c9 ; x-ref: $14B2
COLOR_RAM_R11C19 = $d9cb ; x-ref: $1E39
COLOR_RAM_R11C20 = $d9cc ; x-ref: $1E3C
COLOR_RAM_R12C16 = $d9f0 ; x-ref: $1151
COLOR_RAM_R12C32 = $da00 ; x-ref: $1732, $1B82
COLOR_RAM_R14C0 = $da30 ; x-ref: $1089
COLOR_RAM_R16C11 = $da8b ; x-ref: $14CA
COLOR_RAM_R16C23 = $da97 ; x-ref: $1553
COLOR_RAM_R17C0 = $daa8 ; x-ref: $108E
COLOR_RAM_R17C24 = $dac0 ; x-ref: $1154
COLOR_RAM_R18C14 = $dade ; x-ref: $156C
COLOR_RAM_R18C32 = $daf0 ; x-ref: $1735
COLOR_RAM_R19C0 = $daf8 ; x-ref: $1091
COLOR_RAM_R19C8 = $db00 ; x-ref: $1B85
COLOR_RAM_R21C0 = $db48 ; x-ref: $1094
COLOR_RAM_R21C14 = $db56 ; x-ref: $536F
COLOR_RAM_R22C2 = $db72 ; x-ref: $4503
COLOR_RAM_R23C0 = $db98 ; x-ref: $1099
COLOR_RAM_R23C2 = $db9a ; x-ref: $4506
COLOR_RAM_R23C3 = $db9b ; x-ref: $44BD
COLOR_RAM_R24C2 = $dbc2 ; x-ref: $4509
f_DBFF = $dbff ; x-ref: $56E6
e_E097 = $e097 ; x-ref: $4A0F, $4A24, $4A8D
e_EA7E = $ea7e ; x-ref: $573E
KERNAL_RESET_VECTOR = $fce2 ; x-ref: $8000
sfx_voice_1_state = $7080 ; x-ref: $1279, $539D, $53B2, $53DA, $53F5
sfx_voice_1_freq_lo = $7081 ; x-ref: $127C, $53A2, $53C5, $53EA
sfx_voice_1_freq_mod = $7082 ; x-ref: $127F, $53B6, $53C9, $53CE, $53E2, $53E5
f_7400 = $7400 ; x-ref: $11AE, $1B9D, $1C71, $1C8D, $1CC2
f_7408 = $7408 ; x-ref: $1BBB, $1C5D, $1C74, $1CCB
f_7410 = $7410 ; x-ref: $1BD6, $1C49, $1C60, $1CD4
f_7418 = $7418 ; x-ref: $1BF1, $1C35, $1C4C, $1CDD
f_7420 = $7420 ; x-ref: $1C0C, $1C38, $1CE6
f_7430 = $7430 ; x-ref: $11A9, $1C92, $1C9D, $1D40, $1F0E, $4682
f_7438 = $7438 ; x-ref: $1CA3, $1D2C, $1D43, $1F2D, $4692
f_7440 = $7440 ; x-ref: $1CA9, $1D18, $1D2F, $1F4C, $46A2
f_7448 = $7448 ; x-ref: $1CAF, $1D04, $1D1B, $1F6B, $46B2
f_7450 = $7450 ; x-ref: $1CB5, $1D07, $1F86, $46BE
; ENUMS
; Enum: VicIIColors
VicIIColors = {
BLACK: $00,
WHITE: $01,
RED: $02,
CYAN: $03,
PURPLE: $04,
GREEN: $05,
BLUE: $06,
YELLOW: $07,
ORANGE: $08,
BROWN: $09,
LIGHT_RED: $0a,
DARK_GREY: $0b,
GREY: $0c,
LIGHT_GREEN: $0d,
LIGHT_BLUE: $0e,
LIGHT_GREY: $0f
}
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
; Initializes the VIC-II video chip settings for the game.
; Clears sprite coordinates, enables multi-color mode for character display,
; sets up global border and background colors, and configures sprite sizes,
; priorities, and multi-color settings. Also sets the character memory pointer.
;
; Inputs: None
; Outputs: None
; Side Effects: Modifies VIC-II registers ($D000-$D026) and Sprite 0 pointer ($07F8)
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
$1000a2 00init_vic_videoldx#$00; x-ref: $1803
$10028atxa
$10039d 00 d0b_1003sta$d000,x; Clear sprite coordinates ($D000-$D010) ; x-ref: $1009 Sprite 0 X Pos
$1006e8inx
$1007e0 11cpx#$11
$1009d0 f8bneb_1003
$100B8d 17 d0sta$d017; Sprites Expand 2x Vertical (Y)
$100E8d 1b d0sta$d01b; Sprite to Background Display Priority
$10118d 1d d0sta$d01d; Sprites Expand 2x Horizontal (X)
$1014a9 fflda#$ff
$10168d 15 d0sta$d015; Sprite display Enable
$10198d 1c d0sta$d01c; Sprites Multi-Color Mode Select
$101Ca9 00lda#$00
$101E8d 20 d0sta$d020; Border Color
$1021a9 0blda#$0b
$10238d 21 d0sta$d021; Background Color 0
$1026a9 00lda#$00
$10288d 22 d0sta$d022; Background Color 1, Multi-Color Register 0
$102Ba9 06lda#$06
$102D8d 23 d0sta$d023; Background Color 2, Multi-Color Register 1
$1030a9 00lda#$00
$10328d 25 d0sta$d025; Sprite Multi-Color Register 0
$1035a9 02lda#$02
$10378d 26 d0sta$d026; Sprite Multi-Color Register 1
$103Aad 16 d0lda$d016; VIC Control Register 2
$103D09 10ora#$10
$103F8d 16 d0sta$d016; VIC Control Register 2
$1042ad 18 d0lda$d018; VIC Memory Control Register
$104529 f0and#$f0
$104709 08ora#$08; Set character memory to $2000
$10498d 18 d0sta$d018; VIC Memory Control Register
$104Ca9 c0lda#$c0
$104E8d f8 07stasprite_ptr_0; Sprite 0 pointer points to $3000
$105160rts
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
; Initializes the screen display, background colors, and title/game sprites.
; This routine runs at startup to paint the initial screen layout to Screen RAM
; ($0400) and Color RAM ($D800). It establishes the sprite positions and does a
; fade-in effect by shifting bits into the sprite enable register ($D015) before
; switching to a second screen layout ($2800).
;
; Inputs: None
; Outputs: None
; Side Effects: Modifies Screen RAM ($0400), Color RAM ($D800), and all Sprite
; registers in ($D000-$D015). Loops through wait delays.
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
init_screen_and_sprites
$1052a2 00ldx#$00; x-ref: $1806
$1054bd 00 24b_1054ldaf_2400,x; Copy layout 1 ($2400) to Screen RAM ($0400) ; x-ref: $106D
$10579d 00 04staSCREEN_RAM,x
$105Abd 00 25ldaf_2500,x
$105D9d 00 05staSCREEN_RAM_R6C16,x
$1060bd 00 26ldaf_2600,x
$10639d 00 06staSCREEN_RAM_R12C32,x
$1066bd f0 26ldaf_26F0,x
$10699d f0 06staSCREEN_RAM_R18C32,x
$106Ce8inx
$106Dd0 e5bneb_1054
$106Fa2 00ldx#$00
$1071a9 04b_1071lda#VicIIColors.PURPLE; x-ref: $109F
$10739d 00 d8staCOLOR_RAM,x; Color Memory ($D800) Setup
$1076a9 0flda#VicIIColors.LIGHT_GREY
$10789d 50 d8staCOLOR_RAM_R2C0,x
$107B9d 78 d8staCOLOR_RAM_R3C0,x
$107Ea9 03lda#VicIIColors.CYAN
$10809d c8 d8staCOLOR_RAM_R5C0,x
$10839d 40 d9staCOLOR_RAM_R8C0,x
$10869d b8 d9staCOLOR_RAM_R11C0,x
$10899d 30 dastaCOLOR_RAM_R14C0,x
$108Ca9 01lda#VicIIColors.WHITE
$108E9d a8 dastaCOLOR_RAM_R17C0,x
$10919d f8 dastaCOLOR_RAM_R19C0,x
$10949d 48 dbstaCOLOR_RAM_R21C0,x
$1097a9 04lda#VicIIColors.PURPLE
$10999d 98 dbstaCOLOR_RAM_R23C0,x
$109Ce8inx
$109De0 50cpx#$50
$109Fd0 d0bneb_1071
$10A1a9 00lda#$00
$10A320 ca 11jsrenable_sprites_and_update_hud
$10A6a9 38lda#$38
$10A88d 00 d0sta$d000; Setup Sprites 0-7 X/Y Coordinates; Sprite 0 X Pos
$10AB8d 02 d0sta$d002; Sprite 1 X Pos
$10AE8d 04 d0sta$d004; Sprite 2 X Pos
$10B18d 06 d0sta$d006; Sprite 3 X Pos
$10B4a9 d0lda#$d0
$10B68d 08 d0sta$d008; Sprite 4 X Pos
$10B98d 0a d0sta$d00a; Sprite 5 X Pos
$10BC8d 0c d0sta$d00c; Sprite 6 X Pos
$10BF8d 0e d0sta$d00e; Sprite 7 X Pos
$10C2a9 5alda#$5a
$10C48d 01 d0sta$d001; Sprite 0 Y Pos
$10C78d 09 d0sta$d009; Sprite 4 Y Pos
$10CAa9 72lda#$72
$10CC8d 03 d0sta$d003; Sprite 1 Y Pos
$10CF8d 0b d0sta$d00b; Sprite 5 Y Pos
$10D2a9 8alda#$8a
$10D48d 05 d0sta$d005; Sprite 2 Y Pos
$10D78d 0d d0sta$d00d; Sprite 6 Y Pos
$10DAa9 a2lda#$a2
$10DC8d 07 d0sta$d007; Sprite 3 Y Pos
$10DF8d 0f d0sta$d00f; Sprite 7 Y Pos
$10E2a9 c2lda#$c2
$10E48d f8 07stasprite_ptr_0; Setup Sprites 0-7 Pointers
$10E7a9 c4lda#$c4
$10E98d f9 07stasprite_ptr_1
$10ECa9 c6lda#$c6
$10EE8d fa 07stasprite_ptr_2
$10F1a9 c8lda#$c8
$10F38d fb 07stasprite_ptr_3
$10F6a9 calda#$ca
$10F88d fc 07stasprite_ptr_4
$10FBa9 cclda#$cc
$10FD8d fd 07stasprite_ptr_5
$1100a9 celda#$ce
$11028d fe 07stasprite_ptr_6
$1105a9 d0lda#$d0
$110720 64 11jsrinit_sprite_colors
$110A20 d0 11j_110Ajsrdelay_with_fire_check; x-ref: $1117
$110Dad 15 d0lda$d015; Sprite display Enable
$11100aasla; Slide/Fade in Sprite Enable bits
$111118clc
$111269 01adc#$01
$11148d 15 d0sta$d015; Sprite display Enable
$11174c 0a 11jmpj_110A
$111Aa2 00j_111Aldx#$00; x-ref: $11EB
$111Ca9 20lda#$20
$111E9d d0 04b_111EstaSCREEN_RAM_R5C8,x; x-ref: $112B
$11219d 00 05staSCREEN_RAM_R6C16,x
$11249d 00 06staSCREEN_RAM_R12C32,x
$11279d a0 06staSCREEN_RAM_R16C32,x
$112Ae8inx
$112Bd0 f1bneb_111E
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
; Initializes the title screen by copying layout data to Screen RAM, setting
; Color RAM, disabling sprites, and jumping to the title screen menu.
;
; Inputs: None
; Outputs: None
; Side Effects: Modifies Screen RAM ($0400-$07E7), Color RAM ($D8F0-$DBBF), and
; $D015 (Sprite display enable).
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
$112Da2 00init_title_screenldx#$00; Initialize copy index
$112Fbd 00 28b_112Fldainstructions_screen_1,x; Copy layout data to Screen RAM ; x-ref: $1158
$11329d 00 04staSCREEN_RAM,x
$1135bd 00 29ldainstructions_screen_2,x
$11389d 00 05staSCREEN_RAM_R6C16,x
$113Bbd 00 2aldainstructions_screen_3,x
$113E9d 00 06staSCREEN_RAM_R12C32,x
$1141bd f0 2aldainstructions_screen_4,x
$11449d f0 06staSCREEN_RAM_R18C32,x
$1147a9 00lda#$00; Disable all sprites
$11498d 15 d0sta$d015; Sprite display Enable
$114Ca9 07lda#VicIIColors.YELLOW; Set color to yellow ($07)
$114E9d f0 d8staCOLOR_RAM_R6C0,x; Apply yellow to specific Color RAM areas
$11519d f0 d9staCOLOR_RAM_R12C16,x
$11549d c0 dastaCOLOR_RAM_R17C24,x
$1157e8inx
$1158d0 d5bneb_112F
$115Aa9 10lda#$10; Set A to $10 for menu init
$115C4c cb 3fjmptitle_screen_menu; Jump to title screen menu
; dead code
$115F.byte$d0, $f9, $4c, $8e, $11
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
; Initializes colors for all 8 hardware sprites and sets sprite pointer 7.
;
; Inputs: A = Value for sprite pointer 7
; Outputs: None
; Side Effects: Modifies VIC-II sprite color registers ($D027-$D02E) and sprite pointer 7.
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
$11648d ff 07init_sprite_colorsstasprite_ptr_7; Set sprite pointer 7 ; x-ref: $1107
$1167a9 01lda#$01; Set Sprite 0 and 1 colors to white ($01)
$11698d 27 d0sta$d027; Sprite 0 Color
$116C8d 28 d0sta$d028; Sprite 1 Color
$116Fa9 07lda#$07; Set Sprite 3 color to yellow ($07)
$11718d 2a d0sta$d02a; Sprite 3 Color
$1174a9 0elda#$0e; Set Sprite 4 and 5 colors to light blue ($0E)
$11768d 2b d0sta$d02b; Sprite 4 Color
$1179a9 0elda#$0e
$117B8d 2c d0sta$d02c; Sprite 5 Color
$117Ea9 04lda#$04; Set Sprite 2 color to purple ($04)
$11808d 29 d0sta$d029; Sprite 2 Color
$1183a9 05lda#$05; Set Sprite 6 color to green ($05)
$11858d 2d d0sta$d02d; Sprite 6 Color
$1188a9 0dlda#$0d; Set Sprite 7 color to light green ($0D)
$118A8d 2e d0sta$d02e; Sprite 7 Color
$118D60rts
$118E20 00 12j_118Ejsrinit_game_vars; x-ref: $3FEA, $3FF7
$119120 0c 17jsrinit_level_screen
$119460rts
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
; Initializes the game state, memory buffers, and SID audio filters.
; This routine sets up several 256-byte pages ($0800-$0DFF), clears object/sprite
; buffers, and resets various variables at the start of $0800. It also initializes
; the SID chip's filter and volume settings initially calling `$1195` then jumping
; to `$1200` to complete the rest of the work.
;
; Inputs: None
; Outputs: None
; Side Effects: Modifies memory regions $0800-$0DFF, $0F50-$0F56, $7400-$7457,
; and SID registers $D415-$D418.
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
$1195a2 00init_game_stateldx#$00; x-ref: $1800
$11978atxa
$11989d 50 0fb_1198stahi_score_7digits,x; x-ref: $119E
$119Be8inx
$119Ce0 07cpx#$07
$119Ed0 f8bneb_1198
$11A0a9 4flda#$4f
$11A28d 18 d4sta$d418; SID Mode/Volume; Select Filter Mode and Volume
$11A5a2 00ldx#$00
$11A7a9 20b_11A7lda#$20; x-ref: $11B4
$11A99d 30 74staf_7430,x
$11ACa9 00lda#$00
$11AE9d 00 74staf_7400,x
$11B1e8inx
$11B2e0 28cpx#$28
$11B4d0 f1bneb_11A7
$11B6a9 06lda#$06
$11B88d 17 d4sta$d417; SID Resonance/Voice Input; Filter Resonance Control / Voice Input Control
$11BB4c 00 12jmpinit_game_vars
$11BE.fill11, $00
$11C9.byte$8d
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
; Updates the sprite display enable mask and tail-calls the HUD update routine.
;
; Inputs: A = Sprite enable bitmask
; Outputs: None
; Side Effects: Modifies $D015 (Sprite display enable) and updates HUD display.
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
enable_sprites_and_update_hud
$11CA8d 15 d0sta$d015; Set sprite display enable mask ; x-ref: $10A3 Sprite display Enable
$11CD4c b0 16jmpupdate_hud_display; Tail call to update HUD
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
; Performs a delay loop while polling the fire button. If the fire button is
; pressed during the delay, it waits for release, unwinds the stack, and aborts.
;
; Inputs: None
; Outputs: None
; Side Effects: May discard stack return address and jump to j111A on fire press.
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
delay_with_fire_check
$11D0a2 00ldx#$00; Initialize X delay counter ; x-ref: $110A
$11D2a0 00b_11D2ldy#$00; Initialize Y delay counter ; x-ref: $11DF
$11D4a9 10b_11D4lda#$10; Bit mask for fire button ; x-ref: $11DC
$11D62c f5 00bit@w zp_joy_state; Check joystick state
$11D9f0 07beqb_11E2; If pressed (0), branch to wait-for-release loop
$11DB88dey
$11DCd0 f6bneb_11D4
$11DEcadex
$11DFd0 f1bneb_11D2
$11E160rts
$11E2a9 10b_11E2lda#$10; Wait loop: mask for fire button ; x-ref: $11D9, $11E7
$11E42c f5 00bit@w zp_joy_state
$11E7f0 f9beqb_11E2; Loop until fire button is released (non-zero)
$11E968pla; Discard return address (low byte)
$11EA68pla; Discard return address (high byte)
$11EB4c 1a 11jmpj_111A; Abort current call chain
$11EE.byte$00, $00
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
; Convenience routine to initialize the HUD and trigger a screen scroll down.
;
; Inputs: None
; Outputs: None
; Side Effects: Calls init_hud and scroll_screen_down routines.
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
init_hud_and_scroll_screen_down
$11F020 b0 44jsrinit_hud; Initialize Heads Up Display ; x-ref: $1300
$11F320 00 15jsrscroll_screen_down; Scroll the screen down one row
$11F660rts
$11F7.fill9, $00
level_nr_self_modifiying =*+$01 ; x-ref: $3FD1, $5311, $5314, $531D
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
; Initializes game variables and duplicates memory pages.
; This routine resets various state variables in the $0800-$09FF range, zeroes
; out specific arrays, and then creates two copies of the $0800-$09FF memory pages
; at $0A00-$0BFF and $0C00-$0DFF. It finally resets the SID filter cutoff frequency.
;
; Inputs: None
; Outputs: None
; Side Effects: Modifies memory $0800-$0DFF, $7080-$7082, and SID $D415-$D416.
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
$1200a9 00init_game_varslda#$00; x-ref: $118E, $11BB
$12028d 00 08stalevel_nr
$1205a9 00lda#$00
$12078d 01 08stalevel_block_idx
$120Aa9 18lda#24
$120C8d 02 08stalevel_tile_y_offset
$120Fa9 00lda#$00
$12118d 03 08staseason_nr
$1214a9 80lda#$80
$12168d 04 08staplayer_speed
$1219a9 00lda#$00
$121Baatax; Clear $0820-$084E
$121C9d 20 08b_121Cstacrashed_cars_tens,x; x-ref: $1222
$121Fe8inx
$1220e0 2fcpx#$2f
$1222d0 f8bneb_121C
$1224a9 00lda#$00
$12268d 21 08stacrashed_cars_ones
$1229a9 03lda#$03
$122B8d 23 08stalives_ones
$122Ea9 00lda#$00
$12308d 05 08staplayer_is_jumping
$1233a9 50lda#$50
$12358d 04 08staplayer_speed
$1238a9 00lda#$00
$123A8d e0 08stascore_digits
$123D8d e2 08staspeed_hundreds_digit
$1240a9 08lda#$08
$12428d e1 08staspeed_tens_digit
$1245a9 00lda#$00
$12478d 07 08staplayer_x_offset
$124A8d 08 08staplayer_y_offset
$124Da9 00lda#$00
$124F8d 5e 08stapickup_mode_active
$12528d 86 09stascroll_row_snapshot
$12558d 87 09stadist_substep
$1258a2 00ldx#$00
$125Abd 00 08b_125Aldalevel_nr,x; Copy $0800-$08FF to $0A00 and $0C00 ; x-ref: $126D
$125D9d 00 0astaf_0A00,x
$12609d 00 0cstaf_0C00,x
$1263bd 00 09ldaf_0900,x; Copy $0900-$09FF to $0B00 and $0D00
$12669d 00 0bstaf_0B00,x
$12699d 00 0dstaf_0D00,x
$126Ce8inx
$126Dd0 ebbneb_125A
$126Fa9 00lda#$00
$12718d 15 d4sta$d415; Filter Cutoff Frequency: Low-Nybble
$1274a9 00lda#$00
$12768d 16 d4sta$d416; Filter Cutoff Frequency: High-Byte
$12798d 80 70stasfx_voice_1_state
$127C8d 81 70stasfx_voice_1_freq_lo
$127F8d 82 70stasfx_voice_1_freq_mod
$128260rts
$1283.fill13, $00
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
; MAIN ENTRY POINT
; This code was in the tape loader.
; Moved to the "main" binary to have a single-load game
$129078startsei
$1291a9 53lda#>irq_handler_music
$12938d 15 03staIRQ_VEC_HI; IRQ
$1296a9 98lda#<irq_handler_music
$12988d 14 03staIRQ_VEC_LO; IRQ
$129B58cli
$129C4c 00 18jmpmain
$129F.fill33, $00
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
; Silences SID Voice 1.
; However, if the player is jumping, it pops 4 bytes from the stack to bypass
; both this routine and its caller (reset_voice1_state) and returns directly
; to the caller of reset_voice1_state (e.g., play_crash_sfx).
; This prevents crash sounds from playing while jumping.
;
; Inputs: player_is_jumping
; Outputs: None
; Side Effects: Silences Voice 1 or manipulates stack to bail early.
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
silence_voice1_or_bail_if_jumping
$12C0ad 05 08ldaplayer_is_jumping; x-ref: $3E73
$12C3f0 05beqb_12CA
$12C568pla
$12C668pla
$12C768pla
$12C868pla
$12C960rts
$12CAa9 00b_12CAlda#$00; x-ref: $12C3
$12CC8d 04 d4sta$d404; Voice 1: Control Register
$12CF60rts
$12D0.fill32, $00
; Cartridge cold-start entry point (referenced by vector at $8002)
cartridge_reset_entry
$12F058cli; x-ref: $8002
$12F1a2 fbldx#$fb
$12F39atxs
$12F44c 03 18jmpgame_init_and_loop
$12F7.fill9, $00
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
; Scrolls the playfield down and fetches the next row of map tile data.
; First, it shifts Screen RAM down by one row to create a scrolling effect.
; Then, it computes a pointer to the level map array ($4000) based on the current
; scroll position to grab a 1024-byte map tile ID. Because tile data is located
; at $8010 and stretches underneath the BASIC ROM ($A000-$BFFF), the caller must
; bank out BASIC first. It finally copies 40 bytes of the tile row into Screen RAM
; at $0428 (row 1, leaving the UI row intact) and updates Color RAM.
;
; Inputs: $0800 (level nr), $0801 (Map Block Column), $0802 (Tile Y offset)
; Outputs: None
; Side Effects: Modifies Screen RAM ($0428+), Color RAM, and pointers at $49/$4A.
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
scroll_and_draw_map_row
$130020 f0 11jsrinit_hud_and_scroll_screen_down; Scroll screen downward ; x-ref: $180F
$1303ae 00 08ldxlevel_nr
$1306ac 01 08ldylevel_block_idx
$1309a9 00lda#<level_tile_tbl
$130B85 49stazp_p_tmp_lo
$130Da9 40lda#>level_tile_tbl
$130F85 4astazp_p_tmp_hi
$1311e0 00j_1311cpx#$00; x-ref: $1323
$1313f0 11beqb_1326
$1315a5 49ldazp_p_tmp_lo
$131718clc
$131869 20adc#$20
$131A85 49stazp_p_tmp_lo
$131Ca5 4aldazp_p_tmp_hi
$131E69 00adc#$00
$132085 4astazp_p_tmp_hi
$1322cadex
$13234c 11 13jmpj_1311
$1326b1 49b_1326lda(zp_p_tmp_lo),y; x-ref: $1313
$1328aatax
$1329a9 10lda#<level_tile_definition_tbl
$132B85 49stazp_p_tmp_lo
$132Da9 80lda#>level_tile_definition_tbl
$132F85 4astazp_p_tmp_hi
$1331caj_1331dex; x-ref: $133D
$1332e0 00cpx#$00
$1334f0 0abeqb_1340
$1336a5 4aldazp_p_tmp_hi
$133818clc
$133969 04adc#$04
$133B85 4astazp_p_tmp_hi
$133D4c 31 13jmpj_1331
$1340ae 02 08b_1340ldxlevel_tile_y_offset; x-ref: $1334
$1343e0 00j_1343cpx#$00; x-ref: $1355
$1345f0 11beqb_1358
$1347a5 49ldazp_p_tmp_lo
$134918clc
$134A69 28adc#$28
$134C85 49stazp_p_tmp_lo
$134Ea5 4aldazp_p_tmp_hi
$135069 00adc#$00
$135285 4astazp_p_tmp_hi
$1354cadex
$13554c 43 13jmpj_1343
$1358a0 00b_1358ldy#$00; x-ref: $1345
$135Ab1 49b_135Alda(zp_p_tmp_lo),y; x-ref: $136B
$135C99 28 04staSCREEN_RAM_R1C0,y
$135Fae 03 08ldxseason_nr
$1362bd 7c 16ldatbl_text_color_seasons,x; One byte per season (0=Summer, 1=Autumn, 2=Winter, 3=Spring)
$136599 28 d8staCOLOR_RAM_R1C0,y
$1368c8iny
$1369c0 28cpy#$28
$136Bd0 edbneb_135A
$136Dce 02 08declevel_tile_y_offset
$137030 01bmib_1373
$137260rts
$1373a9 18b_1373lda#24; x-ref: $1370
$13758d 02 08stalevel_tile_y_offset
$1378ee 01 08inclevel_block_idx
$137Bad 01 08ldalevel_block_idx
$137Ec9 20cmp#$20
$1380f0 01beqb_1383
$138260rts
$1383eab_1383nop; x-ref: $1380
$1384eanop
$1385eanop
$1386a2 00ldx#$00
$138820 00 15b_1388jsrscroll_screen_down; x-ref: $13B2
$138B8atxa
$138C48pha
$138Da9 10lda#<level_tile_definition_tbl
$138F85 49stazp_p_tmp_lo
$1391a9 80lda#>level_tile_definition_tbl
$139385 4astazp_p_tmp_hi
$1395a0 00ldy#$00
$1397b1 49b_1397lda(zp_p_tmp_lo),y; x-ref: $13A8
$139999 28 04staSCREEN_RAM_R1C0,y
$139Cae 03 08ldxseason_nr
$139Fbd 7c 16ldatbl_text_color_seasons,x; One byte per season (0=Summer, 1=Autumn, 2=Winter, 3=Spring)
$13A299 28 d8staCOLOR_RAM_R1C0,y
$13A5c8iny
$13A6c0 28cpy#$28
$13A8d0 edbneb_1397
$13AA20 56 47jsrtick_gameplay_systems
$13AD68pla
$13AEaatax
$13AFe8inx
$13B0e0 19cpx#$19
$13B2d0 d4bneb_1388
$13B420 f0 45jsradd_car_x_subpixels
$13B7bd 74 16ldatbl_level_complete_sprite1_ptr,x
$13BA8d f9 07stasprite_ptr_1
$13BDbd 70 16ldatbl_level_complete_sprite2_ptr,x
$13C08d fa 07stasprite_ptr_2
$13C3bd 78 16ldatbl_level_complete_sprite1_color,x
$13C68d 28 d0sta$d028; Sprite 1 Color
$13C920 e7 15jsrreset_hero_sprite_and_color
$13CCa9 90lda#$90
$13CE8d 03 d0sta$d003; Sprite 1 Y Pos
$13D18d 05 d0sta$d005; Sprite 2 Y Pos
$13D4a9 60lda#$60
$13D68d 02 d0sta$d002; Sprite 1 X Pos
$13D9a9 75lda#$75
$13DB8d 04 d0sta$d004; Sprite 2 X Pos
$13DEad 00 d0j_13DElda$d000; x-ref: $13ED Sprite 0 X Pos
$13E1c9 8acmp#$8a
$13E3f0 11beqb_13F6
$13E590 09bccb_13F0
$13E7ce 00 d0dec$d000; Sprite 0 X Pos
$13EA20 e0 14j_13EAjsrdelay_short; x-ref: $13F3
$13ED4c de 13jmpj_13DE
$13F0ee 00 d0b_13F0inc$d000; x-ref: $13E5 Sprite 0 X Pos
$13F34c ea 13jmpj_13EA
$13F6ad 01 d0b_13F6lda$d001; x-ref: $13E3, $1405 Sprite 0 Y Pos
$13F9c9 90cmp#$90
$13FBf0 11beqb_140E
$13FD90 09bccb_1408
$13FFce 01 d0dec$d001; Sprite 0 Y Pos
$140220 e0 14j_1402jsrdelay_short; x-ref: $140B
$14054c f6 13jmpb_13F6
$1408ee 01 d0b_1408inc$d001; x-ref: $13FD Sprite 0 Y Pos
$140B4c 02 14jmpj_1402
$140Ea2 00b_140Eldx#$00; x-ref: $13FB
$1410bd 00 16b_1410ldatxt_congratulations_pt1,x; x-ref: $141E
$14139d 83 04staSCREEN_RAM_R3C11,x
$1416a9 07lda#VicIIColors.YELLOW
$14189d 83 d8staCOLOR_RAM_R3C11,x
$141Be8inx
$141Ce0 12cpx#$12
$141Ed0 f0bneb_1410
$142020 f0 14jsrdelay_long
$1423a2 00ldx#$00
$1425bd 12 16b_1425ldatxt_you_crash_cars,x; x-ref: $1433
$14289d d2 04staSCREEN_RAM_R5C10,x
$142Ba9 07lda#VicIIColors.YELLOW
$142D9d d2 d8staCOLOR_RAM_R5C10,x
$1430e8inx
$1431e0 14cpx#$14
$1433d0 f0bneb_1425
$1435ad 20 08ldacrashed_cars_tens
$143818clc
$143969 30adc#$30
$143B8d df 04staSCREEN_RAM_R5C23
$143Ead 21 08ldacrashed_cars_ones
$144118clc
$144269 30adc#$30
$14448d e0 04staSCREEN_RAM_R5C24
$144720 f0 14jsrdelay_long
$144A20 f0 14jsrdelay_long
$144Da2 00ldx#$00
$144Fbd 26 16b_144Fldatxt_bonus_pts_are,x; x-ref: $145D
$14529d 24 05staSCREEN_RAM_R7C12,x
$1455a9 03lda#VicIIColors.CYAN
$14579d 24 d9staCOLOR_RAM_R7C12,x
$145Ae8inx
$145Be0 10cpx#$10
$145Dd0 f0bneb_144F
$145Fad 20 08ldacrashed_cars_tens
$1462d0 05bneb_1469
$1464ad 21 08ldacrashed_cars_ones
$1467f0 2abeqb_1493
$1469a2 00b_1469ldx#$00; x-ref: $1462
$146Bbd 36 16b_146Bldatxt_multiplier_500,x; x-ref: $1479
$146E9d 74 05staSCREEN_RAM_R9C12,x
$1471a9 04lda#VicIIColors.PURPLE
$14739d 74 d9staCOLOR_RAM_R9C12,x
$1476e8inx
$1477e0 0acpx#$0a
$1479d0 f0bneb_146B
$147Bad 20 08ldacrashed_cars_tens
$147E18clc
$147F69 30adc#$30
$14818d 74 05staSCREEN_RAM_R9C12
$1484ad 21 08ldacrashed_cars_ones
$148718clc
$148869 30adc#$30
$148A8d 75 05staSCREEN_RAM_R9C13
$148D4c 50 18jmpcalc_and_display_crashed_cars_bonus
; dead code
$1490.byte$4c, $ba, $14
$1493a2 00b_1493ldx#$00; x-ref: $1467
$1495bd 40 16b_1495ldatxt_extra_bonus_points,x; x-ref: $14A3
$14989d 73 05staSCREEN_RAM_R9C11,x
$149Ba9 03lda#VicIIColors.CYAN
$149D9d 73 d9staCOLOR_RAM_R9C11,x
$14A0e8inx
$14A1e0 12cpx#$12
$14A3d0 f0bneb_1495
$14A520 f0 14jsrdelay_long
$14A8a2 00ldx#$00
$14AAbd 52 16b_14AAldatxt_50000,x; x-ref: $14B8
$14AD9d c9 05staSCREEN_RAM_R11C17,x
$14B0a9 04lda#VicIIColors.PURPLE
$14B29d c9 d9staCOLOR_RAM_R11C17,x
$14B5e8inx
$14B6e0 05cpx#$05
$14B8d0 f0bneb_14AA
$14BA20 a7 15jsrincrement_score_by_50000
$14BD20 f0 14j_14BDjsrdelay_long; x-ref: $1943
$14C0a2 00ldx#$00
$14C2bd 57 16b_14C2ldatxt_next_way_is,x; x-ref: $14D0
$14C59d 8b 06staSCREEN_RAM_R16C11,x
$14C8a9 07lda#VicIIColors.YELLOW
$14CA9d 8b dastaCOLOR_RAM_R16C11,x
$14CDe8inx
$14CEe0 0bcpx#$0b
$14D0d0 f0bneb_14C2
$14D24c 42 15jmpshow_next_season_screen
$14D5.fill11, $00
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
; Short busy-wait delay (~13 ms). Runs a nested loop with X=10 outer iterations
; and Y=256 inner iterations. Shares the loop body with delay_long.
;
; Inputs: None
; Outputs: X=0, Y=0
; Side Effects: None (burns CPU time)
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
$14E0a2 0adelay_shortldx#$0a; 10 outer iterations ; x-ref: $13EA, $1402
$14E2a0 00delay_outer_loopldy#$00; 256 inner iterations (Y wraps $00->$FF) ; x-ref: $14E8, $14F8
$14E488delay_inner_loopdey; x-ref: $14E5, $14F5
$14E5d0 fdbnedelay_inner_loop
$14E7cadex
$14E8d0 f8bnedelay_outer_loop
$14EA60rts
$14EB.byte$00, $00, $00, $00, $00
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
; Long busy-wait delay (~328 ms). X=$00 wraps to 256 outer iterations, each
; with 256 inner Y iterations. Falls through into delay_short's loop body.
; Used for dramatic pauses during level transitions and score displays.
;
; Inputs: None
; Outputs: X=0, Y=0
; Side Effects: None (burns CPU time)
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
$14F0a2 00delay_longldx#$00; X=$00 wraps to 256 outer iterations ; x-ref: $1420, $1447, $144A, $14A5, $14BD, $155C, $155F, $159E
$14F2a0 00ldy#$00
$14F488dey
$14F5d0 edbnedelay_inner_loop
$14F7cadex
$14F8d0 e8bnedelay_outer_loop
$14FA60rts
$14FB.byte$00, $00, $00, $00, $00
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
; Shifts a large portion of Screen RAM down by one row (40 bytes) to create the
; scrolling effect. It initializes a zero-page pointer ($49/$4A) to the end of
; the scrolling region ($0747) and copies memory to pointer + 40 ($28).
; It iterates backwards until it reaches the HUD boundary at $0427, leaving row 0
; (the HUD) intact.
;
; Inputs: None
; Outputs: None
; Side Effects: Modifies Screen RAM ($0428-$076F) and zero-page pointers $49/$4A.
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
$150020 00 49scroll_screen_downjsrshift_colour_row_pipeline; shift colour pipeline; A=$07 on return ; x-ref: $11F3, $1388
$150385 4astazp_p_tmp_hi
$1505a9 47lda#<SCREEN_RAM_R20C39
$150785 49stazp_p_tmp_lo; Set pointer to $0747
$1509a0 00b_1509ldy#$00; x-ref: $1522, $1528
$150Bb1 49lda(zp_p_tmp_lo),y
$150Da0 28ldy#$28
$150F91 49sta(zp_p_tmp_lo),y; Copy byte down one row (40 bytes offset)
$1511a5 49ldazp_p_tmp_lo
$151338sec
$1514e9 01sbc#$01
$151685 49stazp_p_tmp_lo; Decrement pointer ($49)
$1518a5 4aldazp_p_tmp_hi
$151Ae9 00sbc#$00
$151C85 4astazp_p_tmp_hi; Decrement pointer MSB ($4A) if needed
$151Ea5 49ldazp_p_tmp_lo
$1520c9 27cmp#$27
$1522d0 e5bneb_1509
$1524a5 4aldazp_p_tmp_hi
$1526c9 04cmp#$04
$1528d0 dfbneb_1509; Loop until pointer reaches boundary ($0427)
$152A58cli
$152B60rts
; dead code
$152C.byte$4c, $58, $60, $4a, $e9, $00, $85, $4a
$1534.byte$a5, $49, $c9, $27, $d0, $cf, $a5, $4a
$153C.byte$c9, $04, $d0, $c9, $58, $60
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
; Level transition screen: displays the upcoming season name and "GOOD LUCK!"
; message. If all 32 levels (ways) are completed, awards a BONUS 10000 score.
; Otherwise, advances season_nr (mod 4), resets level state, plays a countdown
; delay animation, and re-enters the main game flow for the next level.
;
; Inputs: season_nr ($0803), a0800 ($0800) level counter
; Outputs: season_nr (incremented mod 4), a0800 (incremented), level state reset
; Side Effects: Writes to Screen/Color RAM, busy-wait delays, may award bonus
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
show_next_season_screen
$1542ad 03 08ldaseason_nr; Load season index (0-3) ; x-ref: $14D2
$15450aasla; season_nr * 8 = offset into txt_seasons
$15460aasla
$15470aasla
$1548aatax
$1549a0 00ldy#$00
$154Bbd 80 16b_154Bldatxt_seasons,x; Copy 8-char season name to screen ; x-ref: $155A
$154E99 97 06staSCREEN_RAM_R16C23,y; Screen RAM row 16, col 23
$1551a9 07lda#VicIIColors.YELLOW; Yellow text
$155399 97 dastaCOLOR_RAM_R16C23,y
$1556e8inx
$1557c8iny
$1558c0 08cpy#$08
$155Ad0 efbneb_154B
$155C20 f0 14jsrdelay_long
$155F20 f0 14jsrdelay_long
$1562a2 00ldx#$00
$1564bd 62 16b_1564ldatxt_good_luck,x; x-ref: $1572
$15679d de 06staSCREEN_RAM_R18C14,x
$156Aa9 07lda#VicIIColors.YELLOW
$156C9d de dastaCOLOR_RAM_R18C14,x
$156Fe8inx
$1570e0 0ccpx#$0c
$1572d0 f0bneb_1564
$1574ee 00 08inclevel_nr; Increment level counter
$1577ad 00 08ldalevel_nr
$157Ac9 20cmp#32; All 32 levels done?
$157Cd0 03bneb_1581
$157E4c 60 53jmpaward_bonus_score; Yes: award BONUS 10000
$1581a9 00b_1581lda#$00; x-ref: $157C, $5395
$15838d 01 08stalevel_block_idx
$1586a9 18lda#24
$15888d 02 08stalevel_tile_y_offset
$158Bee 03 08incseason_nr; Advance to next season
$158Ead 03 08ldaseason_nr
$1591c9 04cmp#$04; Wrap season 4 -> 0
$1593d0 05bneb_159A
$1595a9 00lda#$00
$15978d 03 08staseason_nr
$159Aa2 15b_159Aldx#$15; Countdown delay: 21 iterations ; x-ref: $1593
$159C8ab_159Ctxa; x-ref: $15E2
$159D48pha
$159E20 f0 14jsrdelay_long
$15A168pla
$15A2aatax
$15A3cadex
$15A44c e2 15jmpj_15E2
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
; Increments the player's score by 50000 points.
; This routine calls an internal loop 5 times (controlled by Y register). In each
; loop, it increments the ten-thousand digit (index 2 of the $0825 score array) by 1.
; Overflows are handled seamlessly via a cascading BCD-like carry lookup. After
; adding 5 to the ten-thousand position, it refreshes the HUD to display the new score.
;
; Inputs: None (relies on $0825 array)
; Outputs: None
; Side Effects: Modifies the Score array and calls update_hud_display.
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
increment_score_by_50000
$15A7a0 00ldy#$00; x-ref: $14BA, $5377, $537A
$15A9a2 02b_15A9ldx#$02; x-ref: $15C4
$15ABbd 25 08j_15ABldascore_7digits,x; x-ref: $15BB
$15AE18clc
$15AF69 01adc#$01
$15B1c9 0acmp#$0a
$15B3d0 09bneb_15BE
$15B5a9 00lda#$00
$15B79d 25 08stascore_7digits,x
$15BAcadex
$15BB4c ab 15jmpj_15AB
$15BE9d 25 08b_15BEstascore_7digits,x; x-ref: $15B3
$15C1c8iny
$15C2c0 05cpy#$05
$15C4d0 e3bneb_15A9
$15C64c b0 16jmpupdate_hud_display
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
; Increments the player's 7-digit score uniformly.
; Because the score is stored as an array of 7 individual digits (0-9) at $0825,
; this routine performs a manual base-10 addition. It starts at the least
; significant digit (index 6, $082B), adds 1, and carries over any overflow (10)
; to the next significant digit.
;
; Inputs: Score array at $0825-$082B
; Outputs: Modified Score array
; Side Effects: None
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
$15C9a2 06increment_scoreldx#$06; Start at least significant digit (index 6) ; x-ref: $181B, $4759
$15CBbd 25 08j_15CBldascore_7digits,x; x-ref: $15DB
$15CE18clc
$15CF69 01adc#$01; Add 1 to the current digit
$15D1c9 0acmp#$0a; Check for base-10 overflow
$15D3d0 09bneb_15DE
$15D5a9 00lda#$00
$15D79d 25 08stascore_7digits,x
$15DAcadex; Move to next most significant digit (carry)
$15DB4c cb 15jmpj_15CB
$15DE9d 25 08b_15DEstascore_7digits,x; x-ref: $15D3
$15E160rts
$15E2d0 b8j_15E2bneb_159C; Loop until X=0, then fall through to j16A1 ; x-ref: $15A4
$15E44c a1 16jmpreset_crashed_cars_and_switch_player
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
; Resets the player (hero) sprite's frame to 0 ($C0), sets Sprite 2's color,
; and clears the sprite expansion flags for both X and Y.
;
; Inputs: A = Color for Sprite 2
; Outputs: None
; Side Effects: Modifies Sprite 2 Color ($D029), Player sprite pointer, and Sprite Expand flags ($D017, $D01D)
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
reset_hero_sprite_and_color
$15E78d 29 d0sta$d029; Set Sprite 2 Color ; x-ref: $13C9 Sprite 2 Color
$15EAa9 c0lda#$c0; Hero sprite frame #0
$15EC8d f8 07stasprite_ptr_0; Set hero sprite pointer
$15EFa9 00lda#$00; Clear expand flags
$15F18d 17 d0sta$d017; Sprites Expand 2x Vertical (Y)
$15F48d 1d d0sta$d01d; Sprites Expand 2x Horizontal (X)
$15F760rts
$15F8.byte$20, $08, $8d, $21, $08, $60, $00, $00
.encode
.enc"screen"
txt_congratulations_pt1
$1600.text"CONGRATULATIONS !!"; x-ref: $1410
$1612txt_you_crash_cars.text" YOU CRASH CARS"; x-ref: $1425
$1626txt_bonus_pts_are.text"BONUS POINTS ARE"; x-ref: $144F
$1636txt_multiplier_500.text" X 500 ="; x-ref: $146B
txt_extra_bonus_points
$1640.text"EXTRA BONUS POINTS"; x-ref: $1495
$1652txt_50000.text"50000"; x-ref: $14AA
$1657txt_next_way_is.text"NEXT WAY IS"; x-ref: $14C2
$1662txt_good_luck.text"GOOD LUCK!.."; x-ref: $1564
.endencode
$166E.byte$00, $00
tbl_level_complete_sprite2_ptr
$1670.byte$d5, $d6, $d8, $d7; x-ref: $13BD
tbl_level_complete_sprite1_ptr
$1674.byte$d9, $dc, $da, $db; x-ref: $13B7
tbl_level_complete_sprite1_color
$1678.byte$0d, $01, $0a, $01; x-ref: $13C3
tbl_text_color_seasons
$167C.byteVicIIColors.LIGHT_GREEN; One byte per season (0=Summer, 1=Autumn, 2=Winter, 3=Spring) ; x-ref: $1362, $139F, $1729, $506F
$167D.byteVicIIColors.GREY; grey
$167E.byteVicIIColors.LIGHT_GREY; light grey
$167F.byteVicIIColors.BROWN; brown
.encode
.enc"screen"
$1680txt_seasons.text"SUMMER AUTUMN WINTER SPRING "; x-ref: $154B
.endencode
$16A0.byte$00
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
; Resets the crashed cars counter to zero, then jumps to the active player
; state switch logic. Typically called at the end of a season or game over.
;
; Inputs: None
; Outputs: crashed_cars_tens, crashed_cars_ones cleared
; Side Effects: Jumps to switch_active_player_state
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
reset_crashed_cars_and_switch_player
$16A1a9 00lda#$00; Zero crashed_cars count; jump to 2-player state switch (end of season) ; x-ref: $15E4
$16A38d 20 08stacrashed_cars_tens
$16A68d 21 08stacrashed_cars_ones
$16A94c be 50jmpswitch_active_player_state
$16AC.byte$00, $00, $00, $00
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
; Updates the HUD text on the top row of the screen ($0400).
; Converts numeric gameplay variables such as the current score, high score, and
; other state values into screencodes (by adding $30) and writes them directly
; to Screen RAM.
;
; Inputs: Numeric values at $0821, $0822, $0823, $0825-$082B (Score), and $0F50-$0F56 (High Score)
; Outputs: None
; Side Effects: Modifies Screen RAM ($0403-$0427) to update visible UI numbers.
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
$16B020 40 49update_hud_displayjsradvance_distance_counter; x-ref: $11CD, $15C6, $1818, $1940, $1D4E, $4745, $4756, $47D6
$16B318clc
$16B469 30adc#$30; A = crashed_cars_tens digit (returned by advance_distance_counter)
$16B68d 20 04staSCREEN_RAM_R0C32
$16B9ad 21 08ldacrashed_cars_ones; hud_crashed_ones: screen col 33 ($0421)
$16BC18clc
$16BD69 30adc#$30
$16BF8d 21 04staSCREEN_RAM_R0C33
$16C2ad 22 08ldalives_tens; hud_lives_tens: screen col 38 ($0426)
$16C518clc; hud_lives_ones: screen col 39 ($0427)
$16C669 30adc#$30
$16C88d 26 04staSCREEN_RAM_R0C38
$16CBad 23 08ldalives_ones
$16CE18clc
$16CF69 30adc#$30
$16D18d 27 04staSCREEN_RAM_R0C39
$16D420 a7 1fjsrwrite_level_nr_to_hud; write level number digits to hud_level_tens/ones ($0419/$041A)
$16D74c f2 16jmphud_write_score_and_hiscore
; dead code
$16DA.byte$09, $18, $69, $31, $8d, $1a, $04, $4c
$16E2.byte$f2, $16, $a9, $31, $8d, $19, $04, $ad
$16EA.byte$00, $08, $18, $69, $27, $8d, $1a, $04
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
; Writes the 7-digit current score and the 7-digit high score to the HUD
; area of screen RAM ($0403 and $040E respectively). Converts raw decimal
; digits into screencodes by adding $30.
;
; Inputs: score_7digits, hi_score_7digits
; Outputs: Screen RAM ($0403-$0409, $040E-$0414)
; Side Effects: Updates visible score values on HUD
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
hud_write_score_and_hiscore
$16F2a2 00ldx#$00; write all 7 score digits to $0403-$0409; all 7 hi-score digits to $040E-$0414 ; x-ref: $16D7
$16F4bd 25 08b_16F4ldascore_7digits,x; Read current score digit ; x-ref: $1709
$16F718clc
$16F869 30adc#$30; Convert Score to Screencode
$16FA9d 03 04staSCREEN_RAM_R0C3,x; Write to HUD score area
$16FDbd 50 0fldahi_score_7digits,x; Read high score digit
$170018clc
$170169 30adc#$30; Convert High Score to Screencode
$17039d 0e 04staSCREEN_RAM_R0C14,x; Write to HUD high score area
$1706e8inx
$1707e0 07cpx#$07
$1709d0 e9bneb_16F4
$170B60rts
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
; Initializes the screen and VIC-II state at the start of each level.
; Called on every level start (including 2-player turn swaps).
;
; Phase 1: restore_game_vars, then copy 3 screen pages from tile data under BASIC
; ROM ($8110/$8210/$8300) and HUD row from $8038 to screen RAM;
; apply season text color to all 4 color RAM pages.
; Phase 2: Zero-fill NPC sprite X regs ($D002..$D00D); place player sprite at
; X=$A8, Y=$B0; set player sprite frame ($C0) and color (4=purple);
; enable all 8 sprites; clear jump flag and multicolor mode.
; Phase 3: Reset score digits, speed, all NPC car/sprite state flags, and
; score popup slots; clear collision flag.
; Tail-calls reset_score_sprite_colors to finish.
;
; Inputs: season_nr, level_nr, current_player_nr
; Outputs: Screen RAM ($0400-$07FF), Color RAM ($D800-$DBFF), VIC-II sprite regs
; Side Effects: Clears all enemy/sprite/collision state; resets player speed to $50
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
$170C20 00 50init_level_screenjsrrestore_game_vars; x-ref: $1191, $50A2, $50BB, $5197, $51B8
$170Fa2 00ldx#$00
$171120 d2 50b_1711jsrcopy_hud_text_row; x-ref: $1739
$1714bd 10 81ldaf_8110,x
$17179d 00 05staSCREEN_RAM_R6C16,x
$171Abd 10 82ldaf_8210,x
$171D9d 00 06staSCREEN_RAM_R12C32,x
$1720bd 00 83ldaf_8300,x
$17239d f0 06staSCREEN_RAM_R18C32,x
$1726ac 03 08ldyseason_nr
$1729b9 7c 16ldatbl_text_color_seasons,y; One byte per season (0=Summer, 1=Autumn, 2=Winter, 3=Spring)
$172C9d 28 d8staCOLOR_RAM_R1C0,x
$172F9d 00 d9staCOLOR_RAM_R6C16,x
$17329d 00 dastaCOLOR_RAM_R12C32,x
$17359d f0 dastaCOLOR_RAM_R18C32,x
$1738e8inx
$1739d0 d6bneb_1711
$173Ba2 00ldx#$00; zero-fill VIC-II sprite X regs for NPC sprites 1-7 ($D002..$D00D)
$173D8atxa
$173E9d 02 d0b_173Esta$d002,x; x-ref: $1744 Sprite 1 X Pos
$1741e8inx
$1742e0 0ecpx#$0e
$1744d0 f8bneb_173E
$1746a9 a8lda#$a8; position player sprite at $A8 (center road)
$17488d 00 d0sta$d000; Sprite 0 X Pos
$174Ba9 b0lda#$b0; set player sprite Y pos to $B0; draw player name row
$174D20 35 50jsrset_player_y_and_draw_player_row
$1750a9 c0lda#$c0; player car sprite frame $C0
$17528d f8 07stasprite_ptr_0
$1755a9 04lda#$04
$17578d 27 d0sta$d027; Sprite 0 Color
$175Aa9 fflda#$ff
$175C8d 15 d0sta$d015; Sprite display Enable
$175Fa9 00lda#$00
$17618d 05 08staplayer_is_jumping
$1764a9 1flda#$1f; set score_digits[0] (hundreds) = 0, score_digits[1..2] = 0/8
$17668d 1c d0sta$d01c; Sprites Multi-Color Mode Select
$1769a9 00lda#$00
$176B8d e0 08stascore_digits
$176E8d e2 08staspeed_hundreds_digit
$1771a9 08lda#$08
$17738d e1 08staspeed_tens_digit
$1776a9 50lda#$50
$17788d 04 08staplayer_speed
$177Ba9 00lda#$00
$177D8d 28 09statbl_enemy_car_state
$17808d 29 09statbl_enemy_car_state_1
$17838d 2a 09statbl_enemy_car_state_2
$17868d 2b 09statbl_enemy_car_state_3
$17898d 80 09statbl_score_sprite_active
$178C8d 81 09statbl_score_sprite_active_1
$178F8d 82 09statbl_score_sprite_active_2
$17928d 8a 09stacol_active
$17954c f0 3cjmpreset_score_sprite_colors
$1798.byte$00
$179920 dd 17j_1799jsrupdate_hiscore_if_beaten; x-ref: $4992
$179Cad 20 08ldacrashed_cars_tens
$179F60rts
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
; Handles horizontal movement for the player car (Sprite 0).
; Checks the game state flag at $098A. If active, reads the parsed input state
; at zero page $00F5. Bit 2 ($04) corresponds to Left, Bit 3 ($08) to Right.
; If left is pressed, Sprite 0's X position ($D000) is moved left by 6 pixels,
; clamping at 0. If right is pressed, it is moved right by 6 pixels, clamping
; at $FF (255).
;
; Inputs: State flag $098A, Parsed Input state at $00F5
; Outputs: None
; Side Effects: Modifies Sprite 0 X position ($D000)
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
handle_player_movement
$17A0ad 8a 09ldacol_active; x-ref: $181E, $475C
$17A3f0 01beqb_17A6
$17A560r_17A5rts; x-ref: $17B2
$17A6ad f5 00b_17A6lda@w zp_joy_state; Check input state array at $00F5 ; x-ref: $17A3
$17A929 04and#$04; Check Bit 2 (Left)
$17ABf0 15beqb_17C2
$17ADad f5 00lda@w zp_joy_state
$17B029 08and#$08; Check Bit 3 (Right)
$17B2d0 f1bner_17A5
$17B4ad 00 d0lda$d000; Sprite 0 X Pos
$17B718clc
$17B869 06adc#$06; Move Right 6 pixels
$17BA90 02bccb_17BE
$17BCa9 fflda#$ff; Clamp to max string edge ($FF)
$17BE8d 00 d0b_17BEsta$d000; x-ref: $17BA, $17C8, $17CC Sprite 0 X Pos
$17C160rts
$17C2ad 00 d0b_17C2lda$d000; x-ref: $17AB Sprite 0 X Pos
$17C538sec
$17C6e9 06sbc#$06; Move Left 6 pixels
$17C8b0 f4bcsb_17BE
$17CAa9 00lda#$00; Clamp to left edge ($00)
$17CCf0 f0beqb_17BE
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
; Checks if there is an active collision. If no collision is active,
; it proceeds to handle player acceleration logic.
;
; Inputs: col_active
; Outputs: None
; Side Effects: May branch to handle_acceleration
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
check_acceleration_conditions
$17CEad 8a 09ldacol_active; x-ref: $1832
$17D1f0 01beqb_17D4
$17D360rts
$17D44c 10 44b_17D4jmphandle_acceleration; Proceed to acceleration logic ; x-ref: $17D1
$17D7.byte$00, $00, $00, $00, $00, $00
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
; Compares the player's current score with the high score.
; If the current score is higher, it overwrites the high score.
;
; Inputs: score_7digits ($0825), hi_score_7digits ($0F50)
; Outputs: hi_score_7digits updated if score was higher
; Side Effects: None
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
update_hiscore_if_beaten
$17DDa2 00ldx#$00; x-ref: $1799
$17DFbd 50 0fb_17DFldahi_score_7digits,x; Load high score digit ; x-ref: $17EC
$17E2dd 25 08cmpscore_7digits,x; Compare with current score digit
$17E530 08bmib_17EF; If score is higher, branch to update
$17E7d0 05bner_17EE; If high score is higher, return
$17E9e8inx
$17EAe0 07cpx#$07
$17ECd0 f1bneb_17DF
$17EE60r_17EErts; x-ref: $17E7
$17EFa2 00b_17EFldx#$00; Reset index for copy ; x-ref: $17E5
$17F1bd 25 08b_17F1ldascore_7digits,x; x-ref: $17FA
$17F49d 50 0fstahi_score_7digits,x; Copy score digit to high score
$17F7e8inx
$17F8e0 07cpx#$07
$17FAd0 f5bneb_17F1
$17FC60rts
$17FD.byte$00, $00, $00
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
; Initializes the game and enters the main game loop.
;
; On entry, runs one-time init (game state, VIC-II, screen/sprites), then
; enters the per-frame loop. Each iteration briefly banks out BASIC ROM so
; scroll_and_draw_map_row can read tile data stored under it ($8010+), then
; banks BASIC back in and calls every per-frame update in sequence before
; jumping to apply recoil and looping back.
;
; Inputs: None
; Outputs: None
; Side Effects: Modifies 6510 I/O Port ($01), updates game state and screen
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
$180020 95 11mainjsrinit_game_state; One-time init: zero game state variables and load level data ; x-ref: $129C
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
; Entry point for initializing the game loop. Sets up VIC-II video registers,
; screen, and sprites, then falls through into the main loop.
;
; Inputs: None
; Outputs: None
; Side Effects: Initializes VIC-II hardware state, draws initial screen
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
$180320 00 10game_init_and_loopjsrinit_vic_video; Set up VIC-II registers (border, background, multicolor, raster IRQ) ; x-ref: $12F4, $5107, $511B, $5128
$180620 52 10jsrinit_screen_and_sprites; Draw initial playfield screen and position all sprites
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
; The core per-frame game loop body. Banks out BASIC to draw the map row,
; updates HUD, processes player movement/jumping, checks collisions, updates
; NPC cars, and manages game timing.
;
; Inputs: Current game state, joystick input
; Outputs: None
; Side Effects: Modifies game state, updates screen, manages sprite positions
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
$1809a5 01main_loopldazpa_01; 6510 IO Port ; x-ref: $4FB9
$180B29 feand#$fe; Bank out Basic ROM
$180D85 01stazpa_01
$180F20 00 13jsrscroll_and_draw_map_row; Scroll screen down and draw next tile row (BASIC banked out for tile data at $8010)
$1812a5 01ldazpa_01
$181409 01ora#$01; Bank Basic ROM back in
$181685 01stazpa_01
$181820 b0 16jsrupdate_hud_display; Refresh score, lives, and speed indicator on the HUD row
$181B20 c9 15jsrincrement_score; Add time-based score increment each frame
$181E20 a0 17jsrhandle_player_movement; Read joystick and update player car X/Y position and speed
$182120 00 1ajsrcheck_jump_input; Detect fire button press to initiate a jump over another car
$182420 3a 1ajsrupdate_jump_animation; Advance jump arc frame counter and update sprite pointer
$182720 00 1bjsrcheck_background_collision; Check player sprite vs road/wall tile for collision response
$182A20 00 44jsrapply_y_offset; Apply current vertical scroll offset to all sprite Y positions
$182Dad 05 08ldaplayer_is_jumping; Skip acceleration check while player is airborne
$1830d0 03bneb_1835
$183220 ce 17jsrcheck_acceleration_conditions; Adjust player speed based on current road tile type
$183520 00 46b_1835jsrdelay_frame_by_speed; Busy-wait loop to throttle frame rate to the player's current speed ; x-ref: $1830
$183820 12 47jsrupdate_pickup_timer; Count down timers for on-road pickup items
$183B20 d4 3ajsrprocess_entities_and_input; Handle NPC car AI logic and process any remaining player input side-effects
$183E20 00 3djsrupdate_moving_sprites; Move all active NPC car sprites one step along their path
$184120 55 4ejsrupdate_explosion_animations; Advance crash/explosion sprite animation frames
$184420 a0 49jsrupdate_sprite_animations; Update all other sprite animation states (player car, debris, etc.)
$184720 00 3bjsrdetect_player_car_collision; Check for player-vs-NPC car collisions and trigger responses
$184A20 f0 3ajsrupdate_enemies_and_check_jump; Update enemy AI states and check if player has jumped onto a car
$184D4c cd 4ejmpmain_loop_apply_recoil; Apply X-axis recoil to player, then loop back to main_loop
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
; Converts the number of crashed cars into a score bonus and displays it.
;
; The crashed-car count (a 2-digit value in crashed_cars_tens/ones) is
; multiplied by 100 and added to score_7digits via repeated BCD-style
; addition (5 inner loops: ones->+1, tens->+10, then the computed
; 100/1k/10k partial sums are each added digit-by-digit with carry).
; Afterwards the 3-digit bonus number is written to screen RAM ($057F-$0583)
; and its color (purple=4) to color RAM ($D97F-$D983), skipping leading zeros.
; Finally update_hud_display is called and control falls to the shared
; epilogue that shows a delay and the next-season screen.
;
; Inputs: crashed_cars_tens ($0820), crashed_cars_ones ($0821),
; crashed_cars_bonus_10k/1k/100 ($0830-$0832)
; Outputs: score_7digits ($0825-$082B) updated with bonus
; Side Effects: Writes bonus digits to screen RAM $057F-$0583,
; writes color 4 to color RAM $D97F-$D983,
; calls update_hud_display, then jumps to show next-season screen.
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
calc_and_display_crashed_cars_bonus
$1850a9 00lda#$00; Zero out the 3-digit bonus accumulator (10k, 1k, 100) ; x-ref: $148D
$18528d 30 08stacrashed_cars_bonus_10k
$18558d 31 08stacrashed_cars_bonus_1k
$18588d 32 08stacrashed_cars_bonus_100
$185Bac 21 08ldycrashed_cars_ones; Phase 1: Y = crashed_cars_ones; loop Y times adding +1 to bonus accumulator
$185Ef0 25j_185Ebeqb_1885; x-ref: $1882
$186098tya
$186148pha
$1862a0 05ldy#$05
$1864a2 02b_1864ldx#$02; 5 reps per car (adds 1 to the 3-digit bonus, carries through digits) ; x-ref: $187D
$1866bd 30 08j_1866ldacrashed_cars_bonus_10k,x; X walks digits from MSB [2] to LSB [0]; add 1, propagate carry if digit wraps past 9 ; x-ref: $1876
$186918clc
$186A69 01adc#$01
$186Cc9 0acmp#$0a; Digit wrapped past 9: zero it and carry to the next higher digit
$186Ed0 09bneb_1879
$1870a9 00lda#$00
$18729d 30 08stacrashed_cars_bonus_10k,x
$1875cadex
$18764c 66 18jmpj_1866
$18799d 30 08b_1879stacrashed_cars_bonus_10k,x; x-ref: $186E
$187C88dey
$187Dd0 e5bneb_1864
$187F68pla
$1880a8tay
$188188dey
$18824c 5e 18jmpj_185E
$1885ac 20 08b_1885ldycrashed_cars_tens; Phase 2: Y = crashed_cars_tens; loop Y times adding +10 to bonus accumulator ; x-ref: $185E
$1888f0 25j_1888beqb_18AF; x-ref: $18AC
$188A98tya
$188B48pha
$188Ca0 05ldy#$05
$188Ea2 01b_188Eldx#$01; 5 reps per car (adds 10 to the bonus; only upper 2 digits affected) ; x-ref: $18A7
$1890bd 30 08j_1890ldacrashed_cars_bonus_10k,x; x-ref: $18A0
$189318clc
$189469 01adc#$01
$1896c9 0acmp#$0a
$1898d0 09bneb_18A3
$189Aa9 00lda#$00
$189C9d 30 08stacrashed_cars_bonus_10k,x
$189Fcadex
$18A04c 90 18jmpj_1890
$18A39d 30 08b_18A3stacrashed_cars_bonus_10k,x; x-ref: $1898
$18A688dey
$18A7d0 e5bneb_188E
$18A968pla
$18AAa8tay
$18AB88dey
$18AC4c 88 18jmpj_1888
$18AFa2 00b_18AFldx#$00; Skip leading zeros: scan from MSB until a non-zero digit is found ; x-ref: $1888
$18B1bd 30 08j_18B1ldacrashed_cars_bonus_10k,x; x-ref: $18B7
$18B4d0 04bneb_18BA
$18B6e8inx
$18B74c b1 18jmpj_18B1
$18BAbd 30 08b_18BAldacrashed_cars_bonus_10k,x; Convert digit to PETSCII (+$30) and write to screen RAM $057F+x ; x-ref: $18B4, $18CB
$18BD18clc
$18BE69 30adc#$30
$18C09d 7f 05staSCREEN_RAM_R9C23,x
$18C3a9 04lda#VicIIColors.PURPLE; Set color 4 (purple) for bonus digit in color RAM $D97F+x
$18C59d 7f d9staCOLOR_RAM_R9C23,x
$18C8e8inx
$18C9e0 03cpx#$03
$18CBd0 edbneb_18BA
$18CDa9 30lda#$30; Fill trailing screen RAM positions $0582-$0583 with '0' ($30)
$18CF8d 82 05staSCREEN_RAM_R9C26
$18D28d 83 05staSCREEN_RAM_R9C27
$18D5a9 04lda#VicIIColors.PURPLE; Set color 4 (purple) for trailing positions in color RAM $D982-$D983
$18D78d 82 d9staCOLOR_RAM_R9C26
$18DA8d 83 d9staCOLOR_RAM_R9C27
$18DDac 32 08ldycrashed_cars_bonus_100
$18E0f0 1cj_18E0beqb_18FE; x-ref: $18FB
$18E2a2 04ldx#$04
$18E4bd 25 08j_18E4ldascore_7digits,x; x-ref: $18F4
$18E718clc
$18E869 01adc#$01
$18EAc9 0acmp#$0a
$18ECd0 09bneb_18F7
$18EEa9 00lda#$00
$18F09d 25 08stascore_7digits,x
$18F3cadex
$18F44c e4 18jmpj_18E4
$18F79d 25 08b_18F7stascore_7digits,x; x-ref: $18EC
$18FA88dey
$18FB4c e0 18jmpj_18E0
$18FEac 31 08b_18FEldycrashed_cars_bonus_1k; Phase 4: Y = crashed_cars_bonus_1k; add 1,000 per unit to score_7digits ; x-ref: $18E0
$1901f0 1cj_1901beqb_191F; x-ref: $191C
$1903a2 03ldx#$03
$1905bd 25 08j_1905ldascore_7digits,x; x-ref: $1915
$190818clc
$190969 01adc#$01
$190Bc9 0acmp#$0a
$190Dd0 09bneb_1918
$190Fa9 00lda#$00
$19119d 25 08stascore_7digits,x
$1914cadex
$19154c 05 19jmpj_1905
$19189d 25 08b_1918stascore_7digits,x; x-ref: $190D
$191B88dey
$191C4c 01 19jmpj_1901
$191Fac 30 08b_191Fldycrashed_cars_bonus_10k; Phase 5: Y = crashed_cars_bonus_10k; add 10,000 per unit to score_7digits ; x-ref: $1901
$1922f0 1cj_1922beqb_1940; x-ref: $193D
$1924a2 02ldx#$02
$1926bd 25 08j_1926ldascore_7digits,x; x-ref: $1936
$192918clc
$192A69 01adc#$01
$192Cc9 0acmp#$0a
$192Ed0 09bneb_1939
$1930a9 00lda#$00
$19329d 25 08stascore_7digits,x
$1935cadex
$19364c 26 19jmpj_1926
$19399d 25 08b_1939stascore_7digits,x; x-ref: $192E
$193C88dey
$193D4c 22 19jmpj_1922
$194020 b0 16b_1940jsrupdate_hud_display; Refresh HUD with updated score, then jump to next-season screen epilogue ; x-ref: $1922
$19434c bd 14jmpj_14BD
$1946.fill186, $00
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
; Checks if the Fire button is pressed to initiate a car jump.
; Reads the parsed input state at $00F5 (Bit 4 = Fire button). If the jump
; action is requested and the car is not already jumping (jump state $0805 is 0),
; it initializes the jump animation state machine, sets the initial sprite
; pointer for the jump, and slightly shifts the car's X position.
;
; Inputs: Parsed input state at $00F5, jump state at $0805
; Outputs: None
; Side Effects: Modifies $0805 (jump active), $0806 (jump frame),
; and Sprite 0 X position ($D000).
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
$1A00ad f5 00check_jump_inputlda@w zp_joy_state; Read input state ; x-ref: $1821, $3AD7, $3AF3, $475F
$1A0329 10and#$10; Check Bit 4 (Fire button)
$1A05f0 01beqb_1A08
$1A0760r_1A07rts; x-ref: $1A0B
$1A08ad 05 08b_1A08ldaplayer_is_jumping; Check if already jumping ($0805 != 0) ; x-ref: $1A05
$1A0Bd0 fabner_1A07
$1A0D20 4b 47jsris_speed_above_100_else_return
$1A104alsra
$1A114alsra
$1A1220 f8 1ajsrset_jump_timer_base
$1A15a9 01lda#$01; Set jump active flag
$1A178d 05 08staplayer_is_jumping
$1A1Aa9 01lda#$01; Reset jump animation frame
$1A1C8d 06 08stajump_anim_frame
$1A1Fad 10 08ldajump_timer_base
$1A224alsra
$1A234alsra
$1A244alsra
$1A258d 11 08stajump_frame_timer
$1A28a9 d4lda#$d4; Set Sprite 0 pointer for jump start
$1A2A8d f8 07stasprite_ptr_0
$1A2Dad 00 d0lda$d000; Sprite 0 X Pos
$1A3018clc
$1A3169 04adc#$04
$1A338d 00 d0sta$d000; Sprite 0 X Pos
$1A36eanop
$1A37eanop
$1A38eanop
$1A3960rts
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
; Processes the jump animation state machine for Sprite 0.
; This routine runs continuously in the game loop. If $0805 indicates a jump is
; active, it decrements the frame timer $0811. Once the timer elapses, it
; advances the animation frame $0806 and uses a switch statement ($1A51) to update
; the sprite pointer, sizes, and position to create a jumping arc.
; When the animation reaches the end (frame 9), it resets $0805 to 0.
;
; Inputs: Jump state at $0805, animation frame $0806, timer $0811
; Outputs: None
; Side Effects: Modifies Sprite 0 X position ($D000), Sprite Pointer ($07F8),
; and Sprite Expansion bits ($D017, $D01D).
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
update_jump_animation
$1A3Aad 05 08ldaplayer_is_jumping; Check jump active flag ; x-ref: $1824, $4762
$1A3Dd0 01bneb_1A40
$1A3F60r_1A3Frts; x-ref: $1A43
$1A40ce 11 08b_1A40decjump_frame_timer; Decrement jump frame timer ; x-ref: $1A3D
$1A43d0 fabner_1A3F
$1A45ad 10 08ldajump_timer_base
$1A484alsra
$1A494alsra
$1A4A4alsra
$1A4B8d 11 08stajump_frame_timer
$1A4E20 eb 1ajsrincrement_jump_frame; Increment animation frame (in A)
$1A51c9 09cmp#$09
$1A53f0 2dbeqb_1A82
$1A55c9 08cmp#$08
$1A57f0 26beqb_1A7F
$1A59c9 07cmp#$07
$1A5Bf0 1fbeqb_1A7C
$1A5Dc9 06cmp#$06
$1A5Ff0 18beqb_1A79
$1A61c9 05cmp#$05
$1A63f0 11beqb_1A76
$1A65c9 04cmp#$04
$1A67f0 0abeqb_1A73
$1A69c9 03cmp#$03
$1A6Bf0 03beqb_1A70
$1A6D4c 85 1ajmpjump_anim_frame_1_2
$1A704c 94 1ab_1A70jmpjump_anim_expand_sprite; x-ref: $1A6B
$1A734c ab 1ab_1A73jmpjump_anim_frame_4_5; x-ref: $1A67
$1A764c ab 1ab_1A76jmpjump_anim_frame_4_5; x-ref: $1A63
$1A794c f2 1ab_1A79jmpjump_anim_frame_0; x-ref: $1A5F
$1A7C4c b1 1ab_1A7Cjmpjump_anim_shrink_sprite; x-ref: $1A5B
$1A7F4c c8 1ab_1A7Fjmpjump_anim_frame_6_or_8; x-ref: $1A57
$1A824c d7 1ab_1A82jmpjump_anim_terminate; x-ref: $1A53
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
; Jump Animation Frame 1 & 2 Handler.
; Sets the player car sprite pointer to the ascending graphic.
; X position is processed but effectively unchanged (SBC #$00).
;
; Inputs: None
; Outputs: Sprite 0 Pointer updated
; Side Effects: Updates Sprite 0 graphic.
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
$1A85a9 d3jump_anim_frame_1_2lda#$d3; Animation Frame 1 & 2: Draw ascending sprite ; x-ref: $1A6D
$1A878d f8 07stasprite_ptr_0
$1A8Aad 00 d0lda$d000; Sprite 0 X Pos
$1A8D38sec
$1A8Ee9 00sbc#$00
$1A908d 00 d0sta$d000; Sprite 0 X Pos
$1A9360rts
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
; Jump Animation Frame 3 Handler (Apex).
; Expands the player sprite 2x horizontally and vertically to simulate maximum
; height. Adjusts the X position left by 12 pixels to keep the car visually centered.
;
; Inputs: Sprite 0 X position ($D000)
; Outputs: Sprite 0 X position ($D000), Sprite Expansion registers ($D017, $D01D)
; Side Effects: Enlarges Sprite 0.
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
jump_anim_expand_sprite
$1A94a9 d2lda#$d2; Animation Frame 3: Max height, expand sprite ; x-ref: $1A70
$1A968d f8 07stasprite_ptr_0
$1A99a9 01lda#$01
$1A9B8d 17 d0sta$d017; Sprites Expand 2x Vertical (Y)
$1A9E8d 1d d0sta$d01d; Sprites Expand 2x Horizontal (X)
$1AA1ad 00 d0lda$d000; Sprite 0 X Pos
$1AA438sec
$1AA5e9 0csbc#$0c; Compensate for center shift on expansion
$1AA78d 00 d0sta$d000; Sprite 0 X Pos
$1AAA60rts
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
; Jump Animation Frame 4 & 5 Handler.
; Updates the player sprite to the descending graphic while still expanded.
;
; Inputs: None
; Outputs: Sprite 0 Pointer updated
; Side Effects: Updates Sprite 0 graphic.
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
$1AABa9 d4jump_anim_frame_4_5lda#$d4; Animation Frame 4 & 5: Expanded descending ; x-ref: $1A73, $1A76
$1AAD8d f8 07stasprite_ptr_0
$1AB060rts
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
; Jump Animation Frame 7 Handler.
; Shrinks the player sprite back to normal 1x size as it nears the ground.
; Adjusts the X position right by 12 pixels to compensate for the center shift.
;
; Inputs: Sprite 0 X position ($D000)
; Outputs: Sprite 0 X position ($D000), Sprite Expansion registers ($D017, $D01D)
; Side Effects: Restores Sprite 0 to normal size.
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
jump_anim_shrink_sprite
$1AB1a9 00lda#$00; Animation Frame 7: Shrink sprite back ; x-ref: $1A7C
$1AB38d 17 d0sta$d017; Sprites Expand 2x Vertical (Y)
$1AB68d 1d d0sta$d01d; Sprites Expand 2x Horizontal (X)
$1AB9a9 d3lda#$d3
$1ABB8d f8 07stasprite_ptr_0
$1ABEad 00 d0lda$d000; Sprite 0 X Pos
$1AC118clc
$1AC269 0cadc#$0c; Compensate for center shift on shrink
$1AC48d 00 d0sta$d000; Sprite 0 X Pos
$1AC760rts
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
; Jump Animation Frame 6 & 8 Handler.
; Updates the player sprite to the descending graphic.
; X position is processed but effectively unchanged (ADC #$00).
;
; Inputs: None
; Outputs: Sprite 0 Pointer updated
; Side Effects: Updates Sprite 0 graphic.
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
jump_anim_frame_6_or_8
$1AC8a9 d4lda#$d4; x-ref: $1A7F
$1ACA8d f8 07stasprite_ptr_0
$1ACDad 00 d0lda$d000; Sprite 0 X Pos
$1AD018clc
$1AD169 00adc#$00
$1AD38d 00 d0sta$d000; Sprite 0 X Pos
$1AD660rts
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
; Jump Animation Termination Handler.
; Ends the jump sequence by resetting the jumping flag, silencing the jump sound
; effect on SID Voice 1, and shifting the car left by 4 pixels.
;
; Inputs: Sprite 0 X position ($D000)
; Outputs: player_is_jumping flag ($0805), Sprite 0 X position ($D000)
; Side Effects: Stops jump sound, restores normal gameplay state.
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
$1AD7a9 00jump_anim_terminatelda#$00; Animation Frame 9 (End): Reset sequence ; x-ref: $1A82
$1AD98d 05 08staplayer_is_jumping
$1ADCa9 c0lda#$c0
$1ADE20 30 4cjsrrestore_player_sprite_stop_sound; Stop SID Voice 1 jump sound
$1AE1ad 00 d0lda$d000; Sprite 0 X Pos
$1AE438sec
$1AE5e9 04sbc#$04
$1AE78d 00 d0sta$d000; Sprite 0 X Pos
$1AEA60rts
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
; Advances the jump animation frame counter and returns the new frame number.
;
; Inputs: jump_anim_frame
; Outputs: A register (new frame number), jump_anim_frame
; Side Effects: None
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
$1AEBee 06 08increment_jump_frameincjump_anim_frame; x-ref: $1A4E
$1AEEad 06 08ldajump_anim_frame
$1AF160rts
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
; Jump Animation Frame 0 (and 6) Handler.
; Sets the player car sprite pointer to the neutral graphic.
;
; Inputs: None
; Outputs: Sprite 0 Pointer updated
; Side Effects: Updates Sprite 0 graphic.
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
$1AF2a9 d2jump_anim_frame_0lda#$d2; x-ref: $1A79
$1AF48d f8 07stasprite_ptr_0
$1AF760rts
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
; Calculates and sets the base timer for the jump animation based on the car's
; current speed/momentum. Adds 15 to the input accumulator value.
;
; Inputs: A register (base delay)
; Outputs: jump_timer_base ($0807)
; Side Effects: Adjusts the animation speed.
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
$1AF818set_jump_timer_baseclc; x-ref: $1A12
$1AF969 0fadc#$0f
$1AFB8d 10 08stajump_timer_base
$1AFE60rts
$1AFF00.byte$00
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
; Checks if the player's car has collided with physical background obstacles.
; First, checks if the car is actively jumping (ignores collision if jump state
; is non-zero). If on the ground, transforms Sprite 0's X and Y pixel positions
; into 40x25 character grid coordinates (column and row). It then calculates
; a pointer into Screen RAM ($0400) relative to the car's current position.
; Finally, tests the four corners surrounding the car's footprint by fetching
; the characters and calling $46DE to see if they are a fatal obstacle tile.
;
; Inputs: Jump State at $0805, Sprite 0 X/Y Positions ($D000, $D001)
; Outputs: None (Direct exit/jump on collision via $46DE)
; Side Effects: Can initiate crash sequence, mutates temp pointers $49 and $4A.
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
check_background_collision
$1B00ad 05 08ldaplayer_is_jumping; Ignore collision if jumping ; x-ref: $1827, $4765
$1B03f0 01beqb_1B06
$1B0560rts
$1B06ad 00 d0b_1B06lda$d000; Convert Pixel X to Char Column (divide by 8) ; x-ref: $1B03 Sprite 0 X Pos
$1B0938sec
$1B0Ae9 10sbc#$10
$1B0C4alsra
$1B0D4alsra
$1B0E4alsra
$1B0Fa8tay
$1B10a9 04lda#>SCREEN_RAM
$1B1285 4astazp_p_tmp_hi
$1B14a9 00lda#<SCREEN_RAM
$1B1685 49stazp_p_tmp_lo
$1B18ad 01 d0lda$d001; Convert Pixel Y to Char Row (divide by 8); Sprite 0 Y Pos
$1B1B38sec
$1B1Ce9 2esbc#$2e
$1B1E4alsra
$1B1F4alsra
$1B204alsra
$1B21aatax
$1B22f0 11j_1B22beqb_1B35; Calculate pointer offset down Screen RAM ; x-ref: $1B32
$1B24a5 49ldazp_p_tmp_lo
$1B2618clc
$1B2769 28adc#$28
$1B2985 49stazp_p_tmp_lo
$1B2Ba5 4aldazp_p_tmp_hi
$1B2D69 00adc#$00
$1B2F85 4astazp_p_tmp_hi
$1B31cadex
$1B324c 22 1bjmpj_1B22
$1B35b1 49b_1B35lda(zp_p_tmp_lo),y; Check Top-Left Character ; x-ref: $1B22
$1B37eanop
$1B3820 de 46jsrcheck_tile_is_obstacle
$1B3Bc8iny; Check Top-Right Character
$1B3Cb1 49lda(zp_p_tmp_lo),y
$1B3Eeanop
$1B3F20 de 46jsrcheck_tile_is_obstacle
$1B4298tya; Move to Bottom-Left Character
$1B4318clc
$1B4469 27adc#$27
$1B46a8tay
$1B47b1 49lda(zp_p_tmp_lo),y
$1B49eanop
$1B4A20 de 46jsrcheck_tile_is_obstacle
$1B4Dc8iny; Check Bottom-Right Character
$1B4Eb1 49lda(zp_p_tmp_lo),y
$1B50eanop
$1B5120 de 46jsrcheck_tile_is_obstacle
$1B5460rts
$1B554c 00 48j_1B55jmpplayer_death_handler; x-ref: $46E9
$1B58.byte$ad, $23, $08, $d0, $f7
$1B5D20 10 46j_1B5Djsrshow_game_over_and_wait; x-ref: $4870
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
; High Score Entry Screen
;
; Displays the high score screen, determines if the player's score qualifies
; for the top 5, shifts the table to insert it, and lets the player enter
; their 3-letter initials using a joystick-controlled letter grid.
; A countdown timer auto-confirms when it reaches 00.
;
; Inputs: score_7digits ($2428) - player's current score (7 BCD digits)
; joy_state ($F5) - joystick state for grid navigation
; High score table at $7400-$7457 (5 entries: scores + names)
; Outputs: state_cleanup_index ($0857) - ranking position (1-5), or 0
; High score table updated with new entry if qualified
; Side Effects: Writes to Screen RAM ($0400+) and Color RAM ($D800+)
; Calls update_hud_display. Runs a timed input loop.
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
high_score_entry_screen
$1B60a2 00ldx#$00; X = loop counter 0..255
$1B62bd 28 2cb_1B62ldaenter_high_score_screen_1,x; copy letter grid row 1 to screen ; x-ref: $1B89
$1B659d a0 04staSCREEN_RAM_R4C0,x
$1B68bd 00 2dldaenter_high_score_screen_2,x; copy letter grid row 2 to screen
$1B6B9d 78 05staSCREEN_RAM_R9C16,x
$1B6Ebd 00 2eldaenter_high_score_screen_3,x; copy letter grid row 3 to screen
$1B719d 78 06staSCREEN_RAM_R15C32,x
$1B74bd 78 2eldaenter_high_score_screen_4,x; copy letter grid row 4 to screen
$1B779d f0 06staSCREEN_RAM_R18C32,x
$1B7Aa9 07lda#VicIIColors.YELLOW; yellow
$1B7C9d 28 d8staCOLOR_RAM_R1C0,x; color 4 pages of Color RAM
$1B7F9d 00 d9staCOLOR_RAM_R6C16,x
$1B829d 00 dastaCOLOR_RAM_R12C32,x
$1B859d 00 dbstaCOLOR_RAM_R19C8,x
$1B88e8inx
$1B89d0 d7bneb_1B62
$1B8Bbd 28 24b_1B8Bldaf_2428,x; copy title/header to top of screen ; x-ref: $1B99
$1B8E9d 28 04staSCREEN_RAM_R1C0,x
$1B91a9 0alda#VicIIColors.LIGHT_RED; light red
$1B939d 28 d8staCOLOR_RAM_R1C0,x
$1B96e8inx
$1B97e0 78cpx#$78
$1B99d0 f0bneb_1B8B
; --- Compare score against top 5 entries (7 BCD digits each) ---
$1B9Ba2 00check_1st_placeldx#$00
$1B9Dbd 00 74b_1B9Dldaf_7400,x; 1st place score at $7400 ; x-ref: $1BAA
$1BA0dd 25 08cmpscore_7digits,x
$1BA330 0fbmiis_1st_place; score < 1st? rank = 1
$1BA5d0 12bnecheck_2nd_place; score > 1st? check 2nd
$1BA7e8inx
$1BA8e0 07cpx#$07
$1BAAd0 f1bneb_1B9D
$1BACa9 02lda#$02; score == 1st → rank 2 (below tie)
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
; Stores the calculated ranking and proceeds to insert the score.
;
; Inputs: A = Rank (1-5, or 0 if not ranked)
; Outputs: name_entry_substate = Rank
; Side Effects: Jumps to insert_score_in_table
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
store_rank_and_insert
$1BAE8d 57 08staname_entry_substate; store ranking (0-5) ; x-ref: $1BB6, $1BCC, $1BD1, $1BE7, $1BEC, $1C02, $1C07, $1C1D, ...
$1BB14c 28 1cjmpinsert_score_in_table
$1BB4a9 01is_1st_placelda#$01; Set rank to 1 ; x-ref: $1BA3
$1BB64c ae 1bjmpstore_rank_and_insert
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
; Compares the player's score against the 2nd place leaderboard score.
;
; Inputs: score_7digits = Player score, $7408 = 2nd place score
; Outputs: A = Rank (2 if higher, 3 if equal, otherwise checks 3rd place)
; Side Effects: Jumps to store_rank_and_insert or falls through to check_3rd_place
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
$1BB9a2 00check_2nd_placeldx#$00; x-ref: $1BA5
$1BBBbd 08 74check_2nd_loopldaf_7408,x; Load 2nd place digit ; x-ref: $1BC8
$1BBEdd 25 08cmpscore_7digits,x; Compare with player's score digit
$1BC130 0cbmiis_2nd_place; Leaderboard digit < player digit -> player is 2nd
$1BC3d0 0fbnecheck_3rd_place; Leaderboard digit > player digit -> check 3rd
$1BC5e8inx
$1BC6e0 07cpx#$07
$1BC8d0 f1bnecheck_2nd_loop
$1BCAa9 03lda#$03; Scores equal -> player becomes 3rd
$1BCC4c ae 1bjmpstore_rank_and_insert
$1BCFa9 02is_2nd_placelda#$02; Set rank to 2 ; x-ref: $1BC1
$1BD14c ae 1bjmpstore_rank_and_insert
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
; Compares the player's score against the 3rd place leaderboard score.
;
; Inputs: score_7digits = Player score, $7410 = 3rd place score
; Outputs: A = Rank (3 if higher, 4 if equal, otherwise checks 4th place)
; Side Effects: Jumps to store_rank_and_insert or falls through to check_4th_place
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
$1BD4a2 00check_3rd_placeldx#$00; x-ref: $1BC3
$1BD6bd 10 74check_3rd_loopldaf_7410,x; Load 3rd place digit ; x-ref: $1BE3
$1BD9dd 25 08cmpscore_7digits,x; Compare with player's score digit
$1BDC30 0cbmiis_3rd_place; Leaderboard digit < player digit -> player is 3rd
$1BDEd0 0fbnecheck_4th_place; Leaderboard digit > player digit -> check 4th
$1BE0e8inx
$1BE1e0 07cpx#$07
$1BE3d0 f1bnecheck_3rd_loop
$1BE5a9 04lda#$04; Scores equal -> player becomes 4th
$1BE74c ae 1bjmpstore_rank_and_insert; shift 2nd→3rd
$1BEAa9 03is_3rd_placelda#$03; Set rank to 3 ; x-ref: $1BDC
$1BEC4c ae 1bjmpstore_rank_and_insert
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
; Compares the player's score against the 4th place leaderboard score.
;
; Inputs: score_7digits = Player score, $7418 = 4th place score
; Outputs: A = Rank (4 if higher, 5 if equal, otherwise checks 5th place)
; Side Effects: Jumps to store_rank_and_insert or falls through to check_5th_place
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
$1BEFa2 00check_4th_placeldx#$00; x-ref: $1BDE
$1BF1bd 18 74check_4th_loopldaf_7418,x; Load 4th place digit ; x-ref: $1BFE
$1BF4dd 25 08cmpscore_7digits,x; Compare with player's score digit
$1BF730 0cbmiis_4th_place; Leaderboard digit < player digit -> player is 4th
$1BF9d0 0fbnecheck_5th_place; Leaderboard digit > player digit -> check 5th
$1BFBe8inx
$1BFCe0 07cpx#$07
$1BFEd0 f1bnecheck_4th_loop
$1C00a9 05lda#$05; Scores equal -> player becomes 5th
$1C024c ae 1bjmpstore_rank_and_insert
$1C05a9 04is_4th_placelda#$04; Set rank to 4 ; x-ref: $1BF7
$1C074c ae 1bjmpstore_rank_and_insert
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
; Compares the player's score against the 5th place leaderboard score.
;
; Inputs: score_7digits = Player score, $7420 = 5th place score
; Outputs: A = Rank (5 if higher, 0 if equal or lower)
; Side Effects: Jumps to store_rank_and_insert
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
$1C0Aa2 00check_5th_placeldx#$00; x-ref: $1BF9
$1C0Cbd 20 74check_5th_loopldaf_7420,x; Load 5th place digit ; x-ref: $1C19
$1C0Fdd 25 08cmpscore_7digits,x; Compare with player's score digit
$1C1230 0cbmiis_5th_place; Leaderboard digit < player digit -> player is 5th
$1C14d0 0fbnescore_too_low; Leaderboard digit > player digit -> score too low
$1C16e8inx
$1C17e0 07cpx#$07
$1C19d0 f1bnecheck_5th_loop
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
; Handles the case where the player's score did not qualify for the top 5.
;
; Inputs: None
; Outputs: A = 0 (Rank 0)
; Side Effects: Jumps to store_rank_and_insert
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
$1C1Ba9 00score_not_rankedlda#$00; Rank 0 = not in top 5 ; x-ref: $1C25
$1C1D4c ae 1bjmpstore_rank_and_insert
$1C20a9 05is_5th_placelda#$05; Set rank to 5 ; x-ref: $1C12
$1C224c ae 1bjmpstore_rank_and_insert
$1C254c 1b 1cscore_too_lowjmpscore_not_ranked; Jump to unranked handler ; x-ref: $1C14
; --- Shift table entries down and insert new score ---
insert_score_in_table
$1C28ad 57 08ldaname_entry_substate; x-ref: $1BB1
$1C2Bf0 4fbeqb_1C7C; rank 0 = not ranked, skip insertion
$1C2Dc9 05cmp#$05
$1C2Ff0 4bb_1C2Fbeqb_1C7C; x-ref: $1C45, $1C59, $1C6D
$1C3120 f7 1cjsrshift_name_entries_down; shift name entries down
$1C34eanop
$1C35bd 18 74b_1C35ldaf_7418,x; shift 5th→6th (discard) ; x-ref: $1C3E
$1C389d 20 74staf_7420,x; beq score_not_ranked (rank 0)
$1C3Be8inx
$1C3Ce0 08cpx#$08
$1C3Ed0 f5bneb_1C35
$1C40ad 57 08ldaname_entry_substate
$1C43c9 04cmp#$04
$1C45f0 e8beqb_1C2F
$1C47a2 00ldx#$00
$1C49bd 10 74b_1C49ldaf_7410,x; x-ref: $1C52
$1C4C9d 18 74staf_7418,x
$1C4Fe8inx
$1C50e0 08cpx#$08
$1C52d0 f5bneb_1C49
$1C54ad 57 08ldaname_entry_substate
$1C57c9 03cmp#$03
$1C59f0 d4beqb_1C2F
$1C5Ba2 00ldx#$00; shift 3rd→4th
$1C5Dbd 08 74b_1C5Dldaf_7408,x; x-ref: $1C66
$1C609d 10 74staf_7410,x
$1C63e8inx
$1C64e0 08cpx#$08
$1C66d0 f5bneb_1C5D
$1C68ad 57 08ldaname_entry_substate
$1C6Bc9 02cmp#$02
$1C6Df0 c0beqb_1C2F
$1C6Fa2 00ldx#$00; shift 2nd→3rd
$1C71bd 00 74b_1C71ldaf_7400,x; x-ref: $1C7A
$1C749d 08 74staf_7408,x
$1C77e8inx
$1C78e0 08cpx#$08
$1C7Ad0 f5bneb_1C71
$1C7Cad 57 08b_1C7Cldaname_entry_substate; x-ref: $1C2B, $1C2F
$1C7Ff0 1abeqdisplay_high_score_table
$1C8138sec
$1C82e9 01sbc#$01
$1C840aasla
$1C850aasla
$1C860aasla
$1C87a8tay
$1C88a2 00ldx#$00
$1C8Abd 25 08b_1C8Aldascore_7digits,x; x-ref: $1C99
$1C8D99 00 74staf_7400,y
$1C90a9 20lda#$20
$1C9299 30 74staf_7430,y
$1C95c8iny
$1C96e8inx; copy 7 score digits to table
$1C97e0 07cpx#$07
$1C99d0 efbneb_1C8A
; --- Render all 5 entries: names to screen ---
display_high_score_table
$1C9Ba2 00ldx#$00; x-ref: $1C7F
$1C9Dbd 30 74b_1C9Dldaf_7430,x; name entry 1 (3 chars) ; x-ref: $1CBE
$1CA09d 18 06staSCREEN_RAM_R13C16,x
$1CA3bd 38 74ldaf_7438,x
$1CA69d 68 06staSCREEN_RAM_R15C16,x
$1CA9bd 40 74ldaf_7440,x
$1CAC9d b8 06staSCREEN_RAM_R17C16,x; name entry 4
$1CAFbd 48 74ldaf_7448,x; inner delay loop (256 ticks)
$1CB29d 08 07staSCREEN_RAM_R19C16,x
$1CB5bd 50 74ldaf_7450,x; delay loop outer: 256 * 256 iterations for pacing
$1CB89d 58 07staSCREEN_RAM_R21C16,x
$1CBBe8inx; ones digit: SBC #1; underflow ($FF) means carry to tens
$1CBCe0 03cpx#$03
$1CBEd0 ddbneb_1C9D
$1CC0a2 00ldx#$00
; --- Render score digits (+$30 = screen code '0') ---
display_scores_as_digits
$1CC2bd 00 74ldaf_7400,x; x-ref: $1CF2
$1CC518clc
$1CC669 30adc#$30; if both digits zero: timer expired, auto-confirm
$1CC89d 1c 06staSCREEN_RAM_R13C20,x
$1CCBbd 08 74ldaf_7408,x
$1CCE18clc
$1CCF69 30adc#$30
$1CD19d 6c 06staSCREEN_RAM_R15C20,x
$1CD4bd 10 74ldaf_7410,x
$1CD718clc
$1CD869 30adc#$30
$1CDA9d bc 06staSCREEN_RAM_R17C20,x
$1CDDbd 18 74ldaf_7418,x
$1CE018clc
$1CE169 30adc#$30
$1CE39d 0c 07staSCREEN_RAM_R19C20,x
$1CE6bd 20 74ldaf_7420,x
$1CE918clc
$1CEA69 30adc#$30
$1CEC9d 5c 07staSCREEN_RAM_R21C20,x
$1CEFe8inx
$1CF0e0 07cpx#$07
$1CF2d0 cebnedisplay_scores_as_digits
$1CF44c 4e 1djmpafter_table_update
; --- Shift 3-char name entries down in the name table ($7430) ---
shift_name_entries_down
$1CF7ad 57 08ldaname_entry_substate; x-ref: $1C31
$1CFAc9 05cmp#$05
$1CFCf0 7ebeqb_1D7C
$1CFEc9 00cmp#$00
$1D00f0 7abeqb_1D7C
$1D02a2 00ldx#$00
$1D04bd 48 74b_1D04ldaf_7448,x; shift 5th name → 6th (discard) ; x-ref: $1D0D
$1D079d 50 74staf_7450,x
$1D0Ae8inx
$1D0Be0 03cpx#$03
$1D0Dd0 f5bneb_1D04
$1D0Fad 57 08ldaname_entry_substate
$1D12c9 04cmp#$04
$1D14f0 35beqb_1D4B
$1D16a2 00ldx#$00
$1D18bd 40 74b_1D18ldaf_7440,x; shift 4th → 5th ; x-ref: $1D21
$1D1B9d 48 74staf_7448,x
$1D1Ee8inx
$1D1Fe0 03cpx#$03
$1D21d0 f5bneb_1D18
$1D23ad 57 08ldaname_entry_substate
$1D26c9 03cmp#$03
$1D28f0 21beqb_1D4B
$1D2Aa2 00ldx#$00
$1D2Cbd 38 74b_1D2Cldaf_7438,x; shift 3rd → 4th ; x-ref: $1D35
$1D2F9d 40 74staf_7440,x
$1D32e8inx
$1D33e0 03cpx#$03
$1D35d0 f5bneb_1D2C
$1D37ad 57 08ldaname_entry_substate
$1D3Ac9 02cmp#$02
$1D3Cf0 0dbeqb_1D4B
$1D3Ea2 00ldx#$00
$1D40bd 30 74b_1D40ldaf_7430,x; shift 2nd → 3rd ; x-ref: $1D49
$1D439d 38 74staf_7438,x
$1D46e8inx
$1D47e0 03cpx#$03
$1D49d0 f5bneb_1D40
$1D4Ba2 00b_1D4Bldx#$00; x-ref: $1D14, $1D28, $1D3C
$1D4D60rts
; --- Check if player qualified; if so, enter initials ---
$1D4E20 b0 16after_table_updatejsrupdate_hud_display; copy message to screen ; x-ref: $1CF4
$1D51ad 57 08ldaname_entry_substate
$1D54d0 03bneb_1D59; color = cyan
$1D564c fc 1db_1D56jmpshow_not_in_top_5_message; x-ref: $1D5B
$1D59c9 00b_1D59cmp#$00; x-ref: $1D54
$1D5Bf0 f9beqb_1D56; read screen char at cursor → store as 1st initial in table and screen
$1D5Da9 09lda#$09; countdown timer tens digit = 9
$1D5F8d 58 08stahighscore_timer_tens
$1D62a9 09lda#$09
$1D648d 59 08stahighscore_timer_ones; countdown timer ones digit = 9
$1D67a9 05lda#$05
$1D698d 60 08staactive_row
$1D6Ca9 06lda#$06
$1D6E8d 61 08staactive_col; starting grid column = 6
$1D71a2 00ldx#$00
; High Score input loop: display cursor, read joystick
$1D7320 25 1ehighscore_input_loopjsrdraw_highscore_timer_and_cursor; x-ref: $1DE7
$1D7620 b7 1ejsrhighlight_cursor_cell
$1D79eanop
$1D7Aeanop
$1D7Beanop
$1D7Ceab_1D7Cnop; x-ref: $1CFC, $1D00
$1D7Deanop
$1D7Eeanop
$1D7Feanop
$1D80eanop
$1D81eanop
$1D82eanop
$1D83ad f5 00lda@w zp_joy_state; read joystick port
$1D8629 1fand#$1f; mask direction + fire bits
$1D88c9 1ecmp#$1e; $1E = up
$1D8Af0 60beqhighscore_joy_up
$1D8Cc9 1dcmp#$1d; $1D = down
$1D8Ef0 5fbeqhighscore_joy_down
$1D90c9 1bcmp#$1b; $1B = left
$1D92f0 5ebeqhighscore_joy_left
$1D94c9 17cmp#$17; $17 = right
$1D96f0 5dbeqhighscore_joy_right
$1D98c9 0fcmp#$0f; $0F = fire button
$1D9Af0 5cbeqhighscore_joy_fire
; --- Decrement countdown timer; end entry when expired ---
$1D9C20 25 1edecrement_timerjsrdraw_highscore_timer_and_cursor; display timer, then delay ; x-ref: $1E6C, $1E7F, $1E92, $1EA8, $1F97, $4688, $4698, $46A8, ...
$1D9F8atxa
$1DA048pha
$1DA1a2 00ldx#$00
$1DA3a0 00b_1DA3ldy#$00; x-ref: $1DA9
$1DA588b_1DA5dey; x-ref: $1DA6
$1DA6d0 fdbneb_1DA5
$1DA8cadex
$1DA9d0 f8bneb_1DA3
$1DAB68pla
$1DACaatax
$1DADad 59 08ldahighscore_timer_ones; advance name letter index, then rejoin timer tick
$1DB038sec; ones digit -= 1
$1DB1e9 01sbc#$01
$1DB38d 59 08stahighscore_timer_ones
$1DB6c9 ffcmp#$ff; underflow? wrap to 9
$1DB8d0 0ebneb_1DC8
$1DBAa9 09lda#$09; reset ones to 9
$1DBC8d 59 08stahighscore_timer_ones
$1DBFad 58 08ldahighscore_timer_tens; tens digit -= 1
$1DC238sec
$1DC3e9 01sbc#$01
$1DC58d 58 08stahighscore_timer_tens
$1DC8ad 58 08b_1DC8ldahighscore_timer_tens; x-ref: $1DB8, $46D1
$1DCBd0 1abneb_1DE7
$1DCDad 59 08ldahighscore_timer_ones
$1DD0d0 15bneb_1DE7
$1DD2ad 58 08ldahighscore_timer_tens
$1DD518clc
$1DD669 30adc#$30
$1DD88d cb 05staSCREEN_RAM_R11C19
$1DDBad 59 08ldahighscore_timer_ones
$1DDE18clc
$1DDF69 30adc#$30
$1DE18d cc 05staSCREEN_RAM_R11C20
$1DE44c 0e 1ejmpj_1E0E
$1DE74c 73 1db_1DE7jmphighscore_input_loop; x-ref: $1DCB, $1DD0
$1DEA.byte$71, $1d
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
; Highscore Joystick Dispatch Trampolines
;
; Inputs: None
; Outputs: None
; Side Effects: Jumps to the respective cursor movement or fire handler
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
$1DEC4c 65 1ehighscore_joy_upjmphighscore_move_up; Dispatch up ; x-ref: $1D8A
$1DEF4c 78 1ehighscore_joy_downjmphighscore_move_down; Dispatch down ; x-ref: $1D8E
$1DF24c 8b 1ehighscore_joy_leftjmphighscore_move_left; Dispatch left ; x-ref: $1D92
$1DF54c a1 1ehighscore_joy_rightjmphighscore_move_right; Dispatch right ; x-ref: $1D96
$1DF84c be 3fhighscore_joy_firejmphighscore_fire_pressed; Dispatch fire ; x-ref: $1D9A
$1DFBea.byte$ea
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
; Display "Not In Top 5" Message
;
; Inputs: None
; Outputs: Screen RAM and Color RAM
; Side Effects: Copies the text to the screen and sets its color to cyan
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
show_not_in_top_5_message
$1DFCa2 00ldx#$00; x-ref: $1D56
$1DFEbd d0 2fb_1DFEldatxt_you_arent_in_the_five_best_scores,x; Read character from message ; x-ref: $1E0C
$1E019d bb 05staSCREEN_RAM_R11C3,x; Write to screen RAM
$1E04a9 03lda#VicIIColors.CYAN; Cyan color
$1E069d bb d9staCOLOR_RAM_R11C3,x; Write to color RAM
$1E09e8inx
$1E0Ae0 22cpx#$22
$1E0Cd0 f0bneb_1DFE
$1E0E4c e1 51j_1E0Ejmppoll_joy_for_scroll_switch; x-ref: $1DE4
; dead code
$1E11.byte$5a, $08, $a2, $00, $a0, $00, $88, $d0
$1E19.byte$fd, $ca, $d0, $f8, $ce, $5a, $08, $d0
$1E21.byte$f1, $4c, $00, $51
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
; Draw Highscore Timer And Cursor
;
; Inputs: highscore_timer_tens, highscore_timer_ones, active_row, active_col
; Outputs: Screen RAM and Color RAM
; Side Effects: Updates the timer display digits, colors them cyan, and colors the active cursor letter red
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
draw_highscore_timer_and_cursor
$1E25ad 58 08ldahighscore_timer_tens; Load tens digit ; x-ref: $1D73, $1D9C
$1E2818clc
$1E2969 30adc#$30; Convert to screencode
$1E2B8d cb 05staSCREEN_RAM_R11C19
$1E2Ead 59 08ldahighscore_timer_ones; Load ones digit
$1E3118clc
$1E3269 30adc#$30; Convert to screencode
$1E348d cc 05staSCREEN_RAM_R11C20
$1E37a9 03lda#VicIIColors.CYAN; Cyan color
$1E398d cb d9staCOLOR_RAM_R11C19
$1E3C8d cc d9staCOLOR_RAM_R11C20
$1E3Fa9 d8lda#>COLOR_RAM; Color RAM high byte ($D8)
$1E4185 4astazp_p_tmp_hi
$1E43ad 61 08ldaactive_col; Cursor column
$1E4685 49stazp_p_tmp_lo
$1E48ac 60 08ldyactive_row; Cursor row
$1E4Bf0 11j_1E4Bbeqb_1E5E; move cursor left (min col = 6) ; x-ref: $1E5B
$1E4Da5 49ldazp_p_tmp_lo
$1E4F18clc; Add 40 for each row
$1E5069 28adc#$28
$1E5285 49stazp_p_tmp_lo
$1E54a5 4aldazp_p_tmp_hi
$1E5669 00adc#$00
$1E5885 4astazp_p_tmp_hi
$1E5A88dey
$1E5B4c 4b 1ejmpj_1E4B
$1E5Ea9 02b_1E5Elda#$02; Red color ; x-ref: $1E4B
$1E60a0 00ldy#$00
$1E6291 49sta(zp_p_tmp_lo),y; Set letter color to red
$1E6460rts
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
; Highscore Move Cursor Up
;
; Inputs: active_row
; Outputs: active_row
; Side Effects: Decreases row by 2, capped at min row 5
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
$1E65ad 60 08highscore_move_upldaactive_row; x-ref: $1DEC
$1E68c9 05cmp#$05; Min row 5
$1E6Ad0 03bneb_1E6F
$1E6C4c 9c 1dj_1E6Cjmpdecrement_timer; x-ref: $1E75
$1E6Fce 60 08b_1E6Fdecactive_row; Move up 2 cells ; x-ref: $1E6A
$1E72ce 60 08decactive_row
$1E754c 6c 1ejmpj_1E6C
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
; Highscore Move Cursor Down
;
; Inputs: active_row
; Outputs: active_row
; Side Effects: Increases row by 2, capped at max row 9
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
$1E78ad 60 08highscore_move_downldaactive_row; x-ref: $1DEF
$1E7Bc9 09cmp#$09; Max row 9
$1E7Dd0 03bneb_1E82
$1E7F4c 9c 1dj_1E7Fjmpdecrement_timer; x-ref: $1E88
$1E82ee 60 08b_1E82incactive_row; Move down 2 cells ; x-ref: $1E7D
$1E85ee 60 08incactive_row
$1E884c 7f 1ejmpj_1E7F
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
; Highscore Move Cursor Left
;
; Inputs: active_col
; Outputs: active_col
; Side Effects: Decreases column by 3, capped at min col 6
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
$1E8Bad 61 08highscore_move_leftldaactive_col; x-ref: $1DF2
$1E8Ec9 06cmp#$06; Min col 6
$1E90d0 03bneb_1E95
$1E924c 9c 1dj_1E92jmpdecrement_timer; x-ref: $1E9E
$1E95ce 61 08b_1E95decactive_col; Move left 3 cells ; x-ref: $1E90
$1E98ce 61 08decactive_col
$1E9Bce 61 08decactive_col
$1E9E4c 92 1ejmpj_1E92
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
; Highscore Move Cursor Right
;
; Inputs: active_col
; Outputs: active_col
; Side Effects: Increases column by 3, capped at max col 33 ($21)
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
$1EA1ad 61 08highscore_move_rightldaactive_col; x-ref: $1DF5
$1EA4c9 21cmp#$21; Max col $21 (33)
$1EA6d0 03bneb_1EAB
$1EA84c 9c 1dj_1EA8jmpdecrement_timer; x-ref: $1EB4
$1EABee 61 08b_1EABincactive_col; Move right 3 cells ; x-ref: $1EA6
$1EAEee 61 08incactive_col
$1EB1ee 61 08incactive_col
$1EB44c a8 1ejmpj_1EA8
; --- Set Color RAM at (active_row, active_col) to yellow ---
highlight_cursor_cell
$1EB7a9 d8lda#$d8; $D8 = high byte of Color RAM ($D800) ; x-ref: $1D76
$1EB985 4astazp_p_tmp_hi
$1EBBad 61 08ldaactive_col
$1EBE85 49stazp_p_tmp_lo
$1EC0ac 60 08ldyactive_row
$1EC3f0 11j_1EC3beqb_1ED6; x-ref: $1ED3
$1EC5a5 49ldazp_p_tmp_lo
$1EC718clc
$1EC869 28adc#$28
$1ECA85 49stazp_p_tmp_lo
$1ECCa5 4aldazp_p_tmp_hi
$1ECE69 00adc#$00
$1ED085 4astazp_p_tmp_hi
$1ED288dey
$1ED34c c3 1ejmpj_1EC3
$1ED6a9 07b_1ED6lda#$07; yellow ; x-ref: $1EC3
$1ED8a0 00ldy#$00
$1EDA91 49sta(zp_p_tmp_lo),y
$1EDC60rts
$1EDD4c 59 46j_1EDDjmpj_4659; x-ref: $4656
; dead code
$1EE0.byte$00, $d0, $06, $a5, $4a, $c9, $00, $00
$1EE8.byte$fe, $a5, $49, $c9, $00, $d0, $06, $a5
$1EF0.byte$4a, $c9, $00, $00, $fe
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
; Handle Name Letter Selection
;
; Inputs: X (letter index 0-2), name_entry_substate (rank), p_tmp (points to Color RAM cell)
; Outputs: Screen RAM, Highscore Buffer
; Side Effects: Converts color RAM pointer to screen RAM pointer, reads the selected character, and saves it to the respective rank's highscore name buffer and display location.
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
handle_name_letter_selection
$1EF5e0 03cpx#$03; Check if 3 letters entered ; x-ref: $4675
$1EF7d0 03bneb_1EFC
$1EF94c c7 46jmpterminate_name_entry
$1EFCad 57 08b_1EFCldaname_entry_substate; Load player rank (1-5) ; x-ref: $1EF7
$1EFFc9 01cmp#$01; Rank 1?
$1F01d0 1bbneb_1F1E
$1F03a5 4aldazp_p_tmp_hi
$1F0538sec
$1F06e9 d4sbc#$d4; Subtract $D4 to point to Screen RAM ($0400 page)
$1F0885 4astazp_p_tmp_hi
$1F0Aa0 00ldy#$00
$1F0Cb1 49lda(zp_p_tmp_lo),y; Read selected char from Screen RAM
$1F0E9d 30 74staf_7430,x; Store in Rank 1 name buffer
$1F119d 18 06staSCREEN_RAM_R13C16,x; Write to screen display
$1F14a5 4aldazp_p_tmp_hi
$1F1618clc
$1F1769 d4adc#$d4; Restore pointer to Color RAM
$1F1985 4astazp_p_tmp_hi
$1F1B4c 96 1fjmpj_1F96
$1F1Ec9 02b_1F1Ecmp#$02; x-ref: $1F01
$1F20d0 1bbneb_1F3D
$1F22a5 4aldazp_p_tmp_hi
$1F2438sec
$1F25e9 d4sbc#$d4
$1F2785 4astazp_p_tmp_hi
$1F29a0 00ldy#$00
$1F2Bb1 49lda(zp_p_tmp_lo),y
$1F2D9d 38 74staf_7438,x
$1F309d 68 06staSCREEN_RAM_R15C16,x
$1F33a5 4aldazp_p_tmp_hi
$1F3518clc
$1F3669 d4adc#$d4
$1F3885 4astazp_p_tmp_hi
$1F3A4c 96 1fjmpj_1F96
$1F3Dc9 03b_1F3Dcmp#$03; x-ref: $1F20
$1F3Fd0 1bbneb_1F5C
$1F41a5 4aldazp_p_tmp_hi
$1F4338sec
$1F44e9 d4sbc#$d4
$1F4685 4astazp_p_tmp_hi
$1F48a0 00ldy#$00
$1F4Ab1 49lda(zp_p_tmp_lo),y
$1F4C9d 40 74staf_7440,x
$1F4F9d b8 06staSCREEN_RAM_R17C16,x
$1F52a5 4aldazp_p_tmp_hi
$1F5418clc
$1F5569 d4adc#$d4
$1F5785 4astazp_p_tmp_hi
$1F594c 96 1fjmpj_1F96
$1F5Cc9 04b_1F5Ccmp#$04; x-ref: $1F3F
$1F5Ed0 1bbneb_1F7B
$1F60a5 4aldazp_p_tmp_hi
$1F6238sec
$1F63e9 d4sbc#$d4
$1F6585 4astazp_p_tmp_hi
$1F67a0 00ldy#$00
$1F69b1 49lda(zp_p_tmp_lo),y
$1F6B9d 48 74staf_7448,x
$1F6E9d 08 07staSCREEN_RAM_R19C16,x
$1F71a5 4aldazp_p_tmp_hi
$1F7318clc
$1F7469 d4adc#$d4
$1F7685 4astazp_p_tmp_hi
$1F784c 96 1fjmpj_1F96
$1F7Ba5 4ab_1F7Bldazp_p_tmp_hi; x-ref: $1F5E
$1F7D38sec
$1F7Ee9 d4sbc#$d4
$1F8085 4astazp_p_tmp_hi
$1F82a0 00ldy#$00
$1F84b1 49lda(zp_p_tmp_lo),y
$1F869d 50 74staf_7450,x
$1F899d 58 07staSCREEN_RAM_R21C16,x
$1F8Ca5 4aldazp_p_tmp_hi
$1F8E18clc
$1F8F69 d4adc#$d4
$1F9185 4astazp_p_tmp_hi
$1F934c 96 1fjmpj_1F96
$1F96e8j_1F96inx; x-ref: $1F1B, $1F3A, $1F59, $1F78, $1F93
$1F974c 9c 1djmpdecrement_timer
; Dead code
$1F9A.byte$00, $88, $d0, $fd, $ca, $d0, $f8, $ce
$1FA2.byte$c0, $08, $d0, $f1, $60
; converts level_nr (0-based) to 2-digit screencodes for HUD
; level 0-8 → '01'-'09'; level 9-18 → '10'-'19'; level 19-28 → '20'-'28'; level 29+ → '30'+
write_level_nr_to_hud
$1FA7ad 00 08ldalevel_nr; x-ref: $16D4
$1FAAc9 1dcmp#$1d
$1FAC30 0cbmib_1FBA
$1FAE18clc
$1FAF69 13adc#$13
$1FB18d 1a 04staSCREEN_RAM_R0C26
$1FB4a9 33lda#$33
$1FB68d 19 04staSCREEN_RAM_R0C25
$1FB960rts
$1FBAc9 13b_1FBAcmp#$13; x-ref: $1FAC
$1FBC30 0cbmib_1FCA
$1FBE18clc
$1FBF69 1dadc#$1d
$1FC18d 1a 04staSCREEN_RAM_R0C26
$1FC4a9 32lda#$32
$1FC68d 19 04staSCREEN_RAM_R0C25
$1FC960rts
$1FCAc9 09b_1FCAcmp#$09; x-ref: $1FBC
$1FCC30 0cbmib_1FDA
$1FCE18clc
$1FCF69 27adc#$27
$1FD18d 1a 04staSCREEN_RAM_R0C26
$1FD4a9 31lda#$31
$1FD68d 19 04staSCREEN_RAM_R0C25
$1FD960rts
$1FDA18b_1FDAclc; x-ref: $1FCC
$1FDB69 31adc#$31
$1FDD8d 1a 04staSCREEN_RAM_R0C26
$1FE0a9 30lda#$30
$1FE28d 19 04staSCREEN_RAM_R0C25
$1FE560rts
$1FE6.byte$e8, $4c, $9c, $1d, $14, $20, $13, $03
$1FEE.byte$0f, $12, $05, $13, $00, $00, $00, $00
$1FF6.byte$00
.encode
.enc"screen"
$1FF7txt_game_over.text"GAME OVER"; x-ref: $4612
.endencode
$2000.binary"c64_burnin_rubber_2000.html"
.encode
.enc"screen"
$2400f_2400.text"SC:0000000 HI:0000000 RO:00 CAR:00 LI:00"; x-ref: $1054
$2428f_2428.text" "; x-ref: $1B8B
$2450.text" ", $67, $69, $6b, $6d, $6f, $71, $73, $75, $77, $79, $73, $75, " ", $6f, $71, $6b, $6d, $67, $69, $67, $69, $7b, $7d, $6f, $71, " "
$2478.text" ", $68, $6a, $6c, $6e, $70, $72, $74, $76, $78, $7a, $74, $76, " ", $70, $72, $6c, $6e, $68, $6a, $68, $6a, $7c, $7e, $70, $72, " "
$24A0.text" "
$24C8.text" 500 PTS 300 PTS "
$24F0.text" "
$2500f_2500.text" "; x-ref: $105A
$2528.text" 500 PTS"
$2550.text" 200 PTS "
$2578.text" "
$25A0.text" 300 PTS"
$25C8.text" 200 PTS "
$25F0.text" "
$2600f_2600.text" "; x-ref: $1060
$2628.text" 300 PTS 200 "
$2650.text"PTS "
$2678.text" "
$26A0.text" 32 ROUNDS ARE AVAILABLE"
$26C8.text" "
$26F0f_26F0.text" TRY TO SEE MORE! "; x-ref: $1066
$2718.text" "
$2740.text" P USE JOYSTICK OR KEYS ""J"""
$2768.text" L # "
$2790.text" . "
$27B8.text" ", $7f, " COLOSOFTWARE 1983 "
$27E0.text" "
instructions_screen_1
$2800.text"SC:0000000 HI:0000000 RO:00 CAR:00 LI:00"; x-ref: $112F
$2828.text" "
$2850.text" ", $67, $69, $6b, $6d, $6f, $71, $73, $75, $77, $79, $73, $75, " ", $6f, $71, $6b, $6d, $67, $69, $67, $69, $7b, $7d, $6f, $71, " "
$2878.text" ", $68, $6a, $6c, $6e, $70, $72, $74, $76, $78, $7a, $74, $76, " ", $70, $72, $6c, $6e, $68, $6a, $68, $6a, $7c, $7e, $70, $72, " "
$28A0.text" "
$28C8.text" SCORING POINTS FOR "
$28F0.text" "
instructions_screen_2
$2900.text" .1 CRASH"; x-ref: $1135
$2928.text"ING CARS. "
$2950.text" .2 LANDI"
$2978.text"NG ON CARS. "
$29A0.text" .3 BONUS"
$29C8.text" POINTS AT THE END OF EA"
$29F0.text"CH ROUND. "
instructions_screen_3
$2A00.text" "; x-ref: $113B
$2A28.text" F7 TO CHANGE ROUND: RO ="
$2A50.text" "
$2A78.text" BONUS LIVE EVERY 70000 POI"
$2AA0.text"NTS "
$2AC8.text" PLAYER CAN JUMP ONLY WIT"
instructions_screen_4
$2AF0.text"H MORE THAN 100 MPH "; x-ref: $1141
$2B18.text" "
$2B40.text" PRESS FIRE BUTTON OR ""J"" TO "
$2B68.text"JUMP DURING THE GAME "
$2B90.text" "
$2BB8.text" F1 1 PLAYER F3 2 PLAYER"
$2BE0.text"S "
$2C00unused_monitor_cmd.text".T0400,07FF,2C00 "
enter_high_score_screen_1
$2C28.text" "; x-ref: $1B62
$2C50.text" A B C D E F G H I J "
$2C78.text" "
$2CA0.text" K L M N O P Q R S T "
$2CC8.text" "
$2CF0.text" U V W X"
enter_high_score_screen_2
$2D00.text" Y Z . RUB END "; x-ref: $1B68
$2D28.text" "
$2D50.text" "
$2D78.text" 1- "
$2DA0.text" "
$2DC8.text" 2- "
$2DF0.text" "
enter_high_score_screen_3
$2E00.text" "; x-ref: $1B6E
$2E28.text" 3- "
$2E50.text" "
enter_high_score_screen_4
$2E78.text" 4- "; x-ref: $1B74
$2EA0.text" "
$2EC8.text" 5- "
$2EF0.text" "
$2F18.text" "
$2F40.text" "
$2F68.text" "
$2F90.text" "
$2FB8.text" "
txt_you_arent_in_the_five_best_scores
$2FD0.text"YOU AREN""T IN THE FIVE BEST SCORESY Z "; x-ref: $1DFE
$2FF8.text"EST SC X"
.endencode
$3000.binary"c64_burnin_rubber_3000.html"
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
; Detects collisions between NPC cars (enemy slots 0..2 vs 1..3).
; If two active cars are within 16x16 pixels, calculates a bounce response,
; setting new directions, step counts, and lifetimes based on car types.
;
; Inputs: tbl_enemy_car_state, Sprite X/Y regs ($D002/$D003), f092C, tbl_sprite_step_count_0
; Outputs: tbl_enemy_sprite_direction, tbl_enemy_sprite_active, tbl_enemy_sprite_step_count, tbl_enemy_sprite_lifetime
; Side Effects: Calls $5230 and updates tbl_enemy_sprite_state if both cars were collision-inactive.
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
detect_npc_car_collision
$3980a0 00ldy#$00; Outer loop: Y = car index 0..2 (must be active, state=1) ; x-ref: $3AE4
$3982b9 28 09b_3982ldatbl_enemy_car_state,y; x-ref: $398C
$3985c9 01cmp#$01; car_state = 1 → this NPC is active (outer loop car)
$3987f0 06beqb_398F
$3989c8b_3989iny; Inner loop: X = next active car (Y+1..3), forming pairs (0,1)(0,2)(0,3)(1,2)(1,3)(2,3) ; x-ref: $3994
$398Ac0 03cpy#$03
$398Cd0 f4bneb_3982
$398E60rts
$398F98b_398Ftya; x-ref: $3987
$3990aatax
$3991e8b_3991inx; x-ref: $399B, $39CF, $39FC, $3AD1
$3992e0 04cpx#$04
$3994f0 f3beqb_3989
$3996bd 28 09ldatbl_enemy_car_state,x
$3999c9 01cmp#$01; car_state = 1 → candidate for collision pair (inner loop car)
$399Bd0 f4bneb_3991
$399D8atxa
$399E48pha
$399F0aasla; X slot → sprite register offset (slot*2); $D002+offset = sprite X pos reg
$39A0aatax
$39A198tya
$39A248pha
$39A30aasla; Y slot → sprite register offset (slot*2)
$39A4a8tay
$39A5b9 02 d0lda$d002,y; load sprite X pos of car Y; Sprite 1 X Pos
$39A8dd 02 d0cmp$d002,x; compare against sprite X pos of car X; Sprite 1 X Pos
$39AB90 0ebccb_39BB
$39AD38sec
$39AEfd 02 d0sbc$d002,x; Sprite 1 X Pos
$39B148pha
$39B2a9 01lda#$01
$39B48d d3 08stacollision_rel_x; collision_rel_x = 1: car Y is to the right of car X
$39B768pla
$39B84c c7 39jmpj_39C7
$39BBa9 00b_39BBlda#$00; x-ref: $39AB
$39BD8d d3 08stacollision_rel_x; collision_rel_x = 0: car Y is to the left of car X
$39C0bd 02 d0lda$d002,x; Sprite 1 X Pos
$39C338sec
$39C4f9 02 d0sbc$d002,y; Sprite 1 X Pos
$39C7c9 10j_39C7cmp#$10; horizontal gap ≥ 16px → cars not overlapping, skip pair ; x-ref: $39B8
$39C990 07bccb_39D2
$39CB68pla
$39CCa8tay
$39CD68pla
$39CEaatax
$39CF4c 91 39jmpb_3991
$39D2b9 03 d0b_39D2lda$d003,y; load sprite Y pos of car Y ; x-ref: $39C9 Sprite 1 Y Pos
$39D5dd 03 d0cmp$d003,x; compare against sprite Y pos of car X; Sprite 1 Y Pos
$39D890 0ebccb_39E8
$39DA38sec
$39DBfd 03 d0sbc$d003,x; Sprite 1 Y Pos
$39DE48pha
$39DFa9 01lda#$01
$39E18d d4 08stacollision_rel_y; collision_rel_y = 1: car Y is below car X
$39E468pla
$39E54c f4 39jmpj_39F4
$39E8a9 00b_39E8lda#$00; x-ref: $39D8
$39EA8d d4 08stacollision_rel_y; collision_rel_y = 0: car Y is above car X
$39EDbd 03 d0lda$d003,x; Sprite 1 Y Pos
$39F038sec
$39F1f9 03 d0sbc$d003,y; Sprite 1 Y Pos
$39F4c9 10j_39F4cmp#$10; vertical gap ≥ 16px → cars not overlapping, skip pair ; x-ref: $39E5
$39F690 07bccb_39FF
$39F868pla
$39F9a8tay
$39FA68pla
$39FBaatax
$39FC4c 91 39jmpb_3991
$39FF68b_39FFpla; x-ref: $39F6
$3A00a8tay
$3A0168pla
$3A02aatax
; Direction encoding: 1=up-left 2=up-right 3=down-left 4=down-right
$3A03ad d3 08ldacollision_rel_x
$3A06d0 1fbneb_3A27
$3A08ad d4 08ldacollision_rel_y
$3A0Bd0 0dbneb_3A1A
$3A0Da9 01lda#$01; rel_x=0, rel_y=0: Y bounces up-left (dir 1)
$3A0F99 10 09statbl_enemy_sprite_direction,y
$3A12a9 04lda#$04; rel_x=0, rel_y=0: X bounces down-right (dir 4)
$3A149d 10 09statbl_enemy_sprite_direction,x
$3A174c 43 3ajmpj_3A43
$3A1Aa9 03b_3A1Alda#$03; rel_x=0, rel_y=1: Y bounces down-left (dir 3) ; x-ref: $3A0B
$3A1C99 10 09statbl_enemy_sprite_direction,y
$3A1Fa9 02lda#$02; rel_x=0, rel_y=1: X bounces up-right (dir 2)
$3A219d 10 09statbl_enemy_sprite_direction,x
$3A244c 43 3ajmpj_3A43
$3A27ad d4 08b_3A27ldacollision_rel_y; x-ref: $3A06
$3A2Ad0 0dbneb_3A39
$3A2Ca9 02lda#$02; rel_x=1, rel_y=0: Y bounces up-right (dir 2)
$3A2E99 10 09statbl_enemy_sprite_direction,y
$3A31a9 03lda#$03; rel_x=1, rel_y=0: X bounces down-left (dir 3)
$3A339d 10 09statbl_enemy_sprite_direction,x
$3A364c 43 3ajmpj_3A43
$3A39a9 04b_3A39lda#$04; rel_x=1, rel_y=1: Y bounces down-right (dir 4) ; x-ref: $3A2A
$3A3B99 10 09statbl_enemy_sprite_direction,y
$3A3Ea9 01lda#$01; rel_x=1, rel_y=1: X bounces up-left (dir 1)
$3A409d 10 09statbl_enemy_sprite_direction,x
$3A43bd 24 09j_3A43ldatbl_enemy_sprite_active,x; Both debris sprites inactive: trigger full collision (activate + play crash SFX); JSR sets tbl_enemy_sprite_state[x]=1 and returns A=1 ; x-ref: $3A17, $3A24, $3A36
$3A46d0 10bneb_3A58
$3A48b9 24 09ldatbl_enemy_sprite_active,y; check if car Y debris sprite already active
$3A4Bd0 0bbneb_3A58
$3A4Da9 01lda#$01
$3A4F20 30 52jsrset_collision_state_and_play_sfx; both inactive: activate collision (A=1) + play SFX
$3A5299 0c 09statbl_enemy_sprite_state,y; store JSR return value (A=1) into car Y's sprite state
$3A554c 60 3ajmpj_3A60
$3A58a9 01b_3A58lda#$01; At least one already active: just re-arm both (no SFX replay) ; x-ref: $3A46, $3A4B
$3A5A9d 24 09statbl_enemy_sprite_active,x; at least one already active: mark both active (re-collision)
$3A5D99 24 09statbl_enemy_sprite_active,y; mark car Y active too
$3A608aj_3A60txa; x-ref: $3A55
$3A6148pha
$3A6298tya
$3A6348pha
$3A64bd 2c 09ldatbl_enemy_car_type,x; 2D index for car Y's step count: row=car_type_X, col=car_type_Y → index = type_X*8 + type_Y
$3A67aatax
$3A68b9 2c 09ldatbl_enemy_car_type,y
$3A6Ba8tay
$3A6C8atxa
$3A6D0aasla
$3A6E0aasla
$3A6F0aasla
$3A7085 49stazp_p_tmp_lo
$3A7298tya
$3A7318clc
$3A7465 49adczp_p_tmp_lo
$3A76aatax
$3A77bd 20 3fldatbl_npc_col_step_count,x; X = car_type_x*8 + car_type_y → step count for NPC y's debris sprite
$3A7A85 49stazp_p_tmp_lo
$3A7C68pla
$3A7Da8tay
$3A7E68pla
$3A7Faatax
$3A80a5 49ldazp_p_tmp_lo
$3A8299 14 09statbl_enemy_sprite_step_count,y
$3A858atxa
$3A8648pha
$3A8798tya
$3A8848pha
$3A89bd 2c 09ldatbl_enemy_car_type,x
$3A8Caatax
$3A8Db9 2c 09ldatbl_enemy_car_type,y
$3A90a8tay
$3A910aasla
$3A920aasla
$3A930aasla
$3A9485 49stazp_p_tmp_lo
$3A968atxa
$3A9718clc
$3A9865 49adczp_p_tmp_lo
$3A9Aa8tay
$3A9Bb9 20 3fldatbl_npc_col_step_count,y; Y = car_type_y*8 + car_type_x → step count for NPC x's debris sprite
$3A9E85 49stazp_p_tmp_lo
$3AA068pla
$3AA1a8tay
$3AA268pla
$3AA3aatax
$3AA4a5 49ldazp_p_tmp_lo
$3AA69d 14 09statbl_enemy_sprite_step_count,x
$3AA9bd 2c 09ldatbl_enemy_car_type,x
$3AACc9 02cmp#$02
$3AAEd0 08bneb_3AB8
$3AB0a9 03lda#$03
$3AB29d 20 09statbl_enemy_sprite_lifetime,x; truck (type 2): shorter lifetime ($03 frames)
$3AB54c bd 3ajmpj_3ABD
$3AB8a9 08b_3AB8lda#$08; x-ref: $3AAE
$3ABA9d 20 09statbl_enemy_sprite_lifetime,x; all other types: normal lifetime ($08 frames)
$3ABDb9 2c 09j_3ABDldatbl_enemy_car_type,y; continue scanning remaining pairs ; x-ref: $3AB5
$3AC0c9 02cmp#$02
$3AC2d0 08bneb_3ACC
$3AC4a9 03lda#$03
$3AC699 20 09statbl_enemy_sprite_lifetime,y
$3AC94c d1 3ajmpj_3AD1
$3ACCa9 08b_3ACClda#$08; x-ref: $3AC2
$3ACE99 20 09statbl_enemy_sprite_lifetime,y
$3AD14c 91 39j_3AD1jmpb_3991; x-ref: $3AC9
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
; A small wrapper routine called by the main loop.
; It manages spawning new enemy cars, and then handles player jump inputs.
;
; Inputs: None
; Outputs: None
; Side Effects: Can spawn entities and mutate player state.
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
process_entities_and_input
$3AD420 00 4ajsrspawn_enemy_cars; x-ref: $183B
$3AD720 00 1ajsrcheck_jump_input
$3ADA60rts
$3ADB.byte$00, $00, $00, $00, $00
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
; Calls detect_npc_car_collision with X and Y registers preserved.
; Used by callers that need X/Y intact after the NPC collision scan.
;
; Inputs: Same as detect_npc_car_collision
; Outputs: Same as detect_npc_car_collision
; Side Effects: X and Y restored on exit
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
detect_npc_car_collision_preserve_xy
$3AE08atxa; Wrapper: preserves X/Y across detect_npc_car_collision ; x-ref: $4CD6, $4FB3
$3AE148pha
$3AE298tya
$3AE348pha
$3AE420 80 39jsrdetect_npc_car_collision
$3AE768pla
$3AE8a8tay
$3AE968pla
$3AEAaatax
$3AEB60rts
$3AEC.byte$48, $0a, $a8, $60
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
; Calls update_enemy_cars then check_jump_input.
; Used as an alternate main-loop dispatch that skips spawning.
;
; Inputs: None
; Outputs: None
; Side Effects: Updates enemy car positions and reads player jump input
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
update_enemies_and_check_jump
$3AF020 00 4cjsrupdate_enemy_cars; Wrapper: preserves X/Y across update_enemy_cars + check_jump_input ; x-ref: $184A
$3AF320 00 1ajsrcheck_jump_input
$3AF660rts
$3AF7.fill9, $00
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
; Detects collision between the player (sprite 0) and any NPC car (slots 0..3).
; Exits early if a crash SFX is already playing on Voice 1.
;
; For each NPC slot with car_state == 1 (on-road/active), checks if its sprite
; is within 16 pixels of the player in both X and Y. On collision:
; - Records which quadrant the NPC occupies relative to the player:
; collision_rel_x: 0 = NPC left of player, 1 = NPC right
; collision_rel_y: 0 = NPC above player, 1 = NPC below
; - Sets sprite_direction[x] so the NPC bounces away from the player
; - Plays crash SFX on SID Voice 1 (noise, freq=$0112, A=1/D=8)
; - Computes sprite_lifetime = (npc_speed >> type_shift) + (player_speed >> type_shift) + 4
; - Computes a098B = (npc_speed >> type_shift) + (player_speed >> type_shift) + 1
; - Jumps (no RTS) to apply_collision_speed_score
;
; Inputs: sfx_voice_1_en, car_state[0..3], VIC-II regs $D000-$D009,
; f0900[0..3] (NPC speeds), a0804 (player speed),
; f092C[0..3] (car type index), f3F60/f3F68/f3F70 (type tables)
; Outputs: sprite_direction[x], sprite_active[x], sprite_lifetime[x],
; collision_rel_x, collision_rel_y, a0988, a098A, a098B
; Side Effects: Plays crash SFX on Voice 1; falls through to apply_collision_speed_score
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
detect_player_car_collision
$3B00ad 05 08ldaplayer_is_jumping; Skip if crash SFX already playing on Voice 1 ; x-ref: $1847
$3B03d0 0ebner_3B13
$3B05a2 00ldx#$00
$3B07bd 28 09b_3B07ldatbl_enemy_car_state,x; x-ref: $3B11
$3B0Ac9 01cmp#$01; Only check cars in state 1 (on-road/active)
$3B0Cf0 06beqb_3B14
$3B0Ee8j_3B0Einx; x-ref: $3B2A, $3B42, $3B5C, $3B71, $3E3F, $3E6E
$3B0Fe0 04cpx#$04; 4 NPC slots (0..3)
$3B11d0 f4bneb_3B07
$3B1360r_3B13rts; x-ref: $3B03
$3B148ab_3B14txa; x-ref: $3B0C
$3B1548pha
$3B160aasla
$3B17aatax
$3B18bd 02 d0lda$d002,x; X = slot * 2 (VIC-II sprite reg offset); Sprite 1 X Pos
$3B1Bcd 00 d0cmp$d000; Compare NPC X vs player X; Sprite 0 X Pos
$3B1E90 15bccb_3B35
$3B2038sec
$3B21ed 00 d0sbc$d000; Sprite 0 X Pos
$3B24c9 10cmp#$10; Proximity threshold: 16 pixels
$3B2690 05bccb_3B2D
$3B2868pla
$3B29aatax
$3B2A4c 0e 3bjmpj_3B0E
$3B2Da9 01b_3B2Dlda#$01; x-ref: $3B26
$3B2F8d d3 08stacollision_rel_x; NPC is right of player (collision_rel_x=1)
$3B324c 4a 3bjmpj_3B4A
$3B35ad 00 d0b_3B35lda$d000; x-ref: $3B1E Sprite 0 X Pos
$3B3838sec
$3B39fd 02 d0sbc$d002,x; Sprite 1 X Pos
$3B3Cc9 10cmp#$10
$3B3E90 05bccb_3B45
$3B4068pla
$3B41aatax
$3B424c 0e 3bjmpj_3B0E
$3B45a9 00b_3B45lda#$00; x-ref: $3B3E
$3B478d d3 08stacollision_rel_x; NPC is left of player (collision_rel_x=0)
$3B4Abd 03 d0j_3B4Alda$d003,x; Now check Y proximity ; x-ref: $3B32 Sprite 1 Y Pos
$3B4Dcd 01 d0cmp$d001; Sprite 0 Y Pos
$3B5090 12bccb_3B64
$3B5238sec
$3B53ed 01 d0sbc$d001; Sprite 0 Y Pos
$3B56c9 10cmp#$10; Proximity threshold: 16 pixels
$3B5890 05bccb_3B5F
$3B5A68pla
$3B5Baatax
$3B5C4c 0e 3bjmpj_3B0E
$3B5Fa9 01b_3B5Flda#$01; NPC below player — stores collision_rel_y=1, plays crash SFX ; x-ref: $3B58
$3B614c 76 3bjmpj_3B76
$3B64ad 01 d0b_3B64lda$d001; x-ref: $3B50 Sprite 0 Y Pos
$3B6738sec
$3B68fd 03 d0sbc$d003,x; Sprite 1 Y Pos
$3B6Bc9 10cmp#$10
$3B6D90 05bccb_3B74
$3B6F68pla
$3B70aatax
$3B714c 0e 3bjmpj_3B0E
$3B74a9 00b_3B74lda#$00; NPC above player — stores collision_rel_y=0, plays crash SFX ; x-ref: $3B6D
$3B7620 f4 3ej_3B76jsrset_col_y_dir_play_sfx; x-ref: $3B61
$3B7968pla
$3B7Aaatax
$3B7Bad d3 08ldacollision_rel_x; Branch on X side to pick bounce direction
$3B7Ed0 1fbneb_3B9F
$3B80ad d4 08ldacollision_rel_y
$3B83d0 0dbneb_3B92
$3B85a9 04lda#$04
$3B878d 88 09stacol_quadrant
$3B8Aa9 01lda#$01
$3B8C9d 10 09statbl_enemy_sprite_direction,x; NPC left+above → bounce up-left (dir 1)
$3B8F4c bb 3bjmpj_3BBB
$3B92a9 02b_3B92lda#$02; x-ref: $3B83
$3B948d 88 09stacol_quadrant
$3B97a9 03lda#$03
$3B999d 10 09statbl_enemy_sprite_direction,x; NPC left+below → bounce down-left (dir 3)
$3B9C4c bb 3bjmpj_3BBB
$3B9Fad d4 08b_3B9Fldacollision_rel_y; x-ref: $3B7E
$3BA2d0 0dbneb_3BB1
$3BA4a9 03lda#$03
$3BA68d 88 09stacol_quadrant
$3BA9a9 02lda#$02
$3BAB9d 10 09statbl_enemy_sprite_direction,x; NPC right+above → bounce up-right (dir 2)
$3BAE4c bb 3bjmpj_3BBB
$3BB1a9 01b_3BB1lda#$01; x-ref: $3BA2
$3BB38d 88 09stacol_quadrant
$3BB6a9 04lda#$04
$3BB89d 10 09statbl_enemy_sprite_direction,x; NPC right+below → bounce down-right (dir 4)
$3BBBa9 01j_3BBBlda#$01; x-ref: $3B8F, $3B9C, $3BAE
$3BBD9d 24 09statbl_enemy_sprite_active,x; Activate bounce slot
$3BC08d 8a 09stacol_active
$3BC3bd 2c 09ldatbl_enemy_car_type,x
$3BC6a8tay
$3BC7b9 68 3fldatbl_sprite_step_count_1,y
$3BCA9d 14 09statbl_enemy_sprite_step_count,x; Pixels moved per step (from car-type table)
$3BCDb9 60 3fldatbl_col_recoil_step_px,y; A = recoil pixels/step for this car type
$3BD08d 89 09stacol_step_px
$3BD3b9 70 3fldatbl_col_lifetime_shift,y; A = shift count: divides both speeds before adding to sprite lifetime
$3BD648pha
$3BD7a8tay
$3BD8bd 00 09ldaf_0900,x; lifetime = (npc_speed >> type_shift) + (player_speed >> type_shift) + 4
$3BDB4ab_3BDBlsra; x-ref: $3BDD
$3BDC88dey
$3BDDd0 fcbneb_3BDB
$3BDF85 49stazp_p_tmp_lo
$3BE168pla
$3BE2a8tay
$3BE3ad 04 08ldaplayer_speed
$3BE64ab_3BE6lsra; x-ref: $3BE8
$3BE788dey
$3BE8d0 fcbneb_3BE6
$3BEA18clc
$3BEB65 49adczp_p_tmp_lo
$3BED18clc
$3BEE69 04adc#$04
$3BF09d 20 09statbl_enemy_sprite_lifetime,x; Longer lifetime for faster collisions
$3BF3ac 78 3fldycol_frames_shift; Y = fixed shift for col_frames_left (NPC speed term)
$3BF6bd 00 09ldaf_0900,x; a098B = same formula + 1 (feeds into score)
$3BF94ab_3BF9lsra; x-ref: $3BFB
$3BFA88dey
$3BFBd0 fcbneb_3BF9
$3BFD85 49stazp_p_tmp_lo
$3BFFac 78 3fldycol_frames_shift; Y = fixed shift for col_frames_left (player speed term)
$3C02ad 04 08ldaplayer_speed
$3C054ab_3C05lsra; x-ref: $3C07
$3C0688dey
$3C07d0 fcbneb_3C05
$3C0918clc
$3C0A65 49adczp_p_tmp_lo
$3C0C18clc
$3C0D69 01adc#$01
$3C0F8d 8b 09stacol_frames_left
$3C124c 00 3ejmpapply_collision_speed_score; Update player speed and score based on collision
; Checks if a debris sprite's current pixel position is over a passable road tile.
; Converts sprite X/Y to tile col/row (origin $10/$32, cell=8px), walks Screen
; RAM ($0400, 40 cols/row) and reads the tile. Tiles $20/$65 = road (pass-through).
; Any other tile triggers the hit handler (b3C64): deactivates the debris sprite,
; flashes it white, sets the NPC to damaged state, awards score, spawns score popup.
; Inputs: X = VIC-II sprite reg offset (slot*2), Y = tile column (from caller)
; Stack: slot index (pushed by update_moving_sprites)
; Outputs: None — returns cleanly on road tile, or non-local exit via hit handler.
$3C158acheck_road_collisiontxa; x-ref: $3D2D, $3D5E, $3D7A, $3D96
$3C1648pha; save VIC-II sprite offset (slot*2) before clobbering X
$3C1798tya
$3C1848pha
$3C1920 c0 3cjsrcheck_sprite_offscreen
$3C1C38sec
$3C1De9 10sbc#$10; subtract playfield left edge ($10 = 16px)
$3C1F4alsra; tile col = (spriteX - $10) / 8 (3x LSR = divide by 8)
$3C204alsra
$3C214alsra
$3C22a8tay; Y = tile column
$3C23bd 03 d0lda$d003,x; subtract left playfield edge offset ($10=16px) before tile-column divide; Sprite 1 Y Pos
$3C2638sec; 3x LSR = divide by 8 (8px per tile cell)
$3C27e9 32sbc#$32; subtract playfield top edge ($32 = 50px)
$3C294alsra
$3C2A4alsra; tile_row = (spriteY - $32) / 8 ($32 = top playfield edge; 3x LSR = ÷8)
$3C2B4alsra
$3C2Caatax; X = tile row (used as row-advance loop counter)
$3C2Da9 00lda#<SCREEN_RAM; subtract top playfield edge ($32=50px)
$3C2F85 49stazp_p_tmp_lo
$3C31a9 04lda#>SCREEN_RAM
$3C3385 4astazp_p_tmp_hi
$3C35e0 00j_3C35cpx#$00; x-ref: $3C47
$3C37f0 11beqb_3C4A; walk p_tmp down tile_row rows (each screen row = 40=$28 bytes)
$3C39a5 49ldazp_p_tmp_lo
$3C3B18clc
$3C3C69 28adc#$28; advance one screen row (40 cols = $28 bytes)
$3C3E85 49stazp_p_tmp_lo
$3C40a5 4aldazp_p_tmp_hi
$3C4269 00adc#$00
$3C4485 4astazp_p_tmp_hi
$3C46cadex
$3C474c 35 3cjmpj_3C35
$3C4Ab1 49b_3C4Alda(zp_p_tmp_lo),y; read first tile under sprite; $20=space, $65=road marker — both passable ; x-ref: $3C37
$3C4Cc9 20cmp#$20; non-local exit: unwind own saved X/Y + JSR return addr (2 bytes) + caller's slot push
$3C4Ef0 04beqb_3C54
$3C50c9 65cmp#$65; discard saved X from check_road_collision's pha at $3C16
$3C52d0 10bneb_3C64
$3C54c8b_3C54iny; check right-adjacent tile: sprite straddles two 8px cells; both must be road ; x-ref: $3C4E
$3C55b1 49lda(zp_p_tmp_lo),y
$3C57c9 20cmp#$20
$3C59f0 04beqb_3C5F
$3C5Bc9 65cmp#$65
$3C5Dd0 05bneb_3C64
$3C5F68b_3C5Fpla; road clear: restore regs and return to movement step loop ; x-ref: $3C59
$3C60a8tay
$3C6168pla
$3C62aatax
$3C6360rts
$3C6468b_3C64pla; non-road hit: unwind stack — pop check_road_collision's saved Y ; x-ref: $3C52, $3C5D, $3CCA
$3C65a8tay
$3C6668pla; pop check_road_collision's saved X
$3C67aatax
$3C6868pla; sprite_active=0 (plain debris): clear state only, no SFX
$3C6968pla; pop JSR return address hi
$3C6A68pla; pop slot index pushed by update_moving_sprites
$3C6Baatax; X = debris sprite slot index (0-3)
$3C6Cbd 24 09ldatbl_enemy_sprite_active,x
$3C6Fd0 08bneb_3C79
$3C71a9 00lda#$00
$3C739d 0c 09statbl_enemy_sprite_state,x
$3C764c 0c 3djmpnext_sprite_slot
$3C79a9 00b_3C79lda#$00; sprite_active≠0: deactivate debris sprite (A=0) + play thud SFX ; x-ref: $3C6F
$3C7B20 fa 3ejsrdeactivate_debris_and_play_thud; deactivate debris sprite (A=0) + play thud SFX
$3C7Ea9 02lda#$02; set NPC car state to 2 (damaged)
$3C809d 28 09statbl_enemy_car_state,x
$3C83a9 01lda#$01
$3C859d 28 d0sta$d028,x; flash debris sprite white (colour 1); Sprite 1 Color
$3C88bd 2c 09ldatbl_enemy_car_type,x
$3C8Ba8tay
$3C8Cb9 18 3fldatbl_points_sprite_frame,y
$3C8F20 a0 47jsraward_collision_score_and_damage_sprite
$3C92a9 10lda#$10; NPC damage display timer = $10 frames
$3C949d 30 09statbl_npc_damage_timer,x
$3C97a0 00ldy#$00
$3C99b9 80 09b_3C99ldatbl_score_sprite_active,y; scan for a free score sprite slot (0-2) ; x-ref: $3CA1
$3C9Cf0 07beqb_3CA5
$3C9Ec8iny
$3C9Fc0 03cpy#$03
$3CA1d0 f6bneb_3C99
$3CA3a0 00ldy#$00; all 3 slots taken: wrap back to slot 0 (overwrite oldest)
$3CA5a9 e2b_3CA5lda#$e2; x-ref: $3C9C
$3CA720 cd 3cjsrspawn_score_sprite; spawn score popup at NPC's screen position
$3CAAa9 10lda#$10
$3CAC99 83 09staf_0983,y; score popup display duration = $10 frames
$3CAF4c 0c 3djmpnext_sprite_slot
$3CB2.byte$0c, $3d
$3CB4.fill12, $00
; Guards check_road_collision: if the debris sprite's X pos is $FF (off right
; edge), performs a non-local exit by discarding check_road_collision's saved
; X/Y from the stack and jumping directly to the collision hit handler (b3C64),
; bypassing the tile-lookup. On normal return, A = sprite X pos for tile calc.
check_sprite_offscreen
$3CC0bd 02 d0lda$d002,x; x-ref: $3C19 Sprite 1 X Pos
$3CC3c9 ffcmp#$ff; $FF = sprite scrolled off right edge of playfield
$3CC5f0 01beqb_3CC8
$3CC760rts
$3CC868b_3CC8pla; discard check_road_collision's saved X (non-local exit) ; x-ref: $3CC5
$3CC968pla; discard check_road_collision's saved Y
$3CCA4c 64 3cjmpb_3C64; skip remaining road check → go straight to hit handler
; Spawns a floating score sprite at the NPC car's current screen position.
; A = sprite frame (e.g. $E2 = points graphic), X = NPC slot (0-3),
; Y = score sprite slot (0-2, pre-scanned for a free slot by caller).
; Copies NPC VIC-II X/Y regs to score sprite regs (sprites 5-7).
$3CCD99 fd 07spawn_score_spritestasprite_ptr_5,y; store frame into score sprite pointer table ; x-ref: $3CA7
$3CD0a9 01lda#$01
$3CD299 80 09statbl_score_sprite_active,y; mark score sprite slot as active
$3CD598tya
$3CD648pha
$3CD70aasla; Y*2 → VIC-II offset for score sprites 5-7
$3CD8a8tay
$3CD98atxa
$3CDA48pha
$3CDB0aasla; X*2 → VIC-II offset for NPC sprites 1-4
$3CDCaatax
$3CDDbd 02 d0lda$d002,x; read NPC sprite X pos; Sprite 1 X Pos
$3CE099 0a d0sta$d00a,y; copy to score sprite X pos (sprites 5-7); Sprite 5 X Pos
$3CE3bd 03 d0lda$d003,x; read NPC sprite Y pos; Sprite 1 Y Pos
$3CE699 0b d0sta$d00b,y; copy to score sprite Y pos (sprites 5-7); Sprite 5 Y Pos
$3CE968pla
$3CEAaatax
$3CEB68pla
$3CECa8tay
$3CED60rts
$3CEE.byte$00, $00
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
; Resets the colors of the score overlay sprites (sprites 5-7) back to white.
; This is used to restore the normal color after a collision flash.
;
; Inputs: None
; Outputs: $d02c, $d02d, $d02e (Sprite 5-7 color registers)
; Side Effects: Changes sprite colors on screen
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
reset_score_sprite_colors
$3CF0a9 01lda#$01; reset score sprite overlay colours to white (colour 1) after collision flash ; x-ref: $1795
$3CF28d 2c d0sta$d02c; Sprite 5 Color
$3CF58d 2d d0sta$d02d; Sprite 6 Color
$3CF88d 2e d0sta$d02e; Sprite 7 Color
$3CFB60rts
$3CFC.byte$00, $00, $00, $00
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
; Moves up to 4 active sprites diagonally each frame (collision debris/sparks
; spawned when cars collide). For each active slot, reads direction and step
; count, then moves the sprite one pixel at a time in the given direction.
;
; Direction codes (sprite_direction):
; 1 → up-left (dec X, dec Y)
; 2 → up-right (inc X, dec Y)
; 3 → down-left (dec X, inc Y)
; 4 → down-right (inc X, inc Y) [default]
;
; Each pixel step calls check_road_collision; if the tile under the sprite is
; not a passable road tile ($20/$65), the collision handler fires: triggers
; hit animation (white sprite, new frame), then deactivates the slot.
; After all steps, decrements sprite_lifetime; reaching zero deactivates
; the slot (sprite_active and sprite_state both cleared).
;
; Inputs: sprite_active[0..3], sprite_state[0..3],
; sprite_direction[0..3], sprite_step_count[0..3],
; sprite_lifetime[0..3]; VIC-II sprite X/Y regs
; Outputs: VIC-II sprite X/Y regs ($D002-$D009)
; Side Effects: Deactivates slots on lifetime expiry or road collision;
; triggers hit animation on collision (color, shape change)
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
update_moving_sprites
$3D00a2 00ldx#$00; x-ref: $183E
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
; Main loop for updating moving NPC/debris sprites. Iterates over the 4 sprite slots,
; checking if they are active before dispatching to movement handlers.
;
; Inputs: X register (current slot index)
; Outputs: None
; Side Effects: Dispatches to direction handlers if active
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
$3D02bd 24 09moving_sprites_loopldatbl_enemy_sprite_active,x; Skip slot if both sprite_active and sprite_state are 0 (inactive) ; x-ref: $3D0F
$3D05d0 0bbnedispatch_direction; slot is active, handle movement
$3D07bd 0c 09ldatbl_enemy_sprite_state,x; Also skip if sprite_state is 0
$3D0Ad0 06bnedispatch_direction; state is non-zero, handle movement
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
; Advances to the next sprite slot and loops back if more slots remain (0..3).
;
; Inputs: X register (current slot index)
; Outputs: X register (next slot index)
; Side Effects: Loops back to moving_sprites_loop
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
$3D0Ce8next_sprite_slotinx; x-ref: $3C76, $3CAF, $3D44, $3D4F
$3D0De0 04cpx#$04; 4 sprite slots (0..3)
$3D0Fd0 f1bnemoving_sprites_loop
$3D1160rts
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
; Reads the direction code for the current sprite and dispatches to the
; appropriate diagonal movement routine.
;
; Inputs: X register (slot index), tbl_enemy_sprite_direction
; Outputs: None
; Side Effects: Branches to directional handlers
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
$3D12bd 10 09dispatch_directionldatbl_enemy_sprite_direction,x; fetch direction code (1-4) ; x-ref: $3D05, $3D0A
$3D15c9 01cmp#$01; Direction 1 = up-left
$3D17f0 39beqdir_up_left_entry; 1 = up-left
$3D19c9 02cmp#$02; Direction 2 = up-right
$3D1Bf0 51beqdir_up_right; 2 = up-right
$3D1Dc9 03cmp#$03
$3D1Ff0 69beqdir_down_left; 3 = down-left, 4 = down-right (default)
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
; Moves the sprite down-right by incrementing both X and Y coordinates.
;
; Inputs: X register (slot index), tbl_enemy_sprite_step_count
; Outputs: VIC-II sprite X/Y registers
; Side Effects: Updates sprite position, pushes slot index to stack, checks collision
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
$3D21bd 14 09dir_down_rightldatbl_enemy_sprite_step_count,x; fetch steps to move
$3D24a8tay; use Y as step counter
$3D258atxa; push slot index; asl = slot*2 for VIC-II reg offset
$3D2648pha; slot*2 = VIC-II offset ($D002+offset = sprite X reg)
$3D270aasla; X = slot_index * 2 (VIC-II sprite reg offset)
$3D28aatax; X = sprite offset for VIC-II registers
$3D29c0 00j_3D29cpy#$00; are we done moving? ; x-ref: $3D3A
$3D2Bf0 10beqmove_steps_done
$3D2D20 15 3cjsrcheck_road_collision; check if hit non-road tile
$3D30fe 02 d0inc$d002,x; Move sprite right (inc X); Sprite 1 X Pos
$3D33fe 03 d0inc$d003,x; Move sprite down (inc Y); Sprite 1 Y Pos
$3D36eanop; 3x NOP: timing padding (matches step-loop timing in other direction handlers)
$3D37eanop
$3D38eanop
$3D3988dey
$3D3A4c 29 3djmpj_3D29
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
; Completes the movement steps for a sprite, decrements its lifetime counter,
; and checks if it should be deactivated.
;
; Inputs: Stack (pushed slot index), tbl_enemy_sprite_lifetime
; Outputs: X register (slot index), tbl_enemy_sprite_lifetime
; Side Effects: Restores slot index, decrements lifetime, may jump to deactivate
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
$3D3D68move_steps_donepla; x-ref: $3D2B, $3D5C, $3D78, $3D94
$3D3Eaatax
$3D3Fde 20 09dectbl_enemy_sprite_lifetime,x; reduce lifetime
$3D42f0 03beqlifetime_expired_deactivate; Lifetime expired: deactivate slot
$3D444c 0c 3djmpnext_sprite_slot
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
; Deactivates a sprite when its lifetime runs out by clearing its active and
; state flags.
;
; Inputs: X register (slot index)
; Outputs: tbl_enemy_sprite_active, tbl_enemy_sprite_state
; Side Effects: Retires the sprite slot
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
lifetime_expired_deactivate
$3D47a9 00lda#$00; clear flags to retire sprite ; x-ref: $3D42
$3D499d 24 09statbl_enemy_sprite_active,x
$3D4C9d 0c 09statbl_enemy_sprite_state,x
$3D4F4c 0c 3djmpnext_sprite_slot
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
; Entry point for up-left movement. Fetches the step count and converts the
; slot index into a VIC-II register offset.
;
; Inputs: X register (slot index), tbl_enemy_sprite_step_count
; Outputs: Y register (step count), X register (VIC-II offset)
; Side Effects: Pushes slot index to stack
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
$3D52bd 14 09dir_up_left_entryldatbl_enemy_sprite_step_count,x; all steps done — restore slot index from stack, decrement lifetime ; x-ref: $3D17
$3D55a8tay
$3D568atxa
$3D5748pha
$3D580aasla
$3D59aatax
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
; Moves the sprite up-left by decrementing both X and Y coordinates.
;
; Inputs: X register (VIC-II offset), Y register (step count)
; Outputs: VIC-II sprite X/Y registers
; Side Effects: Updates sprite position, checks collision
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
$3D5Ac0 00dir_up_leftcpy#$00; dir 1: up-left — dec X, dec Y ; x-ref: $3D6B
$3D5Cf0 dfbeqmove_steps_done
$3D5E20 15 3cjsrcheck_road_collision
$3D61de 02 d0dec$d002,x; Move sprite left (dec X) — direction 1; Sprite 1 X Pos
$3D64de 03 d0dec$d003,x; Move sprite up (dec Y) — direction 1; Sprite 1 Y Pos
$3D67eanop
$3D68eanop
$3D69eanop
$3D6A88dey
$3D6B4c 5a 3djmpdir_up_left
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
; Moves the sprite up-right by incrementing the X coordinate and decrementing
; the Y coordinate.
;
; Inputs: X register (slot index), tbl_enemy_sprite_step_count
; Outputs: VIC-II sprite X/Y registers
; Side Effects: Updates sprite position, pushes slot index, checks collision
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
$3D6Ebd 14 09dir_up_rightldatbl_enemy_sprite_step_count,x; dir 2: up-right — inc X, dec Y ; x-ref: $3D1B
$3D71a8tay
$3D728atxa
$3D7348pha
$3D740aasla
$3D75aatax
$3D76c0 00j_3D76cpy#$00; x-ref: $3D87
$3D78f0 c3beqmove_steps_done
$3D7A20 15 3cjsrcheck_road_collision
$3D7Dfe 02 d0inc$d002,x; Move sprite right (inc X) — direction 2; Sprite 1 X Pos
$3D80de 03 d0dec$d003,x; Move sprite up (dec Y) — direction 2; Sprite 1 Y Pos
$3D83eanop
$3D84eanop
$3D85eanop
$3D8688dey
$3D874c 76 3djmpj_3D76
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
; Moves the sprite down-left by decrementing the X coordinate and incrementing
; the Y coordinate.
;
; Inputs: X register (slot index), tbl_enemy_sprite_step_count
; Outputs: VIC-II sprite X/Y registers
; Side Effects: Updates sprite position, pushes slot index, checks collision
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
$3D8Abd 14 09dir_down_leftldatbl_enemy_sprite_step_count,x; dir 3: down-left — dec X, inc Y ; x-ref: $3D1F
$3D8Da8tay
$3D8E8atxa
$3D8F48pha
$3D900aasla
$3D91aatax
$3D92c0 00j_3D92cpy#$00; x-ref: $3DA3
$3D94f0 a7beqmove_steps_done
$3D9620 15 3cjsrcheck_road_collision
$3D99de 02 d0dec$d002,x; Move sprite left (dec X) — direction 3; Sprite 1 X Pos
$3D9Cfe 03 d0inc$d003,x; Move sprite down (inc Y) — direction 3; Sprite 1 Y Pos
$3D9Feanop
$3DA0eanop
$3DA1eanop
$3DA288dey
$3DA34c 92 3djmpj_3D92
$3DA6.byte$00, $00
$3DA8.fill8, $00
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
; Per-frame player horizontal recoil. Called every frame from the main loop
; while a collision is active (col_active != 0). Slides the player sprite X
; by col_step_px pixels in the direction of the hit, for col_frames_left frames.
;
; col_quadrant 1 or 3 (NPC was LEFT of player):
; dec $D000 col_step_px times; calls apply_collision_recoil (Y nudge) each step
; col_quadrant 2 or 4 (NPC was RIGHT of player):
; inc $D000 col_step_px times; no Y nudge (3x NOP — possible bug)
;
; Decrements col_frames_left each call; when it reaches zero, clears col_active
; to end the effect.
;
; Inputs: col_active, col_quadrant, col_step_px, col_frames_left
; Outputs: $D000 (Sprite 0 X Pos)
; Side Effects: Calls apply_collision_recoil for left-side hits; clears
; col_active when col_frames_left expires
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
apply_player_x_recoil
$3DB0ad 8a 09ldacol_active; Skip if no collision in progress ; x-ref: $4ECD
$3DB3d0 01bneb_3DB6
$3DB560rts
$3DB6ad 88 09b_3DB6ldacol_quadrant; x-ref: $3DB3
$3DB9c9 01cmp#$01; Dirs 1 & 3 = NPC was to LEFT → push player left
$3DBBf0 21beqb_3DDE
$3DBDc9 03cmp#$03
$3DBFf0 1dbeqb_3DDE
$3DC1ac 89 09ldycol_step_px; Pixels to move this frame
$3DC4c0 00j_3DC4cpy#$00; x-ref: $3DCF
$3DC6f0 0abeqb_3DD2
$3DC8ee 00 d0inc$d000; Push player right (NPC was right of player); Sprite 0 X Pos
$3DCBeanop; NOPs where apply_collision_recoil call is missing (possible bug)
$3DCCeanop
$3DCDeanop
$3DCE88dey
$3DCF4c c4 3djmpj_3DC4
$3DD2ce 8b 09b_3DD2deccol_frames_left; Decrement frame counter ; x-ref: $3DC6
$3DD5f0 01beqb_3DD8; counter > 0: still running — return, come back next frame
$3DD760rts
$3DD8a9 00b_3DD8lda#$00; counter hit 0: recoil complete — deactivate ; x-ref: $3DD5
$3DDA8d 8a 09stacol_active; Collision effect complete — deactivate
$3DDD60rts
$3DDEac 89 09b_3DDEldycol_step_px; x-ref: $3DBB, $3DBF
$3DE1c0 00j_3DE1cpy#$00; x-ref: $3DEC
$3DE3f0 0abeqb_3DEF
$3DE5ce 00 d0dec$d000; Push player left (NPC was left of player); Sprite 0 X Pos
$3DE820 a0 3ejsrapply_collision_recoil; Y nudge toward collision (only applied for left-side hits)
$3DEB88dey
$3DEC4c e1 3djmpj_3DE1
$3DEFce 8b 09b_3DEFdeccol_frames_left; Decrement frame counter ; x-ref: $3DE3
$3DF2f0 01beqb_3DF5; counter > 0: still running — return, come back next frame
$3DF460rts
$3DF5a9 00b_3DF5lda#$00; counter hit 0: recoil complete — deactivate ; x-ref: $3DF2
$3DF78d 8a 09stacol_active; Collision effect complete — deactivate
$3DFA60rts
$3DFB.byte$00, $00, $00, $00, $00
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
; Applies speed and score adjustments upon bumping into a car.
; This block is jumped to from the collision detection loop. Based on the angle
; of impact ($0988) and the car type, it either slows the player down (subtracting
; speed and score penalties) or speeds the player up (adding speed and score bonuses).
;
; Inputs: $0988 (collision angle), X (enemy index), Y (amount modifier)
; Outputs: None
; Side Effects: Modifies player speed ($0804) and score digits ($08E0). Returns via JMP back to collision loop.
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
apply_collision_speed_score
$3E00bd 2c 09ldatbl_enemy_car_type,x; A = enemy car type (0=truck, 1=sedan...) ; x-ref: $3C12
$3E03a8tay; car type → index into repeat-count table
$3E04b9 79 3fldatbl_col_score_repeat,y; A = number of penalty/bonus cycles for this car type
$3E07a8tay; Y = repeat count (saved/restored around score loop)
$3E08ad 88 09ldacol_quadrant; load collision angle quadrant
$3E0Bc9 01cmp#$01; quadrant 1 = rear/side hit → bonus
$3E0Df0 33beqb_3E42
$3E0Fc9 02cmp#$02; quadrant 2 = rear/side hit → bonus
$3E11f0 2fbeqb_3E42
$3E13ad 04 08b_3E13ldaplayer_speed; --- PENALTY PATH: head-on collision --- ; x-ref: $3E3D
$3E16c9 14cmp#$14; already at minimum speed ($14)?
$3E18f0 25beqb_3E3F; yes → skip penalty, return to loop
$3E1A38sec
$3E1Be9 01sbc#$01; speed -= 1
$3E1D8d 04 08staplayer_speed; store reduced speed
$3E2098tya; index 2 = ones digit of the 3 low-order score digits (score_digits[0]=hundreds, [2]=ones)
$3E2148pha; preserve repeat counter on stack
$3E22a0 02ldy#$02; start digit loop at index 2 (ones digit)
$3E24b9 e0 08j_3E24ldascore_digits,y; penalty: subtract 1 from ones digit; propagate borrow upward through score_digits[0..2] ; x-ref: $3E37
$3E2738sec
$3E28e9 01sbc#$01; digit -= 1
$3E2A99 e0 08stascore_digits,y; store updated digit
$3E2Dc9 ffcmp#$ff; $FF = digit wrapped below 0 (borrow)
$3E2Fd0 09bneb_3E3A; no borrow → score loop done
$3E31a9 09lda#$09; digit borrowed: set to 9
$3E3399 e0 08stascore_digits,y
$3E3688dey; propagate borrow to next higher digit
$3E374c 24 3ejmpj_3E24
$3E3A68b_3E3Apla; restore repeat counter from stack ; x-ref: $3E2F
$3E3Ba8tay
$3E3C88dey; one penalty cycle done
$3E3Dd0 d4bneb_3E13; repeat for remaining cycles
$3E3F4c 0e 3bb_3E3Fjmpj_3B0E; tail call → back to collision detection loop ; x-ref: $3E18
$3E42ad 04 08b_3E42ldaplayer_speed; --- BONUS PATH: rear/side hit --- ; x-ref: $3E0D, $3E11, $3E6C
$3E45c9 dccmp#$dc; already at maximum speed ($DC)?
$3E47f0 25beqb_3E6E; yes → skip bonus, return to loop
$3E4918clc
$3E4A69 01adc#$01; speed += 1
$3E4C8d 04 08staplayer_speed; store increased speed
$3E4F98tya; save repeat counter before clobbering Y
$3E5048pha; preserve repeat counter on stack
$3E51a0 02ldy#$02; start digit loop at index 2 (ones digit)
$3E53b9 e0 08j_3E53ldascore_digits,y; bonus: add 1 to ones digit; propagate carry upward through score_digits[0..2] ; x-ref: $3E66
$3E5618clc
$3E5769 01adc#$01; digit += 1
$3E5999 e0 08stascore_digits,y; store updated digit
$3E5Cc9 0acmp#$0a; $0A = digit overflowed past 9 (carry)
$3E5Ed0 09bneb_3E69; no carry → score loop done
$3E60a9 00lda#$00; digit carried: reset to 0
$3E6299 e0 08stascore_digits,y
$3E6588dey; propagate carry to next higher digit
$3E664c 53 3ejmpj_3E53
$3E6968b_3E69pla; restore repeat counter from stack ; x-ref: $3E5E
$3E6Aa8tay
$3E6B88dey; one bonus cycle done
$3E6Cd0 d4bneb_3E42; repeat for remaining cycles
$3E6E4c 0e 3bb_3E6Ejmpj_3B0E; tail call → back to collision detection loop ; x-ref: $3E47
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
; Resets SID Voice 1 ADSR envelope to 0, effectively silencing the channel.
; Often called before setting up a new sound effect.
;
; Inputs: None
; Outputs: A = $00
; Side Effects: Modifies SID Voice 1 ADSR registers ($D405, $D406).
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
$3E71a9 00reset_voice1_statelda#$00; Clear A for ADSR reset ; x-ref: $3E7D, $3ED1, $3F81, $51BE
$3E7320 c0 12jsrsilence_voice1_or_bail_if_jumping; Clear gate bit (if not jumping)
$3E768d 05 d4sta$d405; Voice 1: Attack / Decay Cycle Control
$3E798d 06 d4sta$d406; Voice 1: Sustain / Release Cycle Control
$3E7C60rts
$3E7D20 71 3ej3E7Djsrreset_voice1_state; x-ref: $3ECE
$3E80a9 0flda#$0f
$3E828d 06 d4sta$d406; Voice 1: Sustain / Release Cycle Control
$3E85a9 6blda#$6b
$3E878d 05 d4sta$d405; Voice 1: Attack / Decay Cycle Control
$3E8Aa9 1elda#$1e
$3E8C8d 01 d4sta$d401; Voice 1: Frequency Control - High-Byte
$3E8Fa9 8clda#$8c
$3E918d 00 d4sta$d400; Voice 1: Frequency Control - Low-Byte
$3E94a9 81lda#$81
$3E968d 04 d4sta$d404; Voice 1: Control Register
$3E9960rts
$3E9A.byte$00, $00, $00, $00, $00, $00
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
; Applies visual recoil to the player's car after a collision.
; Based on the collision angle ($0988), it shifts the player sprite (Sprite 0)
; either up or down on the screen to simulate a physical bump.
; It clamps the player's vertical position between $90 and $D0 to keep them
; within the visible gameplay area.
;
; Inputs: $0988 (collision angle)
; Outputs: None
; Side Effects: Modifies Sprite 0 Y Pos ($D001).
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
apply_collision_recoil
$3EA0ad 88 09ldacol_quadrant; x-ref: $3DE8
$3EA3c9 01cmp#$01
$3EA5f0 14beqb_3EBB
$3EA7c9 02cmp#$02
$3EA9f0 10beqb_3EBB
$3EABee 01 d0inc$d001; Sprite 0 Y Pos
$3EAEad 01 d0lda$d001; Sprite 0 Y Pos
$3EB1c9 d0cmp#$d0
$3EB390 05bccr_3EBA
$3EB5a9 d0lda#$d0
$3EB78d 01 d0sta$d001; Sprite 0 Y Pos
$3EBA60r_3EBArts; x-ref: $3EB3
$3EBBce 01 d0b_3EBBdec$d001; x-ref: $3EA5, $3EA9 Sprite 0 Y Pos
$3EBEad 01 d0lda$d001; Sprite 0 Y Pos
$3EC1c9 90cmp#$90
$3EC3b0 05bcsr_3ECA
$3EC5a9 90lda#$90
$3EC78d 01 d0sta$d001; Sprite 0 Y Pos
$3ECA60r_3ECArts; x-ref: $3EC3
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
; Sets the player's sprite frame pointer and plays a sound effect on Voice 1.
; Used for jump/explosion animations.
;
; Inputs: A = Sprite frame pointer value
; Outputs: None
; Side Effects: Updates sprite_ptr_0, configures SID Voice 1.
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
set_sprite0_frame_and_play_sfx
$3ECB8d f8 07stasprite_ptr_0; Update player sprite frame ; x-ref: $4826
$3ECE4c 7d 3ejmpj3E7D; Play SFX tone
; Plays crash SFX on SID Voice 1 (Noise, Freq=$0112, A=1/D=8)
$3ED120 71 3eplay_crash_sfxjsrreset_voice1_state; x-ref: $3EF7, $5233
$3ED4a9 00lda#$00
$3ED68d 06 d4sta$d406; Voice 1: Sustain / Release Cycle Control
$3ED9a9 18lda#$18
$3EDB8d 05 d4sta$d405; Voice 1: Attack / Decay Cycle Control
$3EDEa9 01lda#$01
$3EE08d 01 d4sta$d401; Voice 1: Frequency Control - High-Byte
$3EE3a9 12lda#$12
$3EE58d 00 d4sta$d400; Voice 1: Frequency Control - Low-Byte
$3EE8a9 81lda#$81
$3EEA8d 04 d4sta$d404; Voice 1: Control Register
$3EED60rts
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
; Updates the state of an enemy car and plays a thud sound effect.
;
; Inputs: X = Enemy index, A = New state value
; Outputs: None
; Side Effects: Modifies tbl_enemy_car_state,X and plays SFX.
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
set_enemy_state_and_play_thud
$3EEE9d 28 09statbl_enemy_car_state,x; Update enemy state ; x-ref: $45B9
$3EF14c 81 3fjmpplay_thud_sfx; Trigger thud sound
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
; Records the relative Y direction of a collision and plays a crash sound effect.
;
; Inputs: A = Relative Y collision direction
; Outputs: None
; Side Effects: Updates collision_rel_y and triggers crash SFX.
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
set_col_y_dir_play_sfx
$3EF48d d4 08stacollision_rel_y; Store collision Y direction ; x-ref: $3B76
$3EF74c d1 3ejmpplay_crash_sfx; Trigger crash sound
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
; Deactivates an enemy/debris sprite and plays a thud sound effect.
;
; Inputs: X = Sprite index, A = Active flag (usually 0)
; Outputs: None
; Side Effects: Updates tbl_enemy_sprite_active,X and triggers thud SFX.
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
deactivate_debris_and_play_thud
$3EFA9d 24 09statbl_enemy_sprite_active,x; Set sprite active flag ; x-ref: $3C7B
$3EFD4c 81 3fjmpplay_thud_sfx; Trigger thud sound
$3F00tbl_sprite_color.byte$01, $01, $04, $07, $0e, $0e, $05, $0d; x-ref: $4B19
$3F08.byte$66, $66, $44, $7c, $9c, $64, $64, $64
$3F10.byte$e5, $e5, $64, $fa, $dc, $e4, $e4, $e4
tbl_points_sprite_frame
$3F18.byte$e3, $e3, $e4, $e4, $e4, $e5, $e5, $e5; x-ref: $3C8C, $45C5, $47A4, $47DD
; Row = attacker type (0-7), Col = victim type (0-7); truck col (2) always gives lowest recoil (1 step)
tbl_npc_col_step_count
$3F20.byte$03, $03, $01, $03, $03, $04, $04, $05; x-ref: $3A77, $3A9B
$3F28.byte$03, $03, $01, $03, $03, $04, $04, $05
$3F30.byte$07, $07, $02, $07, $07, $08, $08, $09
$3F38.byte$03, $03, $01, $03, $03, $04, $04, $05
$3F40.byte$03, $03, $01, $03, $03, $04, $04, $05
$3F48.byte$02, $02, $01, $02, $02, $03, $03, $05
$3F50.byte$02, $02, $01, $02, $02, $03, $03, $05
$3F58.byte$01, $01, $01, $01, $01, $02, $02, $03
; Per-car-type collision recoil step size in pixels. Indexed by car type (0-7).
; Truck (idx 2) = 7px (hardest hit), Bus (idx 7) = 2px (softest bounce).
tbl_col_recoil_step_px
$3F60.byte$05, $05, $07, $05, $05, $04, $04, $02; x-ref: $3BCD
tbl_sprite_step_count_1
$3F68.byte$03, $03, $01, $03, $03, $04, $04, $04; x-ref: $3BC7
; Per-car-type right-shift count for collision debris sprite lifetime.
; Lifetime = (npc_speed >> shift) + (player_speed >> shift) + 4.
; Truck (idx 2) = 7 (speed barely contributes); Bus (idx 7) = 4.
tbl_col_lifetime_shift
$3F70.byte$05, $05, $07, $05, $05, $05, $05, $04; x-ref: $3BD3
; Fixed right-shift count (6) used to compute col_frames_left from NPC and player speeds.
; col_frames_left = (npc_speed >> 6) + (player_speed >> 6) + 1.
; Unlike tbl_col_lifetime_shift, this is not per-car-type — same value for all collisions.
$3F78col_frames_shift.byte$06; x-ref: $3BF3, $3BFF
; Per-car-type repeat count for the speed/score adjustment loop in apply_collision_speed_score.
; Each cycle adds or subtracts 1 from player_speed and one point from the score.
; Truck (idx 2) = 10 (most impact); Bus (idx 7) = 2 (least impact).
$3F79tbl_col_score_repeat.byte$06, $06, $0a, $06, $06, $04, $04, $02; x-ref: $3E04
; Plays a short thud SFX on SID Voice 1 (Noise, Freq=$0112, A=1/D=9).
; Slightly softer than play_crash_sfx (A=1/D=8). Used for minor bumps
; and NPC state transitions. Always preceded by reset_voice1_state.
$3F8120 71 3eplay_thud_sfxjsrreset_voice1_state; x-ref: $3EF1, $3EFD
$3F84a9 00lda#$00
$3F868d 06 d4sta$d406; Voice 1: Sustain / Release Cycle Control
$3F89a9 19lda#$19
$3F8B8d 05 d4sta$d405; Voice 1: Attack / Decay Cycle Control
$3F8Ea9 01lda#$01
$3F908d 01 d4sta$d401; Voice 1: Frequency Control - High-Byte
$3F93a9 12lda#$12
$3F958d 00 d4sta$d400; Voice 1: Frequency Control - Low-Byte
$3F98a9 81lda#$81
$3F9A8d 04 d4sta$d404; Voice 1: Control Register
$3F9D60rts
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
; Plays a click/beep UI sound effect using SID Voice 1.
;
; Inputs: None
; Outputs: None
; Side Effects: Modifies SID Voice 1 control, frequency, ADSR registers
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
$3F9Ea9 00play_click_sfxlda#$00; A = 0 to gate off voice ; x-ref: $3FBE, $3FC4
$3FA08d 04 d4sta$d404; Voice 1: Control Register
$3FA38d 05 d4sta$d405; Voice 1: Attack / Decay Cycle Control
$3FA68d 06 d4sta$d406; Voice 1: Sustain / Release Cycle Control
$3FA9a9 09lda#$09; Attack: 0, Decay: 9
$3FAB8d 05 d4sta$d405; Voice 1: Attack / Decay Cycle Control
$3FAEa9 44lda#$44; Freq high byte
$3FB08d 01 d4sta$d401; Voice 1: Frequency Control - High-Byte
$3FB3a9 95lda#$95; Freq low byte
$3FB58d 00 d4sta$d400; Voice 1: Frequency Control - Low-Byte
$3FB8a9 21lda#$21; Control: Triangle wave + Gate on
$3FBA8d 04 d4sta$d404; Voice 1: Control Register
$3FBD60rts
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
; Handles the fire button press on the high-score screen, playing a click sound and jumping to the hotspot handler.
;
; Inputs: None
; Outputs: None
; Side Effects: Plays SID Voice 1 sound, jumps to handle_screen_hotspots
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
highscore_fire_pressed
$3FBE20 9e 3fjsrplay_click_sfx; x-ref: $1DF8
$3FC14c 37 46jmphandle_screen_hotspots
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
; Plays a click sound effect and loads the player's remaining lives (ones digit).
;
; Inputs: None
; Outputs: A = ones digit of remaining lives
; Side Effects: Plays SID Voice 1 sound
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
sid_tick_sfx_and_get_ones
$3FC420 9e 3fjsrplay_click_sfx; x-ref: $4973
$3FC7ad 23 08ldalives_ones
$3FCA60rts
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
; Initializes menu variables and polls input for player selection or menu navigation.
;
; Inputs: key_scan (current input state)
; Outputs: p_tmp_hi, p_tmp_lo, level_nr_self_modifiying
; Side Effects: Jumps to player selection routines or menu handler
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
$3FCBa9 30title_screen_menulda#$30; Initialize temp pointer ; x-ref: $115C
$3FCD85 4astazp_p_tmp_hi
$3FCFa9 00lda#$00
$3FD18d 01 12stalevel_nr_self_modifiying; Reset starting level
$3FD4a9 31lda#$31
$3FD685 49stazp_p_tmp_lo
$3FD8a5 c5j_3FD8ldazp_key_scan; x-ref: $3FFD
$3FDAc9 dfcmp#$df; Check if '2' was pressed (key_scan)
$3FDCf0 0fbeqselect_2_players
$3FDEc9 efcmp#$ef; Check if '1' was pressed (key_scan)
$3FE0d0 18bneb_3FFA
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
; Configures the game for a single player and jumps to the main game start.
;
; Inputs: None
; Outputs: current_player_nr = 1, number_of_players = 1
; Side Effects: Transfers control to game initialization
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
$3FE2a9 01select_1_playerlda#$01
$3FE48d 01 0fstacurrent_player_nr
$3FE78d 00 0fstanumber_of_players
$3FEA4c 8e 11jmpj_118E
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
; Configures the game for two players and jumps to the main game start.
;
; Inputs: None
; Outputs: number_of_players = 2, current_player_nr = 1
; Side Effects: Transfers control to game initialization
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
$3FEDa9 02select_2_playerslda#$02; x-ref: $3FDC
$3FEF8d 00 0fstanumber_of_players
$3FF2a9 01lda#$01
$3FF48d 01 0fstacurrent_player_nr
$3FF74c 8e 11jmpj_118E
$3FFA20 00 53b_3FFAjsrhandle_menu_selection_input; x-ref: $3FE0
$3FFD4c d8 3fjmpj_3FD8
; tile map (?).
; Each level has $20 bytes, there are 32 levels: 1024 bytes in total
$4000level_tile_tbl.byte$01, $02, $02, $03, $03, $02, $06, $06; level 0 ; x-ref: $1309, $130D, $487B, $487F
$4008.byte$06, $06, $06, $07, $08, $02, $02, $03
$4010.byte$03, $04, $05, $02, $02, $03, $03, $04
$4018.byte$05, $02, $02, $03, $02, $06, $07, $08
$4020.byte$02, $02, $03, $03, $03, $04, $05, $03; level 1
$4028.byte$03, $02, $02, $02, $03, $03, $04, $09
$4030.byte$09, $05, $03, $02, $02, $07, $08, $01
$4038.byte$01, $02, $02, $03, $03, $03, $04, $05
$4040.byte$02, $03, $03, $03, $04, $09, $05, $03; level 2
$4048.byte$03, $03, $02, $02, $06, $06, $06, $02
$4050.byte$02, $03, $03, $04, $05, $03, $02, $02
$4058.byte$06, $07, $08, $06, $02, $03, $04, $05
$4060.byte$01, $02, $02, $03, $03, $03, $02, $0a; level 3
$4068.byte$0c, $04, $05, $03, $02, $02, $02, $03
$4070.byte$02, $0a, $0c, $04, $05, $03, $03, $02
$4078.byte$03, $02, $02, $07, $0e, $08, $07, $08
$4080.byte$01, $02, $02, $03, $03, $04, $09, $09; level 4
$4088.byte$09, $05, $01, $01, $02, $0a, $0c, $02
$4090.byte$02, $0d, $0c, $04, $05, $01, $01, $02
$4098.byte$02, $03, $03, $07, $0e, $08, $07, $08
$40A0.byte$02, $02, $07, $08, $07, $08, $02, $02; level 5
$40A8.byte$03, $03, $03, $04, $09, $05, $03, $03
$40B0.byte$02, $02, $07, $08, $0c, $03, $03, $04
$40B8.byte$05, $03, $07, $08, $02, $03, $03, $02
$40C0.byte$02, $02, $02, $07, $0e, $08, $07, $08; level 6
$40C8.byte$02, $02, $03, $03, $04, $09, $09, $05
$40D0.byte$03, $0d, $0c, $0d, $0c, $02, $02, $07
$40D8.byte$08, $07, $08, $02, $02, $03, $04, $05
$40E0.byte$02, $02, $02, $07, $0e, $0e, $08, $07; level 7
$40E8.byte$08, $02, $02, $03, $03, $0d, $0c, $04
$40F0.byte$05, $0c, $02, $02, $03, $03, $03, $02
$40F8.byte$07, $08, $02, $06, $06, $06, $01, $01
$4100.byte$02, $02, $02, $07, $0e, $08, $07, $0e; level 8
$4108.byte$08, $07, $08, $02, $03, $03, $02, $02
$4110.byte$03, $03, $04, $05, $01, $07, $08, $06
$4118.byte$06, $06, $06, $02, $02, $02, $03, $03
$4120.byte$02, $02, $03, $03, $03, $02, $02, $0d; level 9
$4128.byte$0f, $0f, $0c, $07, $08, $02, $02, $02
$4130.byte$0d, $0f, $0f, $0c, $03, $04, $05, $03
$4138.byte$03, $03, $07, $0e, $08, $07, $0e, $08
$4140.byte$02, $02, $03, $03, $04, $09, $09, $09; level 10
$4148.byte$05, $01, $01, $07, $08, $07, $0e, $08
$4150.byte$07, $08, $02, $02, $03, $03, $02, $02
$4158.byte$06, $06, $06, $02, $03, $03, $04, $05
$4160.byte$02, $02, $02, $0d, $0f, $0f, $0f, $0c; level 11
$4168.byte$07, $0e, $08, $07, $08, $0d, $0f, $0c
$4170.byte$0d, $0f, $0c, $02, $02, $03, $03, $04
$4178.byte$09, $09, $05, $03, $03, $04, $09, $05
$4180.byte$02, $02, $02, $10, $07, $08, $07, $08; level 12
$4188.byte$02, $02, $02, $10, $0d, $0f, $0c, $02
$4190.byte$02, $03, $03, $03, $02, $02, $06, $06
$4198.byte$06, $02, $03, $04, $05, $03, $04, $05
$41A0.byte$02, $02, $02, $03, $03, $10, $02, $10; level 13
$41A8.byte$07, $08, $07, $0e, $08, $03, $03, $04
$41B0.byte$09, $09, $05, $03, $03, $02, $02, $07
$41B8.byte$08, $02, $02, $07, $0e, $08, $07, $08
$41C0.byte$02, $02, $02, $03, $03, $02, $07, $0e; level 14
$41C8.byte$08, $07, $0e, $08, $07, $08, $02, $02
$41D0.byte$03, $03, $02, $10, $02, $10, $02, $10
$41D8.byte$02, $02, $02, $03, $03, $02, $02, $01
$41E0.byte$01, $02, $02, $03, $03, $04, $05, $03; level 15
$41E8.byte$04, $09, $05, $02, $02, $06, $06, $06
$41F0.byte$07, $08, $07, $0e, $08, $02, $0d, $0f
$41F8.byte$0c, $10, $02, $10, $0a, $0c, $02, $02
$4200.byte$02, $02, $02, $02, $02, $07, $0e, $08; level 16
$4208.byte$07, $0e, $08, $07, $08, $02, $03, $03
$4210.byte$04, $09, $05, $0f, $0c, $10, $07, $08
$4218.byte$07, $08, $02, $10, $02, $10, $02, $10
$4220.byte$02, $02, $02, $0b, $02, $0b, $02, $0b; level 17
$4228.byte$02, $02, $0d, $0f, $0c, $02, $10, $07
$4230.byte$08, $07, $0e, $08, $07, $08, $07, $08
$4238.byte$02, $02, $03, $04, $05, $02, $02, $02
$4240.byte$02, $0a, $0c, $0a, $0f, $0c, $02, $02; level 18
$4248.byte$03, $04, $05, $03, $03, $03, $02, $0b
$4250.byte$02, $0b, $02, $10, $06, $06, $07, $0e
$4258.byte$08, $07, $0e, $08, $02, $07, $0e, $08
$4260.byte$02, $02, $03, $03, $02, $07, $0e, $08; level 19
$4268.byte$0d, $0f, $0f, $0c, $02, $0b, $02, $10
$4270.byte$02, $0b, $02, $10, $02, $02, $03, $03
$4278.byte$04, $09, $05, $02, $07, $08, $07, $08
$4280.byte$01, $01, $02, $02, $0d, $0f, $0f, $0c; level 20
$4288.byte$02, $10, $07, $05, $02, $02, $10, $0d
$4290.byte$0f, $0f, $0c, $07, $0e, $08, $07, $0e
$4298.byte$08, $02, $02, $03, $03, $03, $07, $05
$42A0.byte$02, $02, $02, $03, $03, $02, $02, $0d; level 21
$42A8.byte$0f, $0c, $07, $08, $07, $08, $07, $0e
$42B0.byte$0e, $08, $0d, $0f, $0f, $0c, $02, $0b
$42B8.byte$02, $10, $02, $0b, $02, $10, $07, $08
$42C0.byte$03, $03, $03, $04, $09, $09, $05, $02; level 22
$42C8.byte$02, $0b, $02, $10, $0b, $07, $08, $07
$42D0.byte$0e, $08, $07, $0e, $08, $03, $03, $04
$42D8.byte$05, $03, $02, $02, $02, $01, $01, $01
$42E0.byte$02, $02, $03, $03, $03, $02, $0d, $0c; level 23
$42E8.byte$0d, $0f, $0f, $0c, $02, $02, $07, $08
$42F0.byte$07, $08, $02, $03, $04, $05, $02, $03
$42F8.byte$03, $02, $02, $07, $0e, $08, $07, $08
$4300.byte$02, $02, $03, $03, $02, $02, $07, $0e; level 24
$4308.byte$08, $07, $0e, $08, $07, $0e, $08, $02
$4310.byte$0b, $02, $0b, $02, $10, $02, $10, $07
$4318.byte$08, $07, $08, $02, $02, $03, $03, $02
$4320.byte$02, $02, $03, $04, $05, $0c, $02, $02; level 25
$4328.byte$03, $04, $05, $0c, $02, $02, $0b, $02
$4330.byte$10, $02, $0b, $07, $08, $07, $0e, $0e
$4338.byte$0e, $08, $02, $02, $03, $04, $05, $0c
$4340.byte$02, $02, $01, $01, $02, $02, $03, $03; level 26
$4348.byte$04, $05, $0c, $0d, $0f, $0f, $0f, $0c
$4350.byte$02, $02, $10, $02, $0b, $02, $10, $02
$4358.byte$0b, $02, $07, $0e, $0e, $08, $07, $08
$4360.byte$02, $02, $02, $07, $0e, $08, $07, $08; level 27
$4368.byte$07, $0e, $08, $07, $0e, $0e, $08, $02
$4370.byte$02, $02, $03, $04, $05, $0c, $0b, $02
$4378.byte$02, $02, $03, $03, $01, $01, $02, $02
$4380.byte$02, $0d, $0c, $04, $05, $02, $02, $02; level 28
$4388.byte$0d, $0c, $04, $05, $02, $02, $02, $07
$4390.byte$08, $07, $08, $02, $02, $03, $03, $02
$4398.byte$0d, $0c, $04, $05, $02, $02, $07, $08
$43A0.byte$02, $02, $02, $07, $08, $06, $07, $0e; level 29
$43A8.byte$08, $06, $07, $08, $03, $03, $02, $02
$43B0.byte$0b, $02, $10, $07, $08, $07, $0e, $08
$43B8.byte$02, $02, $0b, $02, $10, $02, $10, $02
$43C0.byte$01, $02, $03, $04, $05, $0c, $0d, $0c; level 30
$43C8.byte$02, $0b, $02, $10, $02, $10, $07, $08
$43D0.byte$07, $0e, $08, $07, $0e, $08, $02, $02
$43D8.byte$01, $01, $02, $02, $03, $04, $05, $02
$43E0.byte$01, $02, $02, $03, $03, $04, $09, $05; level 31
$43E8.byte$02, $0d, $0f, $0c, $0a, $0c, $02, $06
$43F0.byte$06, $07, $08, $07, $0e, $08, $02, $0b
$43F8.byte$0d, $0f, $0c, $10, $02, $03, $04, $05
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
; Applies a buffered vertical offset to Sprite 0 (the player's car).
; Takes the accumulated vertical offset stored at $0808, adds it to the current
; Y position of Sprite 0 ($D001), and then clears $0808 back to 0. This is
; used to process collision bumps, road bumps, or other vertical shifts pending
; for the frame.
;
; Inputs: Y position at $D001, offset at $0808
; Outputs: None
; Side Effects: Modifies Sprite 0 Y pos ($D001) and sets $0808 to 0.
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
$4400ad 01 d0apply_y_offsetlda$d001; x-ref: $182A, $4768 Sprite 0 Y Pos
$440318clc
$44046d 08 08adcplayer_y_offset; Add offset buffered in $0808
$44078d 01 d0sta$d001; Sprite 0 Y Pos
$440Aa9 00lda#$00; Clear the buffered offset
$440C8d 08 08staplayer_y_offset
$440F60rts
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
; Handles player acceleration (Up direction) and deceleration (Down direction).
; Reads the parsed input state at $00F5. If 'Up' (Bit 0) is pressed, the car
; moves up the screen (Y position at $D001 decreases until clamped at $90),
; the scrolling speed $0804 is increased, and the 3-byte visual speedometer array
; at $08E0 is incremented in base-10.
; If 'Down' is pressed, it branches to $4464 which performs the inverse (speed
; array decrements, car moves down the screen until clamped at $D0).
;
; Inputs: Parsed input state at $00F5
; Outputs: None
; Side Effects: Modifies Sprite 0 Y pos ($D001), speed $0804, and speedometer $08E0
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
$4410ad f5 00handle_accelerationlda@w zp_joy_state; x-ref: $17D4, $4770
$441329 0fand#$0f; Check Bit 0 (Up/Forward)
$441529 01and#$01
$4417d0 47bneb_4460; Branch if not pressed to check Down
$4419ad 01 d0lda$d001; Sprite 0 Y Pos
$441Cc9 90cmp#$90
$441Ef0 09beqb_4429
$4420ad 01 d0lda$d001; Move Car UP 1 pixel; Sprite 0 Y Pos
$442338sec
$4424e9 01sbc#$01
$44268d 01 d0sta$d001; Sprite 0 Y Pos
$4429ee 04 08b_4429incplayer_speed; Increase scroll speed ($0804) x2 ; x-ref: $441E
$442Cee 04 08incplayer_speed
$442Fa0 00ldy#$00
$4431a2 02b_4431ldx#$02; x-ref: $444C
$4433bd e0 08j_4433ldascore_digits,x; Base-10 Increment Speedometer array ($08E0) ; x-ref: $4446
$443618clc
$443769 01adc#$01
$44399d e0 08stascore_digits,x
$443Cc9 0acmp#$0a
$443Ed0 09bneb_4449
$4440a9 00lda#$00
$44429d e0 08stascore_digits,x
$4445cadex
$44464c 33 44jmpj_4433
$4449c8b_4449iny; x-ref: $443E
$444Ac0 02cpy#$02
$444Cd0 e3bneb_4431
$444Ead 04 08ldaplayer_speed
$4451c9 decmp#$de
$4453d0 0abner_445F
$4455a9 dclda#$dc
$44578d 04 08staplayer_speed
$445Aa9 00lda#$00
$445C8d e2 08staspeed_hundreds_digit
$445F60r_445Frts; x-ref: $4453
$44604c ed 49b_4460jmpj_49ED; x-ref: $4417
$4463.byte$ea
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
; Handles player speed deceleration. Slows down the car if not accelerating,
; and applies faster deceleration if the fire button is pressed. Enforces a
; minimum integer speed of 4.
; Inputs: $DC00 (CIA 1 Port A) for joystick fire button state, is_jumping flag.
; Outputs: Updates speed_fraction and player_speed_int.
; Side Effects: None
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
$4464ad 01 d0handle_decelerationlda$d001; Read CIA 1 Port A (Joystick 2) ; x-ref: $49F4 Sprite 0 Y Pos
$4467c9 d0cmp#$d0; Check Fire button (bit 4)
$4469f0 09beqb_4474
$446Bad 01 d0lda$d001; Check if car is in mid-air; Sprite 0 Y Pos
$446E18clc
$446F69 01adc#$01
$44718d 01 d0sta$d001; Sprite 0 Y Pos
$4474ce 04 08b_4474decplayer_speed; x-ref: $4469
$4477ce 04 08decplayer_speed
$447Aa0 00ldy#$00
$447Ca2 02b_447Cldx#$02; x-ref: $4497
$447Ebd e0 08j_447Eldascore_digits,x; Enforce minimum speed of 4 ; x-ref: $4491
$448138sec
$4482e9 01sbc#$01
$44849d e0 08stascore_digits,x
$4487c9 ffcmp#$ff
$4489d0 09bneb_4494
$448Ba9 09lda#$09
$448D9d e0 08stascore_digits,x
$4490cadex
$44914c 7e 44jmpj_447E
$4494c8b_4494iny; x-ref: $4489
$4495c0 02cpy#$02
$4497d0 e3bneb_447C
$4499ad 04 08ldaplayer_speed
$449Cc9 12cmp#$12
$449Ed0 0fbner_44AF
$44A0a9 14lda#$14
$44A28d 04 08staplayer_speed
$44A5a9 00lda#$00
$44A78d e2 08staspeed_hundreds_digit
$44AAa9 02lda#$02
$44AC8d e1 08staspeed_tens_digit
$44AF60r_44AFrts; x-ref: $449E
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
; Initializes the game's HUD/Dashboard at the bottom of the screen.
; Draws the border graphics and prints the numeric values from $08E0.
;
; Inputs: $08E0..$08E2 (3-byte numeric value)
; Outputs: Screen RAM ($0772-$07CA), Color RAM ($DB72-$DBCA)
; Side Effects: Updates rows 22-24 of the screen display.
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
$44B0a2 00init_hudldx#$00; x-ref: $11F0
$44B2bd e0 08b_44B2ldascore_digits,x; Loop through 3 digits at $08E0 ; x-ref: $44C3
$44B518clc
$44B669 30adc#$30; Convert to PETSCII '0'-'9'
$44B89d 9b 07staSCREEN_RAM_R23C3,x; Store in Row 23, Column 3-5
$44BBa9 03lda#VicIIColors.CYAN
$44BD9d 9b dbstaCOLOR_RAM_R23C3,x
$44C0e8inx
$44C1e0 03cpx#$03
$44C3d0 edbneb_44B2
$44C5eanop
$44C6a9 24lda#$24
$44C88d 72 07staSCREEN_RAM_R22C2
$44CBa2 00ldx#$00
$44CDa9 25b_44CDlda#$25; Loop to draw 7 border chars ; x-ref: $44DA
$44CF9d 73 07staSCREEN_RAM_R22C3,x
$44D2a9 29lda#$29
$44D49d c3 07staSCREEN_RAM_R24C3,x
$44D7e8inx
$44D8e0 07cpx#$07
$44DAd0 f1bneb_44CD
$44DCa9 26lda#$26
$44DE8d 7a 07staSCREEN_RAM_R22C10
$44E1a9 27lda#$27
$44E38d a2 07staSCREEN_RAM_R23C10
$44E6a9 28lda#$28
$44E88d ca 07staSCREEN_RAM_R24C10
$44EBa9 2alda#$2a
$44ED8d c2 07staSCREEN_RAM_R24C2
$44F0a9 0dlda#$0d
$44F28d 9f 07staSCREEN_RAM_R23C7
$44F5a9 10lda#$10
$44F78d a0 07staSCREEN_RAM_R23C8
$44FAa9 08lda#$08
$44FC8d a1 07staSCREEN_RAM_R23C9
$44FFa2 00ldx#$00
$4501a9 07lda#VicIIColors.YELLOW; yellow
$45039d 72 dbb_4503staCOLOR_RAM_R22C2,x; x-ref: $450F
$45069d 9a dbstaCOLOR_RAM_R23C2,x
$45099d c2 dbstaCOLOR_RAM_R24C2,x
$450Ce8inx
$450De0 09cpx#$09
$450Fd0 f2bneb_4503
$4511a9 2blda#$2b
$451320 1d 45jsrclamp_player_speed_bounds
$451660rts
; dead code
$4517.byte$20, $b0, $44, $4c, $46, $63
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
; Adjusts the player's integer speed to ensure it stays within valid bounds.
; Ensures the minimum speed is 4. If the car is jumping, it applies specific
; speed limits to prevent excessive speed while airborne.
; Inputs: is_jumping flag, player_speed_int.
; Outputs: player_speed_int is clamped.
; Side Effects: None
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
clamp_player_speed_bounds
$451D8d 9a 07staSCREEN_RAM_R23C2; Check if car is jumping ; x-ref: $4513
$4520a9 20lda#$20
$45228d 9e 07staSCREEN_RAM_R23C6
$452560rts
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
; Updates the game state by decrementing the progress counter and checking for
; collisions between the player car (Sprite 0) and enemy cars (Sprites 1-4).
;
; 1. Decrements the 3-byte BCD counter at $08E0 by 20 units.
; 2. Checks for 16x16 pixel overlaps between Sprite 0 and Sprites 1-4.
; 3. If collision detected, sets car_state to 2 and calls handler s3EEE.
;
; Inputs: $08E0 (HUD counter), car_state (car status), VIC sprite registers
; Outputs: $08E0 (decremented), car_state (updated on collision)
; Side Effects: Calls collision handler s3EEE on impact.
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
update_tick_and_collisions
$45268atxa; x-ref: $4C38
$452748pha
$452898tya
$452948pha
$452Aa2 00ldx#$00
$452Cad 04 08ldaplayer_speed; Check against minimum speed 4
$452F38sec
$4530e9 14sbc#$14
$45328d 04 08staplayer_speed
$4535a0 02b_4535ldy#$02; x-ref: $4550
$4537b9 e0 08j_4537ldascore_digits,y; Decrement BCD counter 20 times ; x-ref: $454A
$453A38sec
$453Be9 01sbc#$01
$453D99 e0 08stascore_digits,y
$4540c9 ffcmp#$ff
$4542d0 09bneb_454D
$4544a9 09lda#$09
$454699 e0 08stascore_digits,y
$454988dey
$454A4c 37 45jmpj_4537
$454De8b_454Dinx; x-ref: $4542
$454Ee0 14cpx#$14
$4550d0 e3bneb_4535
$4552a2 00ldx#$00; Check if enemy car is active
$4554bd 28 09b_4554ldatbl_enemy_car_state,x; x-ref: $455E
$4557c9 01cmp#$01
$4559f0 0abeqb_4565
$455Be8j_455Binx; x-ref: $457E, $45A4, $45ED
$455Ce0 04cpx#$04
$455Ed0 f4bneb_4554
$456068pla
$4561a8tay
$456268pla
$4563aatax
$456460rts
$45658ab_4565txa; x-ref: $4559
$456648pha
$45670aasla
$4568aatax
$4569bd 02 d0lda$d002,x; X-coord collision check (16px); Sprite 1 X Pos
$456Ccd 00 d0cmp$d000; Sprite 0 X Pos
$456F90 10bccb_4581
$4571bd 02 d0lda$d002,x; Sprite 1 X Pos
$457438sec
$4575ed 00 d0sbc$d000; Sprite 0 X Pos
$4578c9 10cmp#$10
$457A90 13bccb_458F
$457C68j_457Cpla; x-ref: $458C
$457Daatax
$457E4c 5b 45jmpj_455B
$4581ad 00 d0b_4581lda$d000; x-ref: $456F Sprite 0 X Pos
$458438sec
$4585fd 02 d0sbc$d002,x; Sprite 1 X Pos
$4588c9 10cmp#$10
$458A90 03bccb_458F
$458C4c 7c 45jmpj_457C
$458Fbd 03 d0b_458Flda$d003,x; x-ref: $457A, $458A Sprite 1 Y Pos
$4592cd 01 d0cmp$d001; Sprite 0 Y Pos
$459590 10bccb_45A7
$4597bd 03 d0lda$d003,x; Sprite 1 Y Pos
$459A38sec
$459Bed 01 d0sbc$d001; Sprite 0 Y Pos
$459Ec9 10cmp#$10
$45A090 13bccb_45B5
$45A268j_45A2pla; x-ref: $45B2
$45A3aatax
$45A44c 5b 45jmpj_455B
$45A7ad 01 d0b_45A7lda$d001; x-ref: $4595 Sprite 0 Y Pos
$45AA38sec
$45ABfd 03 d0sbc$d003,x; Sprite 1 Y Pos
$45AEc9 10cmp#$10
$45B090 03bccb_45B5
$45B24c a2 45jmpj_45A2
$45B568b_45B5pla; x-ref: $45A0, $45B0
$45B6aatax
$45B7a9 02lda#$02; Collision! Set color/state to 2
$45B920 ee 3ejsrset_enemy_state_and_play_thud
$45BCa9 01lda#$01
$45BE9d 28 d0sta$d028,x; Sprite 1 Color
$45C1bd 2c 09ldatbl_enemy_car_type,x
$45C4a8tay
$45C5b9 18 3fldatbl_points_sprite_frame,y
$45C820 a0 47jsraward_collision_score_and_damage_sprite
$45CBa9 10lda#$10
$45CD9d 30 09statbl_npc_damage_timer,x
$45D0a0 00ldy#$00
$45D2b9 80 09b_45D2ldatbl_score_sprite_active,y; x-ref: $45DA
$45D5f0 07beqb_45DE
$45D7c8iny
$45D8c0 03cpy#$03
$45DAd0 f6bneb_45D2
$45DCa0 00ldy#$00
$45DEa9 e2b_45DElda#$e2; x-ref: $45D5
$45E099 fd 07stasprite_ptr_5,y
$45E3a9 01lda#$01
$45E599 80 09statbl_score_sprite_active,y
$45E8a9 10lda#$10
$45EA20 3d 4ejsrspawn_score_sprite_57
$45ED4c 5b 45jmpj_455B
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
; Adds 8 sub-pixels to the car's X fractional position. Handles the overflow
; into the integer X position and adjusts the screen X coordinate if a 256-pixel
; boundary is crossed.
; Inputs: car_x_fraction, car_x_int, car_screen_x
; Outputs: Updates car_x_fraction, car_x_int, and car_screen_x
; Side Effects: None
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
$45F0a9 07add_car_x_subpixelslda#$07; Add 8 sub-pixels to X fraction ; x-ref: $13B4
$45F28d 15 d0sta$d015; Sprite display Enable
$45F5a9 fflda#$ff
$45F78d 1c d0sta$d01c; Sprites Multi-Color Mode Select
$45FAae 03 08ldxseason_nr
$45FD60rts
$45FE.byte$00, $00
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
; Dynamic delay loop to govern the frame rate and scrolling speed.
; Subtracts the current speed value ($0804) from a base constant ($F3).
; The resulting value determines how many times a nested busy-wait loop executes.
; The faster the car is going (higher $0804 value), the smaller the delay count,
; resulting in the frame executing more quickly.
;
; Inputs: Speed variable at $0804
; Outputs: None
; Side Effects: Busy waits (delays CPU execution)
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
$4600a9 f3delay_frame_by_speedlda#$f3; Base delay count ; x-ref: $1835, $4773
$460238sec
$4603ed 04 08sbcplayer_speed; Adjust screen tile/block coordinate
$4606aatax
$4607a0 30b_4607ldy#$30; Outer loop count (X register) ; x-ref: $460D
$460988b_4609dey; Inner busy loop (Y register) ; x-ref: $460A
$460Ad0 fdbneb_4609
$460Ccadex
$460Dd0 f8bneb_4607
$460F60rts
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
; Displays the "GAME OVER" message centered on row 9 and pauses execution for
; approximately 2.6 seconds.
;
; Inputs: None
; Outputs: None
; Side Effects: Writes to Screen RAM ($0578) and Color RAM ($D978)
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
show_game_over_and_wait
$4610a2 00ldx#$00; x-ref: $1B5D
$4612bd f7 1fb_4612ldatxt_game_over,x; Read 'GAME OVER' character from $1FF7 ; x-ref: $4620
$46159d 78 05staSCREEN_RAM_R9C16,x; Write char to centered screen row 9
$4618a9 03lda#VicIIColors.CYAN; color cyan
$461A9d 78 d9staCOLOR_RAM_R9C16,x
$461De8inx
$461Ee0 09cpx#$09
$4620d0 f0bneb_4612
$4622a9 08lda#$08; Approx 8 * 256 * 256 iterations (~2.6s)
$46248d c0 08stagame_over_delay_ctr; Init outer loop count to 8 → 8 × 256 × 256 = ~524k iterations ≈ 2.6s delay
$4627a2 00b_4627ldx#$00; x-ref: $4634
$4629a0 00b_4629ldy#$00; x-ref: $462F
$462B88b_462Bdey; x-ref: $462C
$462Cd0 fdbneb_462B
$462Ecadex
$462Fd0 f8bneb_4629
$4631ce c0 08decgame_over_delay_ctr
$4634d0 f1bneb_4627
$463660rts
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
; Handles screen interactions by calculating Color RAM pointers and checking
; for specific coordinate hotspots (Row 9, Col $1B/$21) to trigger screen cleanup.
;
; Inputs: active_row ($0860), active_col ($0861), state_cleanup_index ($0857)
; Outputs: p_color_ram ($49/$4A), reset flags at $0858/$0859
; Side Effects: Modifies Screen RAM and internal buffers (erases elements)
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
handle_screen_hotspots
$4637a9 d8lda#>COLOR_RAM; x-ref: $3FC1
$463985 4astazp_p_tmp_hi
$463Bad 61 08ldaactive_col
$463E85 49stazp_p_tmp_lo
$4640ac 60 08ldyactive_row
$4643f0 11j_4643beqb_4656; x-ref: $4653
$4645a5 49ldazp_p_tmp_lo
$464718clc
$464869 28adc#$28
$464A85 49stazp_p_tmp_lo
$464Ca5 4aldazp_p_tmp_hi
$464E69 00adc#$00
$465085 4astazp_p_tmp_hi
$465288dey
$46534c 43 46jmpj_4643
$46564c dd 1eb_4656jmpj_1EDD; Jumps to a location that jumps to the next instruction ; x-ref: $4643
$4659ad 60 08j_4659ldaactive_row; x-ref: $1EDD
$465Cc9 09cmp#$09
$465Ed0 07bneb_4667
$4660ad 61 08ldaactive_col
$4663c9 1bcmp#$1b
$4665f0 11beqhighscore_backspace_handler
$4667ad 60 08b_4667ldaactive_row; x-ref: $465E
$466Ac9 09cmp#$09
$466Cd0 07bneb_4675
$466Ead 61 08ldaactive_col
$4671c9 21cmp#$21
$4673f0 52beqterminate_name_entry
$46754c f5 1eb_4675jmphandle_name_letter_selection; x-ref: $466C
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
; Handles the backspace action during the highscore name entry screen. Decrements
; the active character index and erases the previously entered letter from the
; highscore string buffer and the screen memory (including color RAM).
; Inputs: name_entry_substate (current character index 1-5).
; Outputs: Updates screen memory and name buffer with space character ($20).
; Side Effects: Decrements name entry timer.
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
highscore_backspace_handler
$4678ad 57 08ldaname_entry_substate; Check which letter index we are on ; x-ref: $4665
$467Bc9 01cmp#$01
$467Dd0 0cbneb_468B
$467F20 d4 46jsrname_entry_backspace; Decrement index and get space char
$46829d 30 74staf_7430,x; Erase from screen RAM buffer
$46859d 18 06staSCREEN_RAM_R13C16,x; Erase from color RAM buffer
$46884c 9c 1djmpdecrement_timer
$468Bc9 02b_468Bcmp#$02; x-ref: $467D
$468Dd0 0cbneb_469B
$468F20 d4 46jsrname_entry_backspace
$46929d 38 74staf_7438,x
$46959d 68 06staSCREEN_RAM_R15C16,x
$46984c 9c 1djmpdecrement_timer
$469Bc9 03b_469Bcmp#$03; x-ref: $468D
$469Dd0 0cbneb_46AB
$469F20 d4 46jsrname_entry_backspace
$46A29d 40 74staf_7440,x
$46A59d b8 06staSCREEN_RAM_R17C16,x
$46A84c 9c 1djmpdecrement_timer
$46ABc9 04b_46ABcmp#$04; x-ref: $469D
$46ADd0 0cbneb_46BB
$46AF20 d4 46jsrname_entry_backspace
$46B29d 48 74staf_7448,x
$46B59d 08 07staSCREEN_RAM_R19C16,x
$46B84c 9c 1djmpdecrement_timer
$46BB20 d4 46b_46BBjsrname_entry_backspace; x-ref: $46AD
$46BE9d 50 74staf_7450,x
$46C19d 58 07staSCREEN_RAM_R21C16,x
$46C44c 9c 1djmpdecrement_timer
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
; Terminates the highscore name entry process by forcing the countdown timer to
; zero, which triggers the auto-confirm path and transitions the game state.
; Inputs: None
; Outputs: Clears highscore_timer_tens and highscore_timer_ones to 0.
; Side Effects: Transitions game state.
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
$46C7a9 00terminate_name_entrylda#$00; Force tens digit to 0 ; x-ref: $1EF9, $4673
$46C98d 58 08stahighscore_timer_tens
$46CCa9 00lda#$00
$46CE8d 59 08stahighscore_timer_ones; Force ones digit to 0
$46D14c c8 1djmpb_1DC8; Jump to state transition logic
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
; Helper routine for name entry backspace. Decrements the character index (X reg)
; and clamps it at 0. Returns the space character ($20) in the accumulator.
; Inputs: X register (current character index).
; Outputs: X register decremented, A register = $20.
; Side Effects: None
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
$46D4caname_entry_backspacedex; Decrement index ; x-ref: $467F, $468F, $469F, $46AF, $46BB
$46D5e0 ffcpx#$ff; Check for underflow
$46D7d0 02bneb_46DB
$46D9a2 00ldx#$00; Clamp to 0
$46DBa9 20b_46DBlda#$20; Return space char ($20) ; x-ref: $46D7
$46DD60rts
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
; Checks if the current map tile the player has collided with is an obstacle.
; If it is an empty road ($20), the routine returns normally. If it is a specific
; pickup tile ($65), it processes the score update. Otherwise, it triggers a crash
; by aborting the current routine path and jumping to the collision handler.
; Inputs: A register (tile ID).
; Outputs: None
; Side Effects: May pop return address from stack and jump to crash handler.
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
check_tile_is_obstacle
$46DEc9 20cmp#$20; Check if tile is empty road ; x-ref: $1B38, $1B3F, $1B4A, $1B51
$46E0d0 01bneb_46E3
$46E260r_46E2rts; x-ref: $46EF
$46E3c9 65b_46E3cmp#$65; Check if tile is pickup/coin ; x-ref: $46E0
$46E5f0 41beqb_4728
$46E768pla; Pop return address (abort caller)
$46E868pla
$46E94c 55 1bjmpj_1B55; Jump to collision/crash handler
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
; Synchronizes the position of the player overlay sprite (Sprite 7) with the main
; player sprite (Sprite 0). Used when a pickup is collected to show points.
; Initializes the sprite color and sets the display duration timer.
; Inputs: pickup_mode_active flag, VIC-II Sprite 0 coordinates.
; Outputs: Updates VIC-II Sprite 7 coordinates, color, and sprite pointer.
; Side Effects: Activates pickup display state flags.
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
sync_player_overlay_sprite
$46ECad 5e 08ldapickup_mode_active; Check if already active ; x-ref: $4748
$46EFd0 f1bner_46E2
$46F1a9 ddlda#$dd; Set sprite pointer for Sprite 7
$46F38d ff 07stasprite_ptr_7
$46F6ad 00 d0lda$d000; Copy X pos from Sprite 0; Sprite 0 X Pos
$46F98d 0e d0sta$d00e; Sprite 7 X Pos
$46FCad 01 d0lda$d001; Copy Y pos from Sprite 0; Sprite 0 Y Pos
$46FF8d 0f d0sta$d00f; Sprite 7 Y Pos
$4702a9 01lda#$01; Set color to White
$47048d 2e d0sta$d02e; Sprite 7 Color
$4707a9 01lda#$01
$47098d 5e 08stapickup_mode_active
$470Ca9 20lda#$20
$470E8d 5f 08stapickup_display_timer; Set display timer duration
$471160rts
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
; Updates the temporary display timer for a pickup/coin sprite.
; When the player hits a specific map tile (e.g., $65), Sprite 7 is spawned as
; a visual indicator of the points gained, and state flag $085E is set.
; This routine runs each frame to tick down its lifespan timer at $085F.
; Once the timer hits 0, it deactivates the flag and hides Sprite 7 off-screen.
;
; Inputs: Pickup Active Flag at $085E, Timer at $085F
; Outputs: None
; Side Effects: Modifies $085E, $085F, and Sprite 7 X Pos ($D00E)
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
$4712ad 5e 08update_pickup_timerldapickup_mode_active; Check if pickup sprite is active ; x-ref: $1838, $4776
$4715d0 01bneb_4718
$471760r_4717rts; x-ref: $471B
$4718ce 5f 08b_4718decpickup_display_timer; Decrement duration timer ; x-ref: $4715
$471Bd0 fabner_4717
$471Da9 00lda#$00; Turn off active flag
$471F8d 5e 08stapickup_mode_active
$4722a9 00lda#$00; Hide Sprite 7 off-screen
$47248d 0e d0sta$d00e; Sprite 7 X Pos
$472760rts
$4728ad 5e 08b_4728ldapickup_mode_active; x-ref: $46E5
$472Bd0 1bbneb_4748
$472Da2 03ldx#$03
$472Fbd 25 08j_472Fldascore_7digits,x; x-ref: $4742
$473218clc
$473369 01adc#$01
$47359d 25 08stascore_7digits,x
$4738c9 0acmp#$0a
$473Ad0 09bneb_4745
$473Ca9 00lda#$00
$473E9d 25 08stascore_7digits,x
$4741cadex
$47424c 2f 47jmpj_472F
$474520 b0 16b_4745jsrupdate_hud_display; x-ref: $473A
$47484c ec 46b_4748jmpsync_player_overlay_sprite; x-ref: $472B
; -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
is_speed_above_100_else_return
$474Bad 04 08ldaplayer_speed; x-ref: $1A0D
$474Ec9 64cmp#100
$475030 01bmib_4753
$475260rts
$475368b_4753pla; x-ref: $4750
$475468pla
$475560rts
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
; Main gameplay tick routine.
; This is the core subroutine called every frame/tick during gameplay to process
; all major game systems. It updates the HUD, increments the score, handles player
; input and movement, processes jumps and background collisions, applies vertical
; offsets, handles acceleration (if enabled), manages frame delays, and ticks down
; the pickup/coin visual indicator.
;
; Inputs: None (relies on global state)
; Outputs: None
; Side Effects: Updates player coordinates, animations, score, HUD, and timers.
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
tick_gameplay_systems
$475620 b0 16jsrupdate_hud_display; x-ref: $13AA
$475920 c9 15jsrincrement_score
$475C20 a0 17jsrhandle_player_movement
$475F20 00 1ajsrcheck_jump_input
$476220 3a 1ajsrupdate_jump_animation
$476520 00 1bjsrcheck_background_collision
$476820 00 44jsrapply_y_offset
$476Bad 05 08ldaplayer_is_jumping
$476Ed0 03bneb_4773
$477020 10 44jsrhandle_acceleration
$477320 00 46b_4773jsrdelay_frame_by_speed; x-ref: $476E
$477620 12 47jsrupdate_pickup_timer
$477920 00 4cjsrupdate_enemy_cars
$477C20 55 4ejsrupdate_explosion_animations
$477F60rts
$4780.byte$00, $00, $60
$4783.fill29, $00
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
; award_collision_score_and_damage_sprite
;
; Called when the player's car lands on (or collides with) an NPC car.
; On entry, X = NPC slot index (0-3), Y = car type index from f092C,x.
;
; Phase 1 — Score award:
; Looks up the NPC's sprite frame byte from f3F18,y:
; $E3 (small car) => add 5 points to score array f0825
; $E4 (medium car) => add 3 points
; $E5 (large car) => add 2 points
; Score is stored as individual BCD-style digits at f0825 (7 bytes,
; index 4=ones ... index 0=highest). The loop ripple-carries from
; digit 4 upward for as many iterations as the point value (Y).
; Then calls update_hud_display to redraw the score on the HUD.
;
; Phase 2 — Sprite damage:
; After restoring X/Y, re-reads f3F18,y (same frame byte) and
; falls through to j4E03, which:
; - Stores the frame byte into a07F9,x (sprite pointer for NPC slot)
; - Builds a single-bit mask for slot X, inverts it, ANDs it into
; $D01C (Sprites Multi-Color Select), switching that NPC sprite
; from multicolor to hires mode (visual 'hit' state)
; - Increments a0821 (hit sub-counter); when it reaches 10,
; resets to 0 and increments hud_level_digit
;
; Inputs: X = NPC car slot index (0-3)
; Y = car type index (f092C,x), used to index f3F18
; Outputs: None (returns via j4E03/RTS at $4E3C)
; Side Effects: f0825 score digits updated; $D01C multicolor bit cleared
; for the hit NPC sprite; a0821 and hud_level_digit may
; increment; HUD redrawn via update_hud_display
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
award_collision_score_and_damage_sprite
$47A08atxa; Save X (NPC slot) and Y (car type index) — restored at $47D9 ; x-ref: $3C8F, $45C8
$47A148pha
$47A298tya
$47A348pha
$47A4b9 18 3fldatbl_points_sprite_frame,y
$47A7c9 e3cmp#$e3; $E3 = 500 pts
$47A9d0 05bneb_47B0
$47ABa0 05ldy#$05; 05 == 500 pts
$47AD4c bb 47jmpj_47BB
$47B0c9 e4b_47B0cmp#$e4; $E4 = 300 pts ; x-ref: $47A9
$47B2d0 05bneb_47B9
$47B4a0 03ldy#$03; 03 = 300 pts
$47B64c bb 47jmpj_47BB
$47B9a0 02b_47B9ldy#$02; Assume frame pointer is $E5, which is 200 pts ; x-ref: $47B2
$47BBa2 04j_47BBldx#$04; Start ripple-carry loop at digit index 4 (hundreds) ; x-ref: $47AD, $47B6, $47D4
$47BDbd 25 08j_47BDldascore_7digits,x; Load current score digit ; x-ref: $47D0
$47C018clc
$47C169 01adc#$01; Increment digit by 1
$47C39d 25 08stascore_7digits,x
$47C6c9 0acmp#$0a; Overflow at 10? (BCD-style carry)
$47C8d0 09bneb_47D3
$47CAa9 00lda#$00; Reset digit to 0, carry to next column
$47CC9d 25 08stascore_7digits,x
$47CFcadex; Move left to next score digit
$47D04c bd 47jmpj_47BD
$47D388b_47D3dey; Repeat for each point unit (Y times total) ; x-ref: $47C8
$47D4d0 e5bnej_47BB
$47D620 b0 16jsrupdate_hud_display; Redraw HUD score display after all digits updated
$47D968pla; Restore Y (car type index) and X (NPC slot)
$47DAa8tay
$47DB68pla
$47DCaatax
$47DDb9 18 3fldatbl_points_sprite_frame,y; Re-read sprite frame byte for this car type
$47E04c 03 4ejmpj_4E03; Fall into j4E03: store frame, clear D01C multicolor bit for this sprite slot
; dead code
$47E3.byte$a2, $00, $bd, $f8, $07, $29, $01, $f0
$47EB.byte$0e, $bd, $f8, $07, $29, $fe, $9d, $f8
$47F3.byte$07, $e8, $e0, $05, $d0, $ec, $60, $4c
$47FB.byte$95, $49, $00, $00, $00
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
; Handles the player's death sequence: decrements lives, plays an explosion
; animation based on the hazard, and jumps to either "Game Over" or scans
; backward through level map data (starting at $4000) for a valid respawn
; checkpoint.
;
; Inputs: lives_ones, lives_tens, (p_tmp_lo),Y (hazard type), level_nr, a0801
; Outputs: lives_ones, lives_tens, a0801 (respawn offset), p_tmp_lo/hi
; Side Effects: Modifies sprite_ptr_0 ($07F8), disables sprites ($D015 = 0)
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
$4800ce 23 08player_death_handlerdeclives_ones; x-ref: $1B55
$4803ad 23 08ldalives_ones
$4806c9 ffcmp#$ff
$4808d0 14bneb_481E
$480Aa9 09lda#$09
$480C8d 23 08stalives_ones
$480Fce 22 08declives_tens
$4812ad 22 08ldalives_tens
$4815c9 ffcmp#$ff
$4817d0 05bneb_481E
$4819a9 00lda#$00
$481B8d 22 08stalives_tens
$481Eb1 49b_481Elda(zp_p_tmp_lo),y; x-ref: $4808, $4817
$4820c9 61cmp#$61
$4822d0 20bneb_4844
$4824a9 delda#$de; explosion sprite #0
$482620 cb 3ejsrset_sprite0_frame_and_play_sfx
$482920 e0 48jsrbusy_wait_delay
$482Ca9 dflda#$df; explosion sprite #1
$482E8d f8 07stasprite_ptr_0
$483120 e0 48jsrbusy_wait_delay
$4834a9 delda#$de; explosion sprite #0
$48368d f8 07stasprite_ptr_0
$483920 e0 48jsrbusy_wait_delay
$483Ca9 00lda#$00
$483E8d 15 d0sta$d015; disable all sprites; Sprite display Enable
$48414c 61 48jmpj_4861
$4844a9 e0b_4844lda#$e0; explosion sprite #2 ; x-ref: $4822
$484620 db 51jsrset_sprite0_and_play_noise
$484920 e0 48jsrbusy_wait_delay
$484Ca9 e1lda#$e1; explosion sprite #3
$484E8d f8 07stasprite_ptr_0
$485120 e0 48jsrbusy_wait_delay
$4854a9 e0lda#$e0; explosion sprite #2
$48568d f8 07stasprite_ptr_0
$485920 e0 48jsrbusy_wait_delay
$485Ca9 00lda#$00
$485E8d 15 d0sta$d015; disable all sprites; Sprite display Enable
$4861ad 23 08j_4861ldalives_ones; x-ref: $4841
$4864c9 00cmp#$00
$4866f0 03beqb_486B
$48684c 73 48jmpj_4873
$486Bad 22 08b_486Bldalives_tens; x-ref: $4866
$486Ed0 03bnej_4873
$48704c 5d 1bjmpj_1B5D
$4873a9 18j_4873lda#24; x-ref: $4868, $486E
$48758d 02 08stalevel_tile_y_offset
$4878ac 00 08ldylevel_nr
$487Ba9 00lda#<level_tile_tbl
$487D85 49stazp_p_tmp_lo
$487Fa9 40lda#>level_tile_tbl
$488185 4astazp_p_tmp_hi
$4883c0 00j_4883cpy#$00; x-ref: $4895
$4885f0 11beqb_4898
$4887a5 49ldazp_p_tmp_lo
$488918clc
$488A69 20adc#$20
$488C85 49stazp_p_tmp_lo
$488Ea5 4aldazp_p_tmp_hi
$489069 00adc#$00
$489285 4astazp_p_tmp_hi
$489488dey
$48954c 83 48jmpj_4883
$4898ac 01 08b_4898ldylevel_block_idx; x-ref: $4885
$489Bb1 49j_489Blda(zp_p_tmp_lo),y; x-ref: $48BC
$489Dc9 02cmp#$02
$489Ff0 14beqb_48B5
$48A1c9 03cmp#$03
$48A3f0 10beqb_48B5
$48A5c9 01cmp#$01
$48A7f0 0cbeqb_48B5
$48A94c bb 48jmpj_48BB
$48AC.byte$f2, $c9, $0e, $f0, $ee, $c9, $0f, $f0
$48B4.byte$ea
$48B58c 01 08b_48B5stylevel_block_idx; x-ref: $489F, $48A3, $48A7
$48B84c 7b 50jmpj_507B
$48BB88j_48BBdey; x-ref: $48A9
$48BC4c 9b 48jmpj_489B
; dead code
$48BF.byte$ad, $86, $09, $cd, $27, $08, $30, $0a
$48C7.byte$ad, $86, $09, $38, $ed, $27, $08, $4c
$48CF.byte$db, $48, $ad, $27, $08, $38, $ed, $86
$48D7.byte$09, $18, $69, $0a, $aa, $e0, $00, $00
$48DF.byte$fe
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
; Busy-wait delay of approximately 0.67 seconds, used to pace the crash/explosion
; animation in the game-over sequence.
;
; The routine burns CPU cycles with a three-level nested countdown loop:
; outer : $08FF counts down from 2 to 0 (2 passes)
; middle : X counts down from 0 to 0 (wraps) (256 iterations per pass)
; inner : Y counts down from 0 to 0 (wraps) (256 iterations per X step)
;
; Total inner iterations = 2 x 256 x 256 = 131,072.
; At ~5 cycles per DEY/BNE pair on PAL C64 (985 kHz) this is roughly 0.67 s.
;
; Called three times in succession during the crash sprite swap sequence at j4800
; ($4829, $4831, $4839 / $4849, $4851, $4859), producing a ~2-second animated
; pause while the explosion sprite frames cycle and the SID crash sound plays.
;
; Note: $48F4-$48F9 are dead bytes (a BNE/DEX/BNE sequence that is unreachable
; because the DEC $08FF / BNE loop exits only when $08FF reaches 0, at which
; point the BNE at $48F2 falls through directly to RTS at $48F4).
;
; Inputs: none
; Outputs: A = 0, X = 0, Y = 1 (loop residue); $08FF = 0
; Side Effects: ~0.67 s of CPU time consumed; $08FF zeroed
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
$48E0a9 02busy_wait_delaylda#$02; outer loop counter = 2 passes ; x-ref: $4829, $4831, $4839, $4849, $4851, $4859
$48E28d ff 08stabusy_wait_delay_ctr; store outer count in $08FF
$48E5a2 00b_48E5ldx#$00; middle loop: X = 256 iterations per outer pass ; x-ref: $48F2
$48E7a0 00b_48E7ldy#$00; inner loop: Y = 256 iterations per X step ; x-ref: $48ED
$48E988b_48E9dey; inner burn: ~5 cycles per iteration ; x-ref: $48EA
$48EAd0 fdbneb_48E9
$48ECcadex; middle step: 256 inner loops done, decrement X
$48EDd0 f8bneb_48E7
$48EFce ff 08decbusy_wait_delay_ctr; decrement outer counter ($08FF); loop back if not zero
$48F2d0 f1bneb_48E5
$48F460rts; return after ~0.67 s delay (2 x 256 x 256 inner iterations)
$48F5.byte$d0, $fd, $ca, $d0, $f8, $60, $00, $00; DEAD: unreachable - BNE/DEX/BNE below $48F4 never executed
$48FD.byte$00, $00, $00
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
; Advances a 4-stage pipeline of road colour-row data used by the scrolling engine.
;
; The game maintains four pipeline slots, each 40 bytes apart in RAM:
; Slot 0 (newest): ptr $0748/$0749, colour strip $0753..$076F (29 bytes)
; Slot 1: ptr $0770/$0771, colour strip $077B..$0797
; Slot 2: ptr $0798/$0799, colour strip $07A3..$07BF
; Slot 3 (oldest): ptr $07C0/$07C1, colour strip $07CB..$07E7
;
; Each call shifts all slots one step toward the screen bottom (slot 3 drops off):
; strip[2] -> strip[3] (29 bytes, Y = 0..28)
; strip[1] -> strip[2]
; strip[0] -> strip[1]
; ptr[2] -> ptr[3] (16-bit colour-RAM row address)
; ptr[1] -> ptr[2]
; ptr[0] -> ptr[1]
; $0748/$0749 -> ptr[0] (freshest pointer, injected each frame by the map scroller)
;
; Slot 0 ($0753 strip + $0748 ptr) is written by the caller with the new road row
; data before this routine runs, making it the "front" of the FIFO queue.
;
; Returns A = $07 so that scroll_screen_down ($1500) can immediately form the
; screen pointer $0747 (a4A=$07, a49=$47 = last byte of the visible play area),
; avoiding a redundant LDA #$07.
;
; Called once per frame by scroll_screen_down ($1500) as the first step of the
; full downward screen scroll (road flows top-to-bottom in this top-down racer).
;
; Inputs: $0753..$076F colour strip, slot 0 (29 bytes, newest row)
; $077B..$0797 colour strip, slot 1
; $07A3..$07BF colour strip, slot 2
; $0748/$0749 colour-RAM row pointer, slot 0
; $0770/$0771 colour-RAM row pointer, slot 1
; $0798/$0799 colour-RAM row pointer, slot 2
; Outputs: A = $07 (high byte for screen-RAM scroll pointer $0747)
; $077B..$07E7 slots 1-3 colour strips overwritten with shifted data
; $0770/$0771, $0798/$0799, $07C0/$07C1 colour-RAM ptrs shifted
; Side Effects: Slot 3 previous content destroyed; slot 0 inputs are not touched.
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
shift_colour_row_pipeline
$4900a0 00ldy#$00; Y = 0, loop index for 29-byte colour strip copy ; x-ref: $1500
$4902b9 a3 07b_4902ldaSCREEN_RAM_R23C11,y; read slot 2 strip byte [y] ($07A3+y) ; x-ref: $4917
$490599 cb 07staSCREEN_RAM_R24C11,y; write to slot 3 strip byte [y] ($07CB+y) -- slot2 -> slot3
$4908b9 7b 07ldaSCREEN_RAM_R22C11,y; read slot 1 strip byte [y] ($077B+y)
$490B99 a3 07staSCREEN_RAM_R23C11,y; write to slot 2 strip byte [y] ($07A3+y) -- slot1 -> slot2
$490Eb9 53 07ldaSCREEN_RAM_R21C11,y; read slot 0 strip byte [y] ($0753+y) -- newest row
$491199 7b 07staSCREEN_RAM_R22C11,y; write to slot 1 strip byte [y] ($077B+y) -- slot0 -> slot1
$4914c8iny
$4915c0 1dcpy#$1d; 29 bytes per strip (not 40; word ptrs live in the gap above $076F)
$4917d0 e9bneb_4902
$4919ad 98 07ldaSCREEN_RAM_R23C0; slot 1 colour-RAM row ptr lo ($0798) ...
$491C8d c0 07staSCREEN_RAM_R24C0; ... -> slot 2 ptr lo ($07C0) -- slot1 ptr -> slot2 ptr
$491Fad 99 07ldaSCREEN_RAM_R23C1; slot 1 colour-RAM row ptr hi ($0799)
$49228d c1 07staSCREEN_RAM_R24C1; -> slot 2 ptr hi ($07C1)
$4925ad 70 07ldaSCREEN_RAM_R22C0; slot 0 colour-RAM row ptr lo ($0770)
$49288d 98 07staSCREEN_RAM_R23C0; -> slot 1 ptr lo ($0798) -- slot0 ptr -> slot1 ptr
$492Bad 71 07ldaSCREEN_RAM_R22C1; slot 0 colour-RAM row ptr hi ($0771)
$492E8d 99 07staSCREEN_RAM_R23C1; -> slot 1 ptr hi ($0799)
$4931ad 48 07ldaSCREEN_RAM_R21C0; incoming slot ptr lo ($0748) -- freshest ptr, set by caller/loader
$49348d 70 07staSCREEN_RAM_R22C0; -> slot 0 ptr lo ($0770)
$4937ad 49 07ldaSCREEN_RAM_R21C1; incoming slot ptr hi ($0749)
$493A8d 71 07staSCREEN_RAM_R22C1; -> slot 0 ptr hi ($0771)
$493Da9 07lda#>SCREEN_RAM_R20C39; return A=$07: scroll_screen_down uses this as high byte of ptr $0747
$493F60rts
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
; Advances the two-digit on-screen distance counter shown in the HUD, driven by
; how many new road rows have scrolled since the last call.
;
; scroll_row_counter ($0827) is a 0-9 modular counter incremented once per road
; row by the map scroller. Each call computes delta = (current - snapshot) mod 10
; to get the number of new rows that have passed. For each delta tick the
; sub-step counter dist_substep ($0987) is incremented; once it reaches 7 the
; ones digit dist_digit_ones ($0823) advances by 1, carrying into the tens digit
; dist_digit_tens ($0822) on overflow. Every digit advance also fires a short SID
; voice-1 "tick" click via sid_tick_sfx_and_get_ones.
;
; The routine does NOT end with RTS. It tail-calls update_hiscore_if_beaten
; ($17DD), which compares the 7-digit score ($0825-$082B) against the stored
; hi-score ($0F50-$0F56) and copies the score over if it is higher. That routine
; returns with A = hud_level_digit ($0820), which propagates back to the caller
; update_hud_display ($16B0) and is written to screen RAM at $0420 as the level
; digit after adding $30.
;
; Inputs: scroll_row_counter ($0827) current 0-9 row counter
; scroll_row_snapshot ($0986) row counter value at previous call
; dist_substep ($0987) sub-step accumulator (0-6)
; dist_digit_ones ($0823) ones digit of distance counter (0-9)
; dist_digit_tens ($0822) tens digit of distance counter (0-9)
; Outputs: A = hud_level_digit ($0820) (returned via tail-call to $17DD)
; dist_digit_ones and dist_digit_tens updated in place
; Side Effects: scroll_row_snapshot ($0986) updated to current scroll_row_counter
; dist_substep ($0987) updated
; SID voice 1 programmed with tick SFX on each digit advance
; Hi-score at $0F50-$0F56 overwritten if current score is higher
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
advance_distance_counter
$4940ad 27 08ldascroll_row_counter; load current scroll-row counter (0-9, wraps each 10 rows) ; x-ref: $16B0
$4943cd 86 09cmpscroll_row_snapshot; compare with snapshot from previous call
$494630 0abmib_4952; current < snapshot means counter wrapped through 0; take wrap path
; no-wrap path: delta = current - snapshot (0..9)
$4948ad 27 08ldascroll_row_counter
$494B38sec
$494Ced 86 09sbcscroll_row_snapshot; delta = current - snapshot
$494F4c 5c 49jmpj_495C
; wrap path: counter passed through 0; delta = (current - snapshot) + 10
$4952ad 27 08b_4952ldascroll_row_counter; x-ref: $4946
$495538sec
$4956ed 86 09sbcscroll_row_snapshot; partial subtraction (will be negative without correction)
$495918clc
$495A69 0aadc#$0a; +10 corrects for modular wrap: delta = (current - snapshot) + 10
$495Caaj_495Ctax; X = number of scroll-row ticks to consume this frame ; x-ref: $494F
$495De0 00j_495Dcpx#$00; loop: all ticks consumed? ; x-ref: $4989
$495Ff0 2bbeqb_498C; yes -> save snapshot and exit
$4961ad 87 09ldadist_substep; load sub-step counter (0-6); digit advances once every 7 ticks
$496418clc
$496569 01adc#$01
$49678d 87 09stadist_substep
$496Ac9 07cmp#$07; completed a full 7-step cycle?
$496Cd0 1abneb_4988; no -> skip digit advance this tick
$496Ea9 00lda#$00
$49708d 87 09stadist_substep; reset sub-step to 0 for next cycle
$497320 c4 3fjsrsid_tick_sfx_and_get_ones; fire SID voice-1 tick SFX; returns current dist_digit_ones in A
$497618clc
$497769 01adc#$01; increment ones digit
$49798d 23 08stalives_ones
$497Cc9 0acmp#$0a; ones digit reached 10? (overflow)
$497Ed0 08bneb_4988; no overflow -> continue loop
$4980a9 00lda#$00
$49828d 23 08stalives_ones; wrap ones digit back to 0
$4985ee 22 08inclives_tens; carry into tens digit
$4988cab_4988dex; consume one tick; loop back ; x-ref: $496C, $497E
$49894c 5d 49jmpj_495D
$498Cad 27 08b_498Cldascroll_row_counter; reload current row counter (snapshot must be fresh, not stale in A) ; x-ref: $495F
$498F8d 86 09stascroll_row_snapshot; save as new snapshot for next call
$49924c 99 17jmpj_1799; tail-call: update hi-score if beaten; returns A = hud_level_digit ($0820)
; dead code
$4995.byte$bd, $f8, $07, $09, $01, $9d, $f8, $07
$499D.byte$4c, $f4, $47
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
; Updates 2-frame animations for player and active enemy car sprites.
; Toggles bit 0 of sprite pointers ($07F8-$07FC) to cycle frames.
;
; Inputs: sfx_voice_1_en ($0805) - Player animation enable flag
; car_state ($0928) - Array of 4 enemy car states (1 = Active)
; Outputs: None
; Side Effects: Modifies sprite pointers in screen memory.
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
update_sprite_animations
$49A0ad 05 08ldaplayer_is_jumping; x-ref: $1844
$49A3f0 05beqb_49AA
$49A5a2 01ldx#$01
$49A74c c4 49jmpj_49C4
$49AAad f8 07b_49AAldasprite_ptr_0; x-ref: $49A3
$49AD29 01and#$01
$49AFd0 0bbneb_49BC; If bit 0 set, clear it. Else set it.
$49B1ad f8 07ldasprite_ptr_0
$49B409 01ora#$01
$49B68d f8 07stasprite_ptr_0
$49B94c c4 49jmpj_49C4
$49BCad f8 07b_49BCldasprite_ptr_0; x-ref: $49AF
$49BF29 feand#$fe
$49C18d f8 07stasprite_ptr_0
$49C4a2 00j_49C4ldx#$00; x-ref: $49A7, $49B9
$49C6bd 28 09b_49C6ldatbl_enemy_car_state,x; x-ref: $49EA
$49C9c9 01cmp#$01
$49CBd0 1abneb_49E7
$49CDbd f9 07ldasprite_ptr_1,x
$49D029 01and#$01
$49D2d0 0bbneb_49DF
$49D4bd f9 07ldasprite_ptr_1,x; Toggle frame for active enemy car
$49D709 01ora#$01
$49D99d f9 07stasprite_ptr_1,x
$49DC4c e7 49jmpb_49E7
$49DFbd f9 07b_49DFldasprite_ptr_1,x; x-ref: $49D2
$49E229 feand#$fe
$49E49d f9 07stasprite_ptr_1,x
$49E7e8b_49E7inx; x-ref: $49CB, $49DC
$49E8e0 04cpx#$04
$49EAd0 dabneb_49C6
$49EC60rts
; -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
$49EDad f5 00j_49EDlda@w zp_joy_state; x-ref: $4460
$49F029 02and#$02
$49F2d0 03bner_49F7
$49F44c 64 44jmphandle_deceleration
$49F760r_49F7rts; x-ref: $49F2
$49F8.fill8, $00
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
; Iterates through the 4 available enemy car slots ($0928).
; If it finds an empty slot, it uses the KERNAL ROM's random number generator
; rutines ($E097) multiple times to determine the enemy car's sprite shape (0-7),
; initial starting X coordinate (bounded so it stays on the road), and speed.
;
; Inputs: Enemy active array at $0928
; Outputs: None
; Side Effects: Spawns new enemies, modifies Sprite Pointers $07F9-$07FC,
; and relies on KERNAL ROM state.
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
$4A00a2 00spawn_enemy_carsldx#$00; x-ref: $3AD4
$4A02bd 28 09b_4A02ldatbl_enemy_car_state,x; x-ref: $4A0A
$4A05f0 06beqb_4A0D; Check if slot is empty (0)
$4A07e8j_4A07inx; x-ref: $4ABC, $4B1F
$4A08e0 04cpx#$04
$4A0Ad0 f6bneb_4A02
$4A0C60rts
$4A0D8ab_4A0Dtxa; x-ref: $4A05
$4A0E48pha
$4A0F20 97 e0jsre_E097; Generate Random Number (uses BASIC ROM)
$4A1268pla
$4A13aatax
$4A14a5 8cldazp_rnd_car_type_byte; AND #$07 → random car type 0-7; FAC byte from first ROM_RND call
$4A1629 07and#$07; Random 0-7 (enemy car type)
$4A189d 2c 09statbl_enemy_car_type,x
$4A1B0aasla
$4A1C18clc
$4A1D69 c2adc#$c2
$4A1F9d f9 07stasprite_ptr_1,x
$4A228atxa
$4A2348pha
$4A2420 97 e0jsre_E097; Generate Random Number for Position
$4A2768pla
$4A28aatax
$4A29bd 2c 09ldatbl_enemy_car_type,x
$4A2Cc9 00cmp#$00
$4A2Ef0 1dbeqb_4A4D
$4A30c9 01cmp#$01
$4A32f0 19beqb_4A4D
$4A34c9 02cmp#$02
$4A36f0 22beqb_4A5A
$4A38c9 03cmp#$03
$4A3Af0 2bbeqb_4A67
$4A3Cc9 04cmp#$04
$4A3Ef0 34beqb_4A74
$4A40c9 05cmp#$05
$4A42f0 3dbeqb_4A81
$4A44c9 06cmp#$06
$4A46f0 39beqb_4A81
$4A48c9 07cmp#$07
$4A4Af0 35beqb_4A81
$4A4C00brk
$4A4Da5 8fb_4A4Dldazp_rnd_pos_byte; Mask random byte to [0,$7F] range, add $67 offset → NPC X start position for car types 0/1 ; x-ref: $4A2E, $4A32
$4A4F29 7fand#$7f
$4A5118clc
$4A5269 67adc#$67
$4A5420 ec 4ejsrspawn_npc_car
$4A574c 8b 4ajmpj_4A8B
$4A5Aa5 8fb_4A5Aldazp_rnd_pos_byte; x-ref: $4A36
$4A5C29 3fand#$3f
$4A5E18clc
$4A5F69 45adc#$45
$4A6120 ec 4ejsrspawn_npc_car
$4A644c 8b 4ajmpj_4A8B
$4A67a5 8fb_4A67ldazp_rnd_pos_byte; x-ref: $4A3A
$4A6929 7fand#$7f
$4A6B18clc
$4A6C69 7badc#$7b
$4A6E20 ec 4ejsrspawn_npc_car
$4A714c 8b 4ajmpj_4A8B
$4A74a5 8fb_4A74ldazp_rnd_pos_byte; x-ref: $4A3E
$4A7629 3fand#$3f
$4A7818clc
$4A7969 a0adc#$a0
$4A7B20 ec 4ejsrspawn_npc_car
$4A7E4c 8b 4ajmpj_4A8B
$4A81a5 8fb_4A81ldazp_rnd_pos_byte; x-ref: $4A42, $4A46, $4A4A
$4A8329 7fand#$7f
$4A8518clc
$4A8669 65adc#$65
$4A8820 ec 4ejsrspawn_npc_car
$4A8B8aj_4A8Btxa; x-ref: $4A57, $4A64, $4A71, $4A7E
$4A8C48pha
$4A8D20 97 e0jsre_E097; Generate Random Number for Speed
$4A9068pla
$4A91aatax
$4A924c 74 4cjmpj_4C74
$4A95.byte$cd, $04, $08, $30, $0b
$4A9Aa9 07j_4A9Alda#$07; x-ref: $4C7D
$4A9C85 4astazp_p_tmp_hi
$4A9Ea9 73lda#$73
$4AA085 49stazp_p_tmp_lo
$4AA24c ad 4ajmpj_4AAD
$4AA5a9 04j_4AA5lda#>SCREEN_RAM_R2C0; x-ref: $4C80
$4AA785 4astazp_p_tmp_hi
$4AA9a9 50lda#<SCREEN_RAM_R2C0
$4AAB85 49stazp_p_tmp_lo
$4AADa5 8fj_4AADldazp_rnd_pos_byte; x-ref: $4AA2
$4AAF29 17and#$17
$4AB1a8tay
$4AB2b1 49lda(zp_p_tmp_lo),y
$4AB4c9 20cmp#$20
$4AB6f0 07beqb_4ABF
$4AB8c9 65cmp#$65
$4ABAf0 03beqb_4ABF
$4ABC4c 07 4ajmpj_4A07
$4ABF98b_4ABFtya; x-ref: $4AB6, $4ABA
$4AC00aasla
$4AC10aasla
$4AC20aasla
$4AC318clc
$4AC469 18adc#$18
$4AC648pha
$4AC78atxa
$4AC80aasla
$4AC9aatax
$4ACA68pla
$4ACB9d 02 d0sta$d002,x; Sprite 1 X Pos
$4ACE8atxa
$4ACF4alsra
$4AD0aatax
$4AD14c 83 4cjmpj_4C83
; dead code
$4AD4.byte$cd, $04, $08, $30, $05
$4AD9a9 e0j_4AD9lda#$e0; x-ref: $4C8C
$4ADB4c e0 4ajmpj_4AE0
$4ADEa9 3aj_4ADElda#$3a; x-ref: $4C8F
$4AE048j_4AE0pha; x-ref: $4ADB
$4AE18atxa
$4AE20aasla
$4AE3aatax
$4AE468pla
$4AE59d 03 d0sta$d003,x; Sprite 1 Y Pos
$4AE88atxa
$4AE94alsra
$4AEAaatax
$4AEBa5 8dldazp_rnd_direction_byte; AND #$01 → random lane direction (0=down, 1=up); FAC byte from third ROM_RND call
$4AED29 01and#$01
$4AEF9d 04 09staf_0904,x
$4AF2a5 8eldazp_rnd_speed_byte; AND #$03 → random speed index 0-3; FAC byte from third ROM_RND call
$4AF429 03and#$03
$4AF69d 08 09staf_0908,x
$4AF9a9 01lda#$01
$4AFB9d 28 09statbl_enemy_car_state,x
$4AFEa9 00lda#$00
$4B009d 0c 09statbl_enemy_sprite_state,x
$4B039d 10 09statbl_enemy_sprite_direction,x
$4B069d 14 09statbl_enemy_sprite_step_count,x
$4B099d 18 09staf_0918,x
$4B0C9d 0c 09statbl_enemy_sprite_state,x
$4B0F9d 20 09statbl_enemy_sprite_lifetime,x
$4B129d 24 09statbl_enemy_sprite_active,x
$4B15bd 2c 09ldatbl_enemy_car_type,x
$4B18a8tay
$4B19b9 00 3fldatbl_sprite_color,y
$4B1C9d 28 d0sta$d028,x; Sprite 1 Color
$4B1F4c 07 4ajmpj_4A07
$4B22.fill222, $00
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
; Updates the position and state of the enemy cars (Sprites 1-4).
; This routine iterates through up to 4 active enemy entities. For each active
; entity, it updates their horizontal position (swerving left or right) based on
; their local state metrics. It then computes their new vertical position on the
; screen by factoring in the player's current speed/scroll offset ($0804).
; If an enemy car falls off the top or bottom of the screen (Y < $3A or Y >= $F0),
; the routine automatically despawns it by clearing its status flag and hiding the
; sprite.
;
; Inputs: Global scroll/speed ($0804), arrays at $0900/0904/0908/090C/0924/0928
; Outputs: None
; Side Effects: Modifies Sprite 1-4 X/Y coordinates ($D002-$D009) and entity states.
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
$4C00a2 00update_enemy_carsldx#$00; x-ref: $3AF0, $4779
$4C02bd 0c 09b_4C02ldatbl_enemy_sprite_state,x; x-ref: $4C0A
$4C05f0 06beqb_4C0D
$4C07e8b_4C07inx; x-ref: $4C10, $4C17, $4CFD, $4D30
$4C08e0 04cpx#$04
$4C0Ad0 f6bneb_4C02
$4C0C60rts
$4C0Dbd 24 09b_4C0Dldatbl_enemy_sprite_active,x; x-ref: $4C05
$4C10d0 f5bneb_4C07
$4C12bd 28 09ldatbl_enemy_car_state,x
$4C15c9 01cmp#$01
$4C17d0 eebneb_4C07
$4C19bd 08 09ldaf_0908,x
$4C1Ca8tay
$4C1Dc0 00j_4C1Dcpy#$00; x-ref: $4C58
$4C1Ff0 44beqb_4C65
$4C21bd 04 09ldaf_0904,x
$4C24f0 1fbeqb_4C45
$4C268atxa
$4C2748pha
$4C280aasla
$4C29aatax
$4C2Afe 02 d0inc$d002,x; Sprite 1 X Pos
$4C2D4c 40 4cjmpj_4C40
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
; Resets the player sprite pointer and terminates the jump sound effect.
;
; Inputs: A (sprite pointer value for sprite 0)
; Outputs: Sprite 0 pointer updated, SID voice 1 control register cleared
; Side Effects: Ends jump sound, updates sprite, proceeds to update_tick_and_collisions
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
restore_player_sprite_stop_sound
$4C308d f8 07stasprite_ptr_0; x-ref: $1ADE
$4C33a9 00lda#$00
$4C358d 04 d4sta$d404; Clear Voice 1 Control Register to stop jump sound; Voice 1: Control Register
$4C384c 26 45jmpupdate_tick_and_collisions
$4C3B.byte$00, $00, $00, $00, $00
$4C4068j_4C40pla; x-ref: $4C2D, $4C4C
$4C41aatax
$4C424c 5e 4cjmpj_4C5E
$4C458ab_4C45txa; x-ref: $4C24
$4C4648pha
$4C470aasla
$4C48aatax
$4C49de 02 d0dec$d002,x; Sprite 1 X Pos
$4C4C4c 40 4cjmpj_4C40
$4C4F20 a8 4dj_4C4Fjsrcheck_npc_car_on_road; x-ref: $4CA9
$4C524c 68 4cjmpj_4C68
$4C55eaj_4C55nop; x-ref: $4C62
$4C56eanop
$4C57eanop
$4C584c 1d 4cjmpj_4C1D
$4C5B.byte$00, $00, $00
$4C5E20 33 4dj_4C5Ejsrcheck_car_on_road; x-ref: $4C42
$4C6188dey
$4C624c 55 4cjmpj_4C55
$4C654c 9a 4cb_4C65jmpj_4C9A; x-ref: $4C1F
$4C68bd 00 09j_4C68ldaf_0900,x; x-ref: $4C52
$4C6B38sec
$4C6Ced 04 08sbcplayer_speed
$4C6F90 56bccb_4CC7
$4C714c b1 4cjmpj_4CB1
$4C74bd 00 09j_4C74ldaf_0900,x; x-ref: $4A92
$4C7738sec
$4C78ed 04 08sbcplayer_speed
$4C7B90 03bccb_4C80
$4C7D4c 9a 4ajmpj_4A9A
$4C804c a5 4ab_4C80jmpj_4AA5; x-ref: $4C7B
$4C83bd 00 09j_4C83ldaf_0900,x; x-ref: $4AD1
$4C8638sec
$4C87ed 04 08sbcplayer_speed
$4C8A90 03bccb_4C8F
$4C8C4c d9 4ajmpj_4AD9
$4C8F4c de 4ab_4C8Fjmpj_4ADE; x-ref: $4C8A
; dead code
$4C92.byte$38, $ed, $04, $08, $90, $03, $4c, $d9
$4C9A8aj_4C9Atxa; x-ref: $4C65, $4DA5
$4C9B48pha
$4C9C0aasla
$4C9Daatax
$4C9Ebd 03 d0lda$d003,x; Sprite 1 Y Pos
$4CA118clc
$4CA269 08adc#$08
$4CA49d 03 d0sta$d003,x; Sprite 1 Y Pos
$4CA768pla
$4CA8aatax
$4CA94c 4f 4cjmpj_4C4F
; dead code
$4CAC.byte$cd, $04, $08, $30, $16
$4CB1bd 00 09j_4CB1ldaf_0900,x; x-ref: $4C71
$4CB438sec
$4CB5ed 04 08sbcplayer_speed
$4CB84alsra
$4CB94alsra
$4CBA4alsra
$4CBB18clc
$4CBC69 08adc#$08
$4CBEc9 10cmp#$10
$4CC030 02bmib_4CC4
$4CC2a9 10lda#$10
$4CC44c d1 4cb_4CC4jmpj_4CD1; x-ref: $4CC0
$4CC7ad 04 08b_4CC7ldaplayer_speed; x-ref: $4C6F
$4CCA38sec
$4CCBfd 00 09sbcf_0900,x
$4CCE4c 09 4djmpj_4D09
$4CD1a8j_4CD1tay; x-ref: $4CC4, $4D19
$4CD2c0 00j_4CD2cpy#$00; x-ref: $4CE3
$4CD4f0 10beqb_4CE6
$4CD620 e0 3ajsrdetect_npc_car_collision_preserve_xy
$4CD98atxa
$4CDA48pha
$4CDB0aasla
$4CDCaatax
$4CDDde 03 d0dec$d003,x; Sprite 1 Y Pos
$4CE068pla
$4CE1aatax
$4CE288dey
$4CE34c d2 4cjmpj_4CD2
$4CE68ab_4CE6txa; x-ref: $4CD4, $4DF0
$4CE748pha
$4CE80aasla
$4CE9aatax
$4CEA4c 1c 4djmpj_4D1C
$4CED.byte$03, $d0, $00, $0f
$4CF1a9 00j_4CF1lda#$00; x-ref: $4D27
$4CF39d 03 d0sta$d003,x; Sprite 1 Y Pos
$4CF668pla
$4CF7aatax
$4CF8a9 00lda#$00
$4CFA9d 28 09statbl_enemy_car_state,x
$4CFD4c 07 4cjmpb_4C07
; dead code
$4D00.byte$c9, $f0, $10, $ed, $68, $aa, $4c, $07
$4D08.byte$4c
$4D094aj_4D09lsra; x-ref: $4CCE
$4D0A4alsra
$4D0B4alsra
$4D0Cc9 09cmp#$09
$4D0E30 02bmib_4D12
$4D10a9 08lda#$08
$4D1285 49b_4D12stazp_p_tmp_lo; x-ref: $4D0E
$4D14a9 08lda#$08
$4D1638sec
$4D17e5 49sbczp_p_tmp_lo
$4D194c d1 4cjmpj_4CD1
$4D1Cbd 03 d0j_4D1Clda$d003,x; x-ref: $4CEA Sprite 1 Y Pos
$4D1Fc9 80cmp#$80
$4D2130 07bmib_4D2A
$4D23c9 f0cmp#$f0
$4D2530 07bmib_4D2E
$4D274c f1 4cb_4D27jmpj_4CF1; x-ref: $4D2C
$4D2Ac9 3ab_4D2Acmp#$3a; x-ref: $4D21
$4D2C30 f9bmib_4D27
$4D2E68b_4D2Epla; x-ref: $4D25
$4D2Faatax
$4D304c 07 4cjmpb_4C07
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
; Checks whether an enemy car (sprite N, passed in X) is on a drivable road tile.
;
; The routine converts the sprite's screen-space pixel position (from VIC-II
; $D002/$D003 registers) into a tile column (Y) and tile row (X) by subtracting
; a fixed border offset and dividing by 8 (three LSRs). It then computes a
; pointer into screen RAM at $0400 using a 16-bit base address in (a49/a4A)
; and multiplies the row by 40 ($28) to find the correct row offset.
;
; A lookup table at $F0904, indexed by sprite number X, provides a half-tile
; column adjustment (+1) to handle wide sprites that straddle two tiles.
;
; The road tile check reads the screen code at the computed (row, col) position:
; - $20 (space) = road tile -> jump to j4ED3 (car is off-road / blocked)
; - $65 (letter) = another road variant -> also treated as blocked
;
; If the car is on road (non-road tile), the routine stores $01 at f0904,x (car
; is on-road flag = active), restores registers, samples bits 0-1 of ZP $8E for
; a 2-bit value and stores it at f0908,x (road direction/surface type), then
; jumps to j4C9A (continue normal car movement logic).
;
; If the car is off-road, f0904,x is cleared ($00), and the routine redirects to
; j4ED3 which will handle the out-of-bounds / collision branch.
;
; Inputs: X = sprite/car index (0-3)
; Outputs: f0904,x = 1 if on-road, 0 if off-road; f0908,x = road surface bits
; Side Effects: Reads VIC-II sprite X/Y registers ($D002/$D003); reads screen RAM
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
$4D338acheck_car_on_roadtxa; sprite index -> X reg (doubled for VIC pair offset) ; x-ref: $4C5E
$4D3448pha
$4D3598tya
$4D3648pha
$4D378atxa
$4D3848pha
$4D390aasla
$4D3Aaatax
$4D3Bbd 02 d0lda$d002,x; Sprite 1 X Pos
$4D3E38sec
$4D3Fe9 10sbc#$10
$4D414alsra
$4D424alsra
$4D434alsra; subtract left border ($10 px) then >> 3 = tile column -> Y
$4D44a8tay
$4D45bd 03 d0lda$d003,x; Sprite 1 Y Pos
$4D4838sec
$4D49e9 32sbc#$32
$4D4B4alsra
$4D4C4alsra
$4D4D4alsra
$4D4Eaatax
$4D4Fa9 00lda#<SCREEN_RAM
$4D5185 49stazp_p_tmp_lo
$4D53a9 04lda#>SCREEN_RAM; base screen RAM low byte = $00 (addr $0400)
$4D5585 4astazp_p_tmp_hi; base screen RAM high byte = $04 (addr $0400)
$4D57e0 00j_4D57cpx#$00; x-ref: $4D69
$4D59f0 11beqb_4D6C
$4D5Ba5 49ldazp_p_tmp_lo
$4D5D18clc
$4D5E69 28adc#$28
$4D6085 49stazp_p_tmp_lo
$4D62a5 4aldazp_p_tmp_hi
$4D6469 00adc#$00
$4D6685 4astazp_p_tmp_hi
$4D68cadex
$4D694c 57 4djmpj_4D57
$4D6C68b_4D6Cpla; $20 (space screencode) = road tile -> car is off-road/blocked ; x-ref: $4D59
$4D6Daatax
$4D6Ebd 04 09ldaf_0904,x
$4D71f0 01beqb_4D74
$4D73c8iny
$4D74b1 49b_4D74lda(zp_p_tmp_lo),y; x-ref: $4D71
$4D76c9 20cmp#$20
$4D78d0 05bneb_4D7F
$4D7A4c d3 4eb_4D7Ajmpcheck_npc_offscreen_right; x-ref: $4D81
$4D7D.byte$ea, $60
$4D7Fc9 65b_4D7Fcmp#$65; $65 = alternate road screencode -> also off-road ; x-ref: $4D78
$4D81f0 f7beqb_4D7A
$4D83bd 04 09j_4D83ldaf_0904,x; not on road: clear on-road flag for this car ; x-ref: $4EE9
$4D86f0 08beqb_4D90
$4D88a9 00lda#$00
$4D8A9d 04 09staf_0904,x
$4D8D4c 95 4djmpj_4D95
$4D90a9 01b_4D90lda#$01; x-ref: $4D86
$4D929d 04 09staf_0904,x
$4D95eaj_4D95nop; x-ref: $4D8D
$4D96eanop
$4D97eanop
$4D9868pla
$4D99a8tay
$4D9A68pla
$4D9Baatax
$4D9C68pla
$4D9D68pla
$4D9Ea5 8eldazp_rnd_speed_byte
$4DA029 03and#$03
$4DA29d 08 09staf_0908,x
$4DA54c 9a 4cjmpj_4C9A
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
; Checks if the NPC car is still on the road or has hit the off-road boundary.
; If off-road, it pops the return address and jumps to b4CE6 to abort caller.
;
; Inputs: X (NPC car index)
; Outputs: None (if on road)
; Side Effects: Aborts caller by manipulating stack if off-road.
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
check_npc_car_on_road
$4DA88atxa; Save NPC car index (X) and loop counter (Y) ; x-ref: $4C4F
$4DA948pha
$4DAA98tya
$4DAB48pha
$4DAC8atxa
$4DAD0aasla
$4DAEaatax
$4DAFbd 02 d0lda$d002,x; Convert Sprite 1 X Pos to tile column; Sprite 1 X Pos
$4DB238sec
$4DB3e9 10sbc#$10
$4DB54alsra
$4DB64alsra
$4DB74alsra
$4DB8a8tay
$4DB9bd 03 d0lda$d003,x; Convert Sprite 1 Y Pos to tile row; Sprite 1 Y Pos
$4DBC38sec
$4DBDe9 32sbc#$32
$4DBF4alsra
$4DC04alsra
$4DC14alsra
$4DC2aatax
$4DC3a9 d9lda#<p_03D9; Base address $03D9 (Screen RAM $0400 - $27)
$4DC585 49stazp_p_tmp_lo
$4DC7a9 03lda#>p_03D9
$4DC985 4astazp_p_tmp_hi
$4DCBe0 00j_4DCBcpx#$00; x-ref: $4DDD
$4DCDf0 11beqb_4DE0
$4DCFa5 49ldazp_p_tmp_lo
$4DD118clc
$4DD269 28adc#$28
$4DD485 49stazp_p_tmp_lo
$4DD6a5 4aldazp_p_tmp_hi
$4DD869 00adc#$00
$4DDA85 4astazp_p_tmp_hi
$4DDCcadex
$4DDD4c cb 4djmpj_4DCB
$4DE0b1 49b_4DE0lda(zp_p_tmp_lo),y; x-ref: $4DCD
$4DE2c9 20cmp#$20
$4DE4f0 0dbeqb_4DF3
$4DE6c9 65cmp#$65
$4DE8f0 09beqb_4DF3
$4DEA68b_4DEApla; Off-road: pop Y, X, and caller return address! ; x-ref: $4DFC
$4DEBa8tay
$4DEC68pla
$4DEDaatax
$4DEE68pla
$4DEF68pla
$4DF04c e6 4cjmpb_4CE6
$4DF3c8b_4DF3iny; x-ref: $4DE4, $4DE8
$4DF4b1 49lda(zp_p_tmp_lo),y
$4DF6c9 20cmp#$20
$4DF8f0 04beqb_4DFE
$4DFAc9 65cmp#$65
$4DFCd0 ecbneb_4DEA
$4DFE68b_4DFEpla; x-ref: $4DF8
$4DFFa8tay
$4E0068pla
$4E01aatax
$4E0260rts
$4E039d f9 07j_4E03stasprite_ptr_1,x; x-ref: $47E0
$4E068atxa
$4E0748pha
$4E08aatax
$4E09a9 02lda#$02
$4E0Be0 00j_4E0Bcpx#$00; x-ref: $4E11
$4E0Df0 05beqb_4E14
$4E0F0aasla
$4E10cadex
$4E114c 0b 4ejmpj_4E0B
$4E1485 49b_4E14stazp_p_tmp_lo; x-ref: $4E0D
$4E16a9 fflda#$ff
$4E1838sec
$4E19e5 49sbczp_p_tmp_lo
$4E1B85 49stazp_p_tmp_lo
$4E1Dad 1c d0lda$d01c; Sprites Multi-Color Mode Select
$4E2025 49andzp_p_tmp_lo
$4E228d 1c d0sta$d01c; Sprites Multi-Color Mode Select
$4E2568pla
$4E26aatax
$4E27ee 21 08inccrashed_cars_ones
$4E2Aad 21 08ldacrashed_cars_ones
$4E2D8d 21 08stacrashed_cars_ones
$4E30c9 0acmp#$0a
$4E32d0 08bner_4E3C
$4E34a9 00lda#$00
$4E368d 21 08stacrashed_cars_ones
$4E39ee 20 08inccrashed_cars_tens
$4E3C60r_4E3Crts; x-ref: $4E32
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
; Initializes a score sprite (Sprites 5-7) at the player's current location.
;
; Inputs: A (timer duration), Y (score sprite index 0-2)
; Outputs: Initializes timer array $0983,Y
; Side Effects: Modifies sprite 5-7 color and coordinates to match player
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
spawn_score_sprite_57
$4E3D99 83 09staf_0983,y; x-ref: $45EA
$4E40a9 01lda#$01
$4E4299 2c d0sta$d02c,y; Set color to 1 (white); Sprite 5 Color
$4E4598tya
$4E460aasla
$4E47a8tay
$4E48ad 00 d0lda$d000; Sprite 0 X Pos
$4E4B99 0a d0sta$d00a,y; Copy player X Pos to score sprite X Pos; Sprite 5 X Pos
$4E4Ead 01 d0lda$d001; Sprite 0 Y Pos
$4E5199 0b d0sta$d00b,y; Copy player Y Pos to score sprite Y Pos; Sprite 5 Y Pos
$4E5460rts
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
; Updates explosion and projectile animation timers.
; First, it checks the enemy pool (Sprites 1-4). If an enemy is in state $02
; (exploding), it ticks down a duration timer at $0930. When the timer reaches 0,
; it resets their state, restores their default multi-color bit config, and hides them.
; Then, it runs a second loop over a pool of 3 secondary objects (Sprites 5-7),
; ticking their timers and dropping them downward visually by adding to their Y Pos.
;
; Inputs: Enemy states at $0928, Timers at $0930 and $0983
; Outputs: None
; Side Effects: Modifies Sprites 1-7 coordinates and multi-color registers.
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
update_explosion_animations
$4E55a2 00ldx#$00; x-ref: $1841, $477C
$4E57bd 28 09b_4E57ldatbl_enemy_car_state,x; x-ref: $4E61
$4E5Ac9 02cmp#$02
$4E5Cf0 08beqb_4E66
$4E5Ee8j_4E5Einx; x-ref: $4E95
$4E5Fe0 04cpx#$04
$4E61d0 f4bneb_4E57
$4E634c 98 4ejmpj_4E98
$4E66de 30 09b_4E66dectbl_npc_damage_timer,x; x-ref: $4E5C
$4E69f0 03beqb_4E6E
$4E6B4c 98 4ejmpj_4E98
$4E6Ea9 00b_4E6Elda#$00; x-ref: $4E69
$4E709d 28 09statbl_enemy_car_state,x
$4E738atxa
$4E7448pha
$4E75a9 02lda#$02
$4E77e0 00j_4E77cpx#$00; x-ref: $4E7D
$4E79f0 05beqb_4E80
$4E7B0aasla
$4E7Ccadex
$4E7D4c 77 4ejmpj_4E77
$4E8085 49b_4E80stazp_p_tmp_lo; x-ref: $4E79
$4E82ad 1c d0lda$d01c; Sprites Multi-Color Mode Select
$4E8505 49orazp_p_tmp_lo
$4E878d 1c d0sta$d01c; Sprites Multi-Color Mode Select
$4E8A68pla
$4E8B48pha
$4E8C0aasla
$4E8Daatax
$4E8Ea9 00lda#$00
$4E909d 02 d0sta$d002,x; Sprite 1 X Pos
$4E9368pla
$4E94aatax
$4E954c 5e 4ejmpj_4E5E
$4E98a2 00j_4E98ldx#$00; x-ref: $4E63, $4E6B
$4E9Abd 80 09b_4E9Aldatbl_score_sprite_active,x; x-ref: $4EA2
$4E9Dd0 06bneb_4EA5
$4E9Fe8j_4E9Finx; x-ref: $4EBA
$4EA0e0 03cpx#$03
$4EA2d0 f6bneb_4E9A
$4EA460rts
$4EA5de 83 09b_4EA5decf_0983,x; x-ref: $4E9D
$4EA8d0 13bneb_4EBD
$4EAAa9 00lda#$00
$4EAC9d 80 09statbl_score_sprite_active,x
$4EAF8atxa
$4EB048pha
$4EB10aasla
$4EB2aatax
$4EB3a9 00lda#$00
$4EB59d 0a d0sta$d00a,x; Sprite 5 X Pos
$4EB868j_4EB8pla; x-ref: $4F01
$4EB9aatax
$4EBA4c 9f 4ejmpj_4E9F
$4EBD8ab_4EBDtxa; x-ref: $4EA8
$4EBE48pha
$4EBF0aasla
$4EC0aatax
$4EC1bd 0b d0lda$d00b,x; Sprite 5 Y Pos
$4EC418clc
$4EC569 08adc#$08
$4EC79d 0b d0sta$d00b,x; Sprite 5 Y Pos
$4ECA4c f5 4ejmpclamp_sprite5_top_boundary
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
; Main loop tail: applies player X recoil then hands off to the finalizer.
;
; Called unconditionally at the bottom of main_loop via JMP. Applies any
; pending X-axis collision recoil to the player sprite, then falls through
; to main_loop_finalize_and_repeat which runs the remaining per-frame
; housekeeping before jumping back to main_loop.
;
; Inputs: Recoil state managed by apply_player_x_recoil
; Outputs: None
; Side Effects: May shift player sprite X position
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
main_loop_apply_recoil
$4ECD20 b0 3djsrapply_player_x_recoil; Apply X-axis collision recoil to the player sprite ; x-ref: $184D
$4ED04c b0 4fjmpmain_loop_finalize_and_repeat; Fall through to per-frame housekeeping and re-enter main loop
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
; NPC off-screen-right guard, called from the NPC road-tile walker.
;
; On entry the stack holds (top to bottom): NPC slot index, Y, return address.
; Checks whether the NPC's sprite X position is $FF (sprite has scrolled off
; the right edge of the screen). Two paths:
;
; Not $FF (still on-screen): pop all three stack frames (slot, Y, ret)
; and return to the caller's caller — early exit from the tile walk.
; $FF (off-screen right): restore slot index into X, read the next tile
; byte from the current map pointer (p_tmp_lo),Y, then jump back
; into the tile-walk loop at j4D83 to handle the new tile.
;
; Inputs: Stack: NPC slot (1 byte), Y (1 byte), return address (2 bytes)
; $D002+X: NPC sprite X register (VIC-II)
; (p_tmp_lo),Y: current map tile pointer
; Outputs: A = next tile byte (off-screen path only)
; Side Effects: Unwinds 3 stack frames on the on-screen early-exit path
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
check_npc_offscreen_right
$4ED38atxa; Push NPC slot index; compute sprite reg offset (slot * 2) into X ; x-ref: $4D7A
$4ED448pha
$4ED50aasla
$4ED6aatax
$4ED7bd 02 d0lda$d002,x; Load NPC sprite X pos; $FF means sprite has scrolled off the right edge; Sprite 1 X Pos
$4EDAc9 ffcmp#$ff
$4EDCf0 06beqb_4EE4
$4EDE68pla; On-screen path: pop slot, Y, and return address — early exit from tile walk
$4EDF68pla
$4EE0a8tay
$4EE168pla
$4EE2aatax
$4EE360rts
$4EE468b_4EE4pla; Off-screen path: restore slot index into X ; x-ref: $4EDC
$4EE5aatax
$4EE6eanop
$4EE7b1 49lda(zp_p_tmp_lo),y; Read next map tile byte via current pointer
$4EE94c 83 4djmpj_4D83; Re-enter tile walk loop to process the new tile
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
; Initializes speed and fresh flag for a newly spawned NPC car.
;
; Inputs: A (initial speed), X (NPC car slot 0-3)
; Outputs: Initializes $0900,X (speed) and $0910,X (fresh flag)
; Side Effects: Sets up NPC car speed and marks it fresh for the overtake check
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
$4EEC9d 00 09spawn_npc_carstaf_0900,x; Set NPC speed ; x-ref: $4A54, $4A61, $4A6E, $4A7B, $4A88
$4EEFa9 01lda#$01
$4EF19d 34 09statbl_enemy_car_fresh_flag,x; Set fresh flag to 1 for overtake check
$4EF460rts
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
; Top-boundary clamp for Sprite 5 during NPC car movement.
;
; Called mid-loop when an NPC car's Sprite 5 Y position is being updated.
; If the Y position has gone above $20 (off the top of the playfield), the
; sprite's X position is clamped to 1 to effectively reset/hide it at the
; left edge. Execution always rejoins the NPC car movement loop at j4EB8.
;
; Inputs: $D00B+X: Sprite 5 Y position for the current NPC slot
; Outputs: $D00A+X: Sprite 5 X position (set to 1 if Y < $20)
; Side Effects: None
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
clamp_sprite5_top_boundary
$4EF5bd 0b d0lda$d00b,x; Load Sprite 5 Y pos for this NPC slot ; x-ref: $4ECA Sprite 5 Y Pos
$4EF8c9 20cmp#$20; Is Y >= $20? If so, sprite is still in bounds; skip clamp
$4EFAb0 05bcsb_4F01
$4EFCa9 01lda#$01; Y < $20: sprite scrolled off the top — clamp X to 1 to hide/reset it
$4EFE9d 0a d0sta$d00a,x; Sprite 5 X Pos
$4F014c b8 4eb_4F01jmpj_4EB8; Rejoin NPC movement loop ; x-ref: $4EFA
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
; Writes a 2x2 tile stamp to screen RAM when the player successfully passes
; over a type-4 NPC car (the "jump target" car). Only fires once per car
; appearance: car_fresh_flag[x] is set at spawn and cleared here after stamping.
;
; Proximity conditions (both must hold):
; Y: player sprite Y >= NPC sprite Y + $20 (player is >= 32px past the NPC)
; X: |player X - NPC X| < $40 (within 64px horizontally)
;
; Screen address: $0400 + ((npc_sprite_y - $22) >> 3) * 40 + ((npc_sprite_x - $10) >> 3)
; Tile stamp (2x2):
; $1B $1C <- top row at computed address
; $1D $1E <- bottom row 40 chars later
;
; Skipped if game state (a0800) is 0 or 3.
;
; Inputs: a0800 (game state), car_state[0..3], f092C[0..3] (car type),
; car_fresh_flag[0..3], VIC-II sprite regs $D000-$D009
; Outputs: Screen RAM ($0400+)
; Side Effects: Clears car_fresh_flag[x] after stamping (one-shot per car)
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
draw_car_overtake_mark
$4F04ad 00 08ldalevel_nr; x-ref: $4FB0
$4F07c9 00cmp#$00; Skip if game state 0 or 3 (not in active play)
$4F09f0 12beqr_4F1D
$4F0Bc9 03cmp#$03
$4F0Df0 0ebeqr_4F1D
$4F0Fa2 00ldx#$00
$4F11bd 28 09b_4F11ldatbl_enemy_car_state,x; x-ref: $4F1B
$4F14c9 01cmp#$01; Only check on-road/active cars (state 1)
$4F16f0 06beqb_4F1E
$4F18e8b_4F18inx; x-ref: $4F23, $4F28, $4F46, $4FAC
$4F19e0 04cpx#$04
$4F1Bd0 f4bneb_4F11
$4F1D60r_4F1Drts; x-ref: $4F09, $4F0D
$4F1Ebd 2c 09b_4F1Eldatbl_enemy_car_type,x; x-ref: $4F16
$4F21c9 04cmp#$04; Only process type-4 cars (jump target)
$4F23d0 f3bneb_4F18
$4F25bd 34 09ldatbl_enemy_car_fresh_flag,x
$4F28f0 eebeqb_4F18; Skip if already stamped (flag cleared after first hit)
$4F2A8atxa
$4F2B48pha
$4F2C0aasla
$4F2Daatax
$4F2Ebd 03 d0lda$d003,x; Check Y: is player past this car?; Sprite 1 Y Pos
$4F31cd 01 d0cmp$d001; Sprite 0 Y Pos
$4F3490 03bccb_4F39
$4F364c 44 4fjmpj_4F44
$4F39ad 01 d0b_4F39lda$d001; x-ref: $4F34 Sprite 0 Y Pos
$4F3C38sec
$4F3Dfd 03 d0sbc$d003,x; Sprite 1 Y Pos
$4F40c9 20cmp#$20; Player must be >= 32px below NPC (past it in race direction)
$4F42b0 05bcsb_4F49
$4F4468j_4F44pla; x-ref: $4F36, $4F61
$4F45aatax
$4F464c 18 4fjmpb_4F18
$4F49bd 02 d0b_4F49lda$d002,x; x-ref: $4F42 Sprite 1 X Pos
$4F4Ccd 00 d0cmp$d000; Sprite 0 X Pos
$4F4F90 07bccb_4F58
$4F5138sec
$4F52ed 00 d0sbc$d000; Sprite 0 X Pos
$4F554c 5f 4fjmpj_4F5F
$4F58ad 00 d0b_4F58lda$d000; x-ref: $4F4F Sprite 0 X Pos
$4F5B38sec
$4F5Cfd 02 d0sbc$d002,x; Sprite 1 X Pos
$4F5Fc9 40j_4F5Fcmp#$40; X proximity: must be within 64px ; x-ref: $4F55
$4F61b0 e1bcsj_4F44
$4F63bd 02 d0lda$d002,x; Sprite 1 X Pos
$4F6638sec
$4F67e9 10sbc#$10; sprite_x - $10 = pixel offset from left edge; >>3 = tile column (0-39)
$4F694alsra
$4F6A4alsra
$4F6B4alsra
$4F6C85 49stazp_p_tmp_lo
$4F6Ebd 03 d0lda$d003,x; Sprite 1 Y Pos
$4F7138sec
$4F72e9 22sbc#$22; sprite_y - $22 = pixel offset from top; >>3 = tile row (0-24)
$4F744alsra
$4F754alsra
$4F764alsra
$4F77a8tay
$4F78a9 04lda#$04
$4F7A85 4astazp_p_tmp_hi
$4F7Cc0 00j_4F7Ccpy#$00; Multiply row by 40 (screen width) to get row byte offset ; x-ref: $4F8E
$4F7Ef0 11beqb_4F91
$4F80a5 49ldazp_p_tmp_lo
$4F8218clc
$4F8369 28adc#$28
$4F8585 49stazp_p_tmp_lo
$4F87a5 4aldazp_p_tmp_hi
$4F8969 00adc#$00
$4F8B85 4astazp_p_tmp_hi
$4F8D88dey
$4F8E4c 7c 4fjmpj_4F7C
$4F91a9 1bb_4F91lda#$1b; Write top-left tile of 2x2 stamp ; x-ref: $4F7E
$4F9391 49sta(zp_p_tmp_lo),y
$4F95c8iny
$4F96a9 1clda#$1c; Write top-right tile
$4F9891 49sta(zp_p_tmp_lo),y
$4F9Aa0 28ldy#$28; Next screen row (+40 chars)
$4F9Ca9 1dlda#$1d; Write bottom-left tile
$4F9E91 49sta(zp_p_tmp_lo),y
$4FA0c8iny
$4FA1a9 1elda#$1e; Write bottom-right tile
$4FA391 49sta(zp_p_tmp_lo),y
$4FA568pla
$4FA6aatax
$4FA7a9 00lda#$00; Clear flag: don't stamp this car again
$4FA99d 34 09statbl_enemy_car_fresh_flag,x
$4FAC4c 18 4fjmpb_4F18
$4FAF.byte$00
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
; Per-frame finalizer: last three housekeeping calls before looping back.
;
; Runs at the very end of every game frame, after recoil has been applied.
; Draws the car-overtake tile stamp if the player jumped over a type-4 NPC,
; detects any remaining NPC-vs-NPC collisions (X/Y registers preserved),
; syncs the loop pace to keyboard input, then unconditionally jumps back to
; the top of main_loop.
;
; Inputs: None (reads global game state)
; Outputs: None
; Side Effects: May stamp screen RAM, trigger NPC collision, stall on input
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
main_loop_finalize_and_repeat
$4FB020 04 4fjsrdraw_car_overtake_mark; Draw 2x2 tile stamp if player jumped over a type-4 NPC car this frame ; x-ref: $4ED0
$4FB320 e0 3ajsrdetect_npc_car_collision_preserve_xy; Detect NPC-vs-NPC car collisions (X/Y registers preserved by wrapper)
$4FB620 39 52jsrsync_to_keypress; Sync loop pace to keyboard: stall if no key held, else return immediately
$4FB94c 09 18jmpmain_loop; Loop unconditionally back to top of main_loop
$4FBC.fill68, $00
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
; Restores game variables from double buffers.
; This routine copies game state data from back buffers ($0A00/$0B00 or $0C00/$0D00)
; into the active variables pages ($0800/$0900). It chooses which buffer to pull
; from based on player/turn states in $0F00 and $0F01 (useful for 2-player modes).
;
; Inputs: $0F00, $0F01
; Outputs: None
; Side Effects: Overwrites $0800-$09FF memory region.
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
$5000earestore_game_varsnop; x-ref: $170C
$5001eanop
$5002eanop
$5003ad 00 0fldanumber_of_players
$5006c9 02cmp#$02
$5008f0 12beqb_501C
$500Aa2 00b_500Aldx#$00; x-ref: $5021
$500Cbd 00 0ab_500Cldaf_0A00,x; x-ref: $5019
$500F9d 00 08stalevel_nr,x
$5012bd 00 0bldaf_0B00,x
$50159d 00 09staf_0900,x
$5018e8inx
$5019d0 f1bneb_500C
$501B60rts
$501Cad 01 0fb_501Cldacurrent_player_nr; x-ref: $5008
$501Fc9 01cmp#$01
$5021f0 e7beqb_500A
$5023a2 00ldx#$00
$5025bd 00 0cb_5025ldaf_0C00,x; x-ref: $5032
$50289d 00 08stalevel_nr,x
$502Bbd 00 0dldaf_0D00,x
$502E9d 00 09staf_0900,x
$5031e8inx
$5032d0 f1bneb_5025
$503460rts
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
; Initializes the player's turn by setting Y position and flashing the
; \"PLAYER X\" banner on screen before clearing it.
;
; Inputs: A (initial player sprite Y position), current_player_nr (1 or 2)
; Outputs: Sprite 0 Y Pos updated
; Side Effects: Draws \"PLAYER X\" on screen, busy waits, then clears it.
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
set_player_y_and_draw_player_row
$50358d 01 d0sta$d001; Store A into Sprite 0 Y pos ; x-ref: $174D Sprite 0 Y Pos
$5038a2 00ldx#$00
$503Abd f0 50b_503Aldatxt_player,x; x-ref: $5048
$503D9d 00 05staSCREEN_RAM_R6C16,x
$5040a9 07lda#VicIIColors.YELLOW
$50429d 00 d9staCOLOR_RAM_R6C16,x
$5045e8inx
$5046e0 08cpx#$08
$5048d0 f0bneb_503A
$504Aad 01 0fldacurrent_player_nr
$504D18clc
$504E69 30adc#$30
$50508d 07 05staSCREEN_RAM_R6C23
$5053a9 04lda#$04; Busy wait delay loop
$505585 49stazp_p_tmp_lo
$5057a2 00b_5057ldx#$00; x-ref: $5063
$5059a0 00b_5059ldy#$00; x-ref: $505F
$505B88b_505Bdey; x-ref: $505C
$505Cd0 fdbneb_505B
$505Ecadex
$505Fd0 f8bneb_5059
$5061c6 49deczp_p_tmp_lo
$5063d0 f2bneb_5057
$5065a2 00ldx#$00
$5067a9 20b_5067lda#$20; Clear banner with spaces ; x-ref: $5078
$50699d 00 05staSCREEN_RAM_R6C16,x
$506Cac 03 08ldyseason_nr
$506Fb9 7c 16ldatbl_text_color_seasons,y; One byte per season (0=Summer, 1=Autumn, 2=Winter, 3=Spring)
$50729d 00 d9staCOLOR_RAM_R6C16,x
$5075e8inx
$5076e0 08cpx#$08
$5078d0 edbneb_5067
$507A60rts
$507Bad 00 0fj_507Bldanumber_of_players; x-ref: $48B8
$507Ec9 02cmp#$02
$5080f0 03beqb_5085
$50824c aa 50jmpj_50AA
$50854c 75 51b_5085jmpj_5175; x-ref: $5080
; dead code
$5088.byte$c9, $01, $f0, $19
$508Ca9 01j_508Clda#$01; x-ref: $512D, $519A
$508E8d 01 0fstacurrent_player_nr
$5091a2 00j_5091ldx#$00; x-ref: $50CF
$5093bd 00 08b_5093ldalevel_nr,x; x-ref: $50A0
$50969d 00 0cstaf_0C00,x
$5099bd 00 09ldaf_0900,x
$509C9d 00 0dstaf_0D00,x
$509Fe8inx
$50A0d0 f1bneb_5093
$50A24c 0c 17jmpinit_level_screen
$50A5a9 02j_50A5lda#$02; x-ref: $5152, $51BB
$50A78d 01 0fstacurrent_player_nr
$50AAa2 00j_50AAldx#$00; x-ref: $5082, $50C5, $50CD
$50ACbd 00 08b_50ACldalevel_nr,x; x-ref: $50B9
$50AF9d 00 0astaf_0A00,x
$50B2bd 00 09ldaf_0900,x
$50B59d 00 0bstaf_0B00,x
$50B8e8inx
$50B9d0 f1bneb_50AC
$50BB4c 0c 17jmpinit_level_screen
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
; Saves the active player's variables into their backup buffers.
; Player 1 uses $0A00/$0B00, Player 2 uses $0C00/$0D00.
;
; Inputs: number_of_players, current_player_nr
; Outputs: Backup buffers updated
; Side Effects: Copies 2 pages of memory
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
switch_active_player_state
$50BEad 00 0fldanumber_of_players; Check if 2-player game ; x-ref: $16A9
$50C1c9 02cmp#$02
$50C3f0 03beqb_50C8
$50C54c aa 50jmpj_50AA
$50C8ad 01 0fb_50C8ldacurrent_player_nr; x-ref: $50C3
$50CBc9 01cmp#$01
$50CDf0 dbbeqj_50AA
$50CF4c 91 50jmpj_5091
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
; Copies a single character from the HUD text data to screen RAM row 1.
;
; Inputs: X (character index)
; Outputs: Screen RAM at $0428,X
; Side Effects: Updates one character of the HUD text on screen.
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
$50D2bd 38 80copy_hud_text_rowldaf_8038,x; Copy 1 byte from $8038+X (HUD row text under BASIC ROM) to $0428+X (screen row 1) ; x-ref: $1711
$50D59d 28 04staSCREEN_RAM_R1C0,x
$50D860rts
; dead code
$50D9.byte$ad, $00, $0f, $c9, $02, $f0, $03, $4c
$50E1.byte$03, $18, $ad, $01, $0f, $c9, $01, $f0
$50E9.byte$f6, $a2, $00, $4c, $f8, $50, $08
.encode
.enc"screen"
$50F0txt_player.text"PLAYER ", $ff; x-ref: $503A
.endencode
$50F9.byte$49, $00, $00, $ff, $49, $33, $ff
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
; Handles a scroll direction change event, triggered from the countdown/wait
; loop at $51E6 once it expires. It checks two state variables to decide how
; to swap the map scroll buffers, then reloads the game level via s170C.
;
; $0F00 = current scroll mode (must be $02 = "switching direction" to act)
; $0F01 = current scroll direction ($01 = scrolling up/reverse, $02 = forward)
;
; If $0F00 != $02: bail out immediately to j1803 (re-init video).
;
; If $0F00 == $02, four paths based on $0F01 + pending car data:
;
; PATH A ($0F01 != $01, pending cars at $0A22/$0A23):
; Set $0F01 = $01, copy work buffer $0800 -> $0C00,
; copy car table $0900 -> $0D00, then reload level (s170C).
;
; PATH B ($0F01 != $01, pending cars at $0A22/$0A23 absent):
; Copy work buffer $0800 -> $0A00,
; copy car table $0900 -> $0B00, then reload level (s170C).
; Set $0F01 = $02.
;
; PATH C ($0F01 == $01, pending cars at $0C22/$0C23):
; Copy work buffer $0800 -> $0A00,
; copy car table $0900 -> $0B00, then reload level (s170C).
;
; PATH D ($0F01 == $01, no pending cars):
; Set $0F01 = $01, copy work buffer $0800 -> $0C00,
; copy car table $0900 -> $0D00, then reload level (s170C).
;
; In all active paths, the 256-byte buffers are fully copied via a DEX/BNE loop.
;
; Inputs: $0F00 = scroll mode flag; $0F01 = direction; $0A22/$0A23, $0C22/$0C23
; = pending NPC car presence flags; $0800, $0900 = source work buffers
; Outputs: $0A00/$0B00 or $0C00/$0D00 = updated scroll/car buffers;
; $0F01 = updated direction state
; Side Effects: Calls s170C (restore_game_vars + level reload), re-entering the
; main game flow from the top of the level
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
handle_scroll_direction_switch
$5100ad 00 0fldanumber_of_players; $02 = scroll direction-change mode; anything else = bail ; x-ref: $51FC
$5103c9 02cmp#$02
$5105f0 03beqb_510A
$51074c 03 18jmpgame_init_and_loop
$510Aad 01 0fb_510Aldacurrent_player_nr; $01 = reverse direction, $02 = forward direction ; x-ref: $5105
$510Dc9 01cmp#$01
$510Ff0 0dbeqb_511E
$5111ad 23 0aldabuf_a_pending_cars_hi; check if any pending NPC cars in secondary lane buffer
$5114d0 15bneb_512B
$5116ad 22 0aldabuf_a_pending_cars_lo
$5119d0 10bneb_512B
$511B4c 03 18jmpgame_init_and_loop
$511Ead 23 0cb_511Eldabuf_c_pending_cars_hi; direction is $01: check $0C22/$0C23 pending cars instead ; x-ref: $510F
$5121d0 2dbneb_5150
$5123ad 22 0cldabuf_c_pending_cars_lo
$5126d0 28bneb_5150
$51284c 03 18jmpgame_init_and_loop
$512Ba2 00b_512Bldx#$00; PATH A: pending cars present in lane A; set dir=$01, swap to C/D buffers ; x-ref: $5114, $5119
$512D4c 8c 50jmpj_508C
; dead code
$5130.byte$9d, $00, $0c, $bd, $00, $09, $9d, $00
$5138.byte$0d, $e8, $d0, $f1, $a2, $00, $4c, $a5
$5140.byte$50, $9d, $00, $08, $bd, $00, $0b, $9d
$5148.byte$00, $09, $e8, $d0, $f1, $4c, $0c, $17
$5150a2 00b_5150ldx#$00; PATH C: direction $01, pending cars in C lane; swap to A/B buffers ; x-ref: $5121, $5126
$51524c a5 50jmpj_50A5
; dead code
$5155.byte$9d, $00, $0a, $bd, $00, $09, $9d, $00
$515D.byte$0b, $e8, $d0, $f1, $a2, $00, $4c, $8c
$5165.byte$50, $9d, $00, $08, $bd, $00, $0d, $9d
$516D.byte$00, $09, $e8, $d0, $f1, $4c, $0c, $17
$5175ad 01 0fj_5175ldacurrent_player_nr; x-ref: $5085
$5178c9 01cmp#$01
$517Af0 21beqb_519D
$517Cad 23 0aldabuf_a_pending_cars_hi
$517Fd0 19bneb_519A
$5181ad 22 0aldabuf_a_pending_cars_lo
$5184d0 14bneb_519A
$5186a2 00ldx#$00
$5188bd 00 08b_5188ldalevel_nr,x; x-ref: $5195
$518B9d 00 0cstaf_0C00,x
$518Ebd 00 09ldaf_0900,x
$51919d 00 0dstaf_0D00,x
$5194e8inx
$5195d0 f1bneb_5188
$51974c 0c 17jmpinit_level_screen
$519A4c 8c 50b_519Ajmpj_508C; x-ref: $517F, $5184
$519Dad 23 0cb_519Dldabuf_c_pending_cars_hi; x-ref: $517A
$51A0d0 19bneb_51BB
$51A2ad 22 0cldabuf_c_pending_cars_lo
$51A5d0 14bneb_51BB
$51A7a2 00ldx#$00
$51A9bd 00 08b_51A9ldalevel_nr,x; x-ref: $51B6
$51AC9d 00 0astaf_0A00,x
$51AFbd 00 09ldaf_0900,x
$51B29d 00 0bstaf_0B00,x
$51B5e8inx
$51B6d0 f1bneb_51A9
$51B84c 0c 17jmpinit_level_screen
$51BB4c a5 50b_51BBjmpj_50A5; x-ref: $51A0, $51A5
$51BE20 71 3ej_51BEjsrreset_voice1_state; x-ref: $51DE
$51C1a9 00lda#$00
$51C38d 06 d4sta$d406; Voice 1: Sustain / Release Cycle Control
$51C6a9 1dlda#$1d
$51C88d 05 d4sta$d405; Voice 1: Attack / Decay Cycle Control
$51CBa9 01lda#$01
$51CD8d 01 d4sta$d401; Voice 1: Frequency Control - High-Byte
$51D0a9 12lda#$12
$51D28d 00 d4sta$d400; Voice 1: Frequency Control - Low-Byte
$51D5a9 81lda#$81
$51D78d 04 d4sta$d404; Voice 1: Control Register
$51DA60rts
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
; Sets sprite 0's image pointer to the provided frame and plays a noise explosion.
;
; Inputs: A = Sprite frame pointer value
; Outputs: None
; Side Effects: Updates sprite_ptr_0, resets and configures SID Voice 1 for noise
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
set_sprite0_and_play_noise
$51DB8d f8 07stasprite_ptr_0; Set sprite 0 frame pointer ; x-ref: $4846
$51DE4c be 51jmpj_51BE; Play noise effect on Voice 1
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
; Polls the joystick for a UP movement with a timeout loop.
; If UP is pressed (bit 0 is 0), or if the timeout expires, it proceeds
; to handle the scroll direction switch.
;
; Inputs: joy_state
; Outputs: None
; Side Effects: Delays execution, calls handle_scroll_direction_switch
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
poll_joy_for_scroll_switch
$51E1a9 20lda#$20; Set timeout to $20 ; x-ref: $1E0E
$51E38d da 08stajoy_poll_timeout
$51E6a2 00b_51E6ldx#$00; x-ref: $51FA
$51E8a0 00b_51E8ldy#$00; x-ref: $51F5
$51EAad f5 00b_51EAlda@w zp_joy_state; Read joystick state ; x-ref: $51F2
$51ED29 01and#$01; Check bit 0 (UP)
$51EFf0 0bbeqb_51FC; If 0 (pressed), exit loop
$51F188dey
$51F2d0 f6bneb_51EA
$51F4cadex
$51F5d0 f1bneb_51E8
$51F7ce da 08decjoy_poll_timeout; Decrement timeout
$51FAd0 eabneb_51E6
$51FC4c 00 51b_51FCjmphandle_scroll_direction_switch; Proceed to handle scroll direction switch ; x-ref: $51EF
; dead code
$51FF.byte$ff, $ad, $05, $08, $d0, $01, $60, $ae
$5207.byte$06, $08, $a9, $00, $8d, $04, $d4, $8d
$520F.byte$05, $d4, $8d, $06, $d4, $bd, $50, $52
$5217.byte$8d, $01, $d4, $bd, $60, $52, $8d, $00
$521F.byte$d4, $a9, $09, $8d, $05, $d4, $a9, $0f
$5227.byte$8d, $06, $d4, $a9, $11, $8d, $04, $d4
$522F.byte$60
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
; Updates the state of an enemy sprite and triggers a crash sound effect.
; Returns 1 in the accumulator.
;
; Inputs: A = New enemy sprite state, X = Enemy sprite index
; Outputs: A = 1
; Side Effects: Updates tbl_enemy_sprite_state, plays crash SFX
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
set_collision_state_and_play_sfx
$52309d 0c 09statbl_enemy_sprite_state,x; Update enemy state for index X ; x-ref: $3A4F
$523320 d1 3ejsrplay_crash_sfx; Play the crash sound effect
$5236a9 01lda#$01; Return 1 to indicate success/state change
$523860r_5238rts; x-ref: $523D
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
; Main-loop input synchronizer. Called every frame from j4FB0.
;
; Ties the main loop's execution pace to player key input:
; - If any key is currently held (key_scan != $7F): returns immediately,
; allowing the game loop to run at full speed.
; - If no key is held (key_scan == $7F): spins through a full
; press -> release -> press cycle before returning.
;
; The CIA keyboard scanner (j56E2) runs inside the IRQ, so key_scan is
; updated even during the spin-waits — sprite animation continues unaffected.
;
; Phase 1 ($5239): bail immediately if a key is already held
; Phase 2 ($523F): spin until any key is pressed
; Phase 3 ($5245): spin until key is released
; Phase 4 (j5270): spin until key is pressed again, then return
;
; Inputs: key_scan ($C5)
; Outputs: A = key_scan on early exit; undefined on full wait path
; Side Effects: Stalls main loop execution until a fresh keypress cycle
; completes when no key is being held
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
$5239a5 c5sync_to_keypressldazp_key_scan; Phase 1: key already held? Return immediately ; x-ref: $4FB6
$523Bc9 7fcmp#$7f; $7F = no key; wait for release
$523Dd0 f9bner_5238
$523Fa5 c5b_523Fldazp_key_scan; Phase 2: spin until any key pressed ; x-ref: $5243
$5241c9 7fcmp#$7f; $7F = no key; loop until a key is pressed
$5243f0 fabeqb_523F
$5245a5 c5b_5245ldazp_key_scan; Phase 3: spin until key released ; x-ref: $5249
$5247c9 7fcmp#$7f; $7F = no key; wait for release
$5249d0 fabneb_5245
$524B4c 70 52jmpj_5270; Phase 4: wait for second press, then return
$524E.byte$ea, $ea
; posibly dead data. referenced only by dead code
unused_sid_freq_hi_tbl
$5250.byte>$0893, >$099f, >$0acd, >$0b72, >$0cd8
$5255.byte>$0e6b, >$102f, >$1125, >$133f, >$083f
$525A.byte>$0025, >$8845, >$d068, >$fd8c, >$cab3
$525F.byte>$d08c
unused_sid_freq_lo_tbl
$5260.byte<$0893, <$099f, <$0acd, <$0b72, <$0cd8
$5265.byte<$0e6b, <$102f, <$1125, <$133f, <$083f
$526A.byte<$0025, <$8845, <$d068, <$fd8c, <$cab3
$526F.byte<$d08c
$5270a5 c5j_5270ldazp_key_scan; Phase 4: spin until key pressed, return (shared entry point) ; x-ref: $524B, $5274
$5272c9 7fcmp#$7f; $7F = no key; wait for press
$5274f0 fabeqj_5270; Loop while no key
$527660rts
$5277.byte$08, $ff, $00, $ff, $00, $02, $00, $ff
$527F.byte$00, $40, $ff, $00, $ff, $00, $ff, $00
$5287.byte$ff, $00, $ff, $00, $ff, $00, $ff, $00
$528F.byte$ff, $00, $ff, $00, $ff, $00, $ff, $00
$5297.byte$ff, $00, $ff, $00, $ff, $00, $ff, $00
$529F.byte$ff, $00, $ff, $00, $ff, $00, $ff, $00
$52A7.byte$ff, $00, $ff, $00, $ff, $00, $ff, $00
$52AF.byte$ff, $00, $ff, $00, $ff, $00, $ff, $00
$52B7.byte$ff, $00, $ff, $00, $ff, $00, $ff, $00
$52BF.byte$ff, $00, $ff, $00, $ff, $00, $ff, $00
$52C7.byte$ff, $00, $ff, $00, $ff, $00, $ff, $00
$52CF.byte$ff, $00, $ff, $00, $ff, $00, $ff, $00
$52D7.byte$ff, $00, $ff, $00, $ff, $00, $ff, $00
$52DF.byte$ff, $00, $ff, $00, $ff, $00, $ff, $00
$52E7.byte$ff, $00, $ff, $00, $ff, $00, $ff, $00
$52EF.byte$ff, $00, $ff, $00, $ff, $00, $ff, $00
$52F7.byte$ff, $00, $ff, $00, $ff, $00, $ff, $00
$52FF.byte$ff
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
; Handles user input during the main menu / selection screen.
; This routine monitors a specific key press (flagged as $F7 in the keyboard
; matrix byte $C5, likely the F1 key or spacebar) to increment a 2-digit number
; stored in $49 and $4A as ASCII/Screen Code characters. The number cycles
; from '01' up to '16', and wraps back around. It then renders those digits directly
; to Video RAM at $0651 and $0652 to provide visual feedback of the selection
; (e.g., selecting a starting level or difficulty).
;
; Inputs: $C5 (Current Key Pressed)
; Outputs: None
; Side Effects: Modifies $49 (units), $4A (tens), and Video RAM $0651-$0652.
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
handle_menu_selection_input
$5300a5 49ldazp_p_tmp_lo; x-ref: $3FFA
$53028d 52 06staSCREEN_RAM_R14C34
$5305a5 4aldazp_p_tmp_hi
$53078d 51 06staSCREEN_RAM_R14C33
$530Aa5 c5ldazp_key_scan
$530Cc9 f7cmp#$f7; $F7 = %11110111 (bit 3 clear)
$530Ef0 01beqb_5311
$531060rts
$5311ee 01 12b_5311inclevel_nr_self_modifiying; x-ref: $530E
$5314ad 01 12ldalevel_nr_self_modifiying
$5317c9 10cmp#$10
$5319d0 05bneb_5320
$531Ba9 00lda#$00
$531D8d 01 12stalevel_nr_self_modifiying
$5320e6 49b_5320inczp_p_tmp_lo; x-ref: $5319
$5322a5 49ldazp_p_tmp_lo
$5324c9 3acmp#$3a
$5326d0 06bneb_532E
$5328a9 30lda#$30
$532A85 49stazp_p_tmp_lo
$532Ce6 4ainczp_p_tmp_hi
$532Ea5 4ab_532Eldazp_p_tmp_hi; x-ref: $5326
$5330c9 31cmp#$31
$5332d0 0ebneb_5342
$5334a5 49ldazp_p_tmp_lo
$5336c9 37cmp#$37
$5338d0 08bneb_5342
$533Aa9 31lda#$31
$533C85 49stazp_p_tmp_lo
$533Ea9 30lda#$30
$534085 4astazp_p_tmp_hi
$5342a5 49b_5342ldazp_p_tmp_lo; x-ref: $5332, $5338
$53448d 52 06staSCREEN_RAM_R14C34
$5347a5 4aldazp_p_tmp_hi
$53498d 51 06staSCREEN_RAM_R14C33
$534Ca5 c5b_534Cldazp_key_scan; x-ref: $5350
$534Ec9 f7cmp#$f7; $F7 held — wait for release
$5350f0 fabeqb_534C
$535260rts
.encode
.enc"screen"
$5353txt_bonus_10000.text"BONUS 10000", $ff, "@"; x-ref: $5367
.endencode
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
; Displays a "BONUS 10000" message and awards bonus points.
; This routine copies the "BONUS 10000" text to the screen ($0756 area) and colors
; it purple ($04). It then calls the score increment routine twice to award the
; points, performs a nested delay loop to leave the text on-screen momentarily,
; and finally jumps back to the main flow.
;
; Inputs: None
; Outputs: None
; Side Effects: Updates Screen RAM, Color RAM, Score array, and delays execution.
; Bugs: Message says "BONUS 10000", but it actually increases it by 100000
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
$5360a9 00award_bonus_scorelda#$00; x-ref: $157E
$53628d 00 08stalevel_nr
$5365a2 00ldx#$00
$5367bd 53 53b_5367ldatxt_bonus_10000,x; x-ref: $5375
$536A9d 56 07staSCREEN_RAM_R21C14,x
$536Da9 04lda#VicIIColors.PURPLE
$536F9d 56 dbstaCOLOR_RAM_R21C14,x
$5372e8inx
$5373e0 0bcpx#$0b
$5375d0 f0bneb_5367
$537720 a7 15jsrincrement_score_by_50000; BUG: Message says "BONUS 10000", but it actually increments 100,000
$537A20 a7 15jsrincrement_score_by_50000
$537Deanop
$537Eeanop
$537Feanop
$5380eanop
$5381eanop
$5382eanop
$5383a9 08lda#$08
$538585 49stazp_p_tmp_lo
$5387a2 00b_5387ldx#$00; x-ref: $5393
$5389a0 00b_5389ldy#$00; x-ref: $538F
$538B88b_538Bdey; x-ref: $538C
$538Cd0 fdbneb_538B
$538Ecadex
$538Fd0 f8bneb_5389
$5391c6 49deczp_p_tmp_lo
$5393d0 f2bneb_5387
$53954c 81 15jmpb_1581
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
; SFX Engine Voice 1 (Engine Sound) Handler
;
; Initializes and modulates Voice 1 on the SID to create a continuous sound
; while sfx_voice_1_en is non-zero. When zeroed, it resets the local state.
;
; Inputs: sfx_voice_1_en ($0805) - Enable flag for the Voice 1 SFX
; Outputs: sfx_voice_1_state ($7080), sfx_voice_1_freq_lo ($7081),
; sfx_voice_1_freq_mod ($7082)
; Side Effects: Updates Voice 1 registers (Frequency, Control, Attack/Decay, Sustain/Release)
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
$5398ad 05 08irq_handler_musicldaplayer_is_jumping; x-ref: $1291, $1296
$539Bf0 56beqsfx_voice_1_reset; If sf_voice_1_en is clear, reset state
$539Dae 80 70ldxsfx_voice_1_state
$53A0d0 21bnesfx_voice_1_modulate; If state > 0 (already playing), branch to modulation
$53A28e 81 70stxsfx_voice_1_freq_lo; Clear internal freq_lo component
$53A58e 00 d4stx$d400; Clear SID Voice 1 frequency low; Voice 1: Frequency Control - Low-Byte
$53A88e 01 d4stx$d401; Clear SID Voice 1 frequency high; Voice 1: Frequency Control - High-Byte
$53AB8e 05 d4stx$d405; Voice 1: Attack / Decay Cycle Control
$53AE8e 04 d4stx$d404; Voice 1: Control Register
$53B1e8inx; Set state to 1 (initialized)
$53B28e 80 70stxsfx_voice_1_state
$53B5e8inx
$53B68e 82 70stxsfx_voice_1_freq_mod; Set mod factor to 2
$53B9a9 f4lda#$f4; Sustain = $F, Release = $4
$53BB8d 06 d4sta$d406; Voice 1: Sustain / Release Cycle Control
$53BEa9 11lda#$11; Gate ON + Triangle Wave
$53C08d 04 d4sta$d404; Voice 1: Control Register
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
; Modulates the frequency of Voice 1 by adding the frequency modifier.
; If the frequency modifier is negative (falling pitch), it handles the bounce effect.
;
; Inputs: sfx_voice_1_state, sfx_voice_1_freq_lo, sfx_voice_1_freq_mod
; Outputs: A = new frequency mod or voice state
; Side Effects: May gate off Voice 1 if modulation ends
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
$53C330 2bsfx_voice_1_modulatebmib_53F0; Skip modulation if state is $80 (releasing) ; x-ref: $53A0
$53C5ad 81 70ldasfx_voice_1_freq_lo
$53C818clc
$53C96d 82 70adcsfx_voice_1_freq_mod; Add mod factor to frequency low byte
$53CCd0 1cbnesfx_voice_1_store_freq
$53CEad 82 70ldasfx_voice_1_freq_mod
$53D110 0cbplsfx_voice_1_bounce
$53D3a9 10lda#$10
$53D58d 04 d4sta$d404; Gate OFF Voice 1; Voice 1: Control Register
$53D8a9 80lda#$80
$53DA8d 80 70stasfx_voice_1_state; Set state to releasing ($80)
$53DDd0 11bneb_53F0
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
; Reverses the direction of the frequency modulation to create a bounce effect.
; The modifier is negated and the frequency wraps around to $FE.
;
; Inputs: sfx_voice_1_freq_mod
; Outputs: sfx_voice_1_freq_mod
; Side Effects: Updates frequency modifier, prepares for store
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
$53DFa9 00sfx_voice_1_bouncelda#$00; x-ref: $53D1
$53E138sec
$53E2ed 82 70sbcsfx_voice_1_freq_mod; Negate the frequency modifier
$53E58d 82 70stasfx_voice_1_freq_mod; Store negated modifier (reverse direction)
$53E8a9 felda#$fe; Set frequency to wrap-around value ($FE)
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
; Stores the newly calculated frequency for Voice 1 into memory and the SID.
; The high byte of the Voice 1 frequency is updated directly.
;
; Inputs: A = new frequency value
; Outputs: sfx_voice_1_freq_lo
; Side Effects: Updates SID Voice 1 frequency high register ($D401)
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
sfx_voice_1_store_freq
$53EA8d 81 70stasfx_voice_1_freq_lo; Update internal frequency low byte state ; x-ref: $53CC
$53ED8d 01 d4sta$d401; Update SID Voice 1 frequency high; Voice 1: Frequency Control - High-Byte
$53F04c d0 54b_53F0jmpj_54D0; Chain to next IRQ routine ; x-ref: $53C3, $53DD, $53F8
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
; Resets the Voice 1 SFX state to 0, effectively turning off the sound effect
; processing for this voice.
;
; Inputs: None
; Outputs: sfx_voice_1_state = 0
; Side Effects: Clears the Voice 1 state variable
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
$53F3a9 00sfx_voice_1_resetlda#$00; Clear Accumulator ; x-ref: $539B
$53F58d 80 70stasfx_voice_1_state; Reset Voice 1 state to 0
$53F8f0 f6beqb_53F0
$53FA00brk
$53FB00brk
$53FC00brk
$53FD00brk
$53FE00brk
$53FF00brk
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
; IRQ-driven melody player for SID Voices 2 & 3.
;
; Called every IRQ frame. Steps through a looping note sequence in the melody
; table at $5500 using a self-modifying pointer ($5445/$5446). A rate-limiting
; timer controls the pace: 8 ticks per note, then a 3-tick gate-off gap.
; Notes alternate between Voice 2 and Voice 3 so the prior note's release
; envelope can finish on one voice while the next note starts on the other.
;
; Table encoding:
; $30 = rest (silent tick, exit immediately)
; $00-$2F = pitch index into sid_freq2_lo/hi_tbl
; >= $40 = end-of-sequence; wrap pointer back to $5500
;
; Key $BF toggles playback on/off; pressing it immediately gates both voices.
; Waveform: triangle ($21), A=0/D=0, Sustain=$B, Release=$A.
;
; Inputs: $C5 (key scan), sfx_prev_key, sfx_v23_en, sfx_v23_timer,
; sfx_v23_idx, sfx_v23_toggle; self-mod melody ptr at $5445/$5446
; Outputs: SID Voice 2 regs ($D407-$D40D), Voice 3 regs ($D40E-$D414)
; Side Effects: Advances self-modifying melody pointer through $5500+;
; updates sfx_prev_key, sfx_v23_en, sfx_v23_timer,
; sfx_v23_idx, sfx_v23_toggle
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
$5400a5 c5irq_handler_voice23ldazp_key_scan; Load current key pressed ; x-ref: $54DB, $54E3
$5402cd 26 54cmpsfx_prev_key
$5405f0 17beqb_541E; If key unchanged, skip to processing
$54078d 26 54stasfx_prev_key
$540Ac9 bfcmp#$bf; Check if F5 was pressed
$540Cd0 10bneb_541E
$540Ea9 20lda#$20
$54108d 0b d4sta$d40b; Gate OFF Voice 2; Voice 2: Control Register
$54138d 12 d4sta$d412; Gate OFF Voice 3; Voice 3: Control Register
$5416ad 27 54ldasfx_v23_en; Toggle the enable flag
$541949 01eor#$01
$541B8d 27 54stasfx_v23_en
$541Ead 27 54b_541Eldasfx_v23_en; x-ref: $5405, $540C
$5421d0 0dbneb_5430; If not enabled, skip processing
$54234c e2 56b_5423jmpscan_keyboard_joystick; x-ref: $5433, $5461, $5488, $54A0
$5426sfx_prev_key.byte$40; x-ref: $5402, $5407
$5427sfx_v23_en.byte$01; x-ref: $5416, $541B, $541E
$5428sfx_v23_timer.byte$03; x-ref: $5430, $5441, $54A7
$5429sfx_v23_idx.byte$01; x-ref: $5435, $543C, $54A2
$542Asfx_v23_toggle.byte$00; x-ref: $546B, $54AC, $54B3, $54BC
$542B00.byte$00
$542Cff.byte$ff
$542D00.byte$00
$542Eff.byte$ff
$542F00.byte$00
$5430ce 28 54b_5430decsfx_v23_timer; Decrement wait timer ; x-ref: $5421
$5433d0 eebneb_5423; If timer hasn't expired, exit
$5435ad 29 54ldasfx_v23_idx; Check phase: 0=play next note, 1=gate-off
$5438f0 68beqb_54A2; idx=1: enter gate-off phase for current voice
$543Aa0 00ldy#$00
$543C8c 29 54stysfx_v23_idx; Reset to play phase (idx=0)
$543Fa9 08lda#$08
$54418d 28 54stasfx_v23_timer; 8 IRQ ticks per note
melody_lo =*+$01 ; x-ref: $5447, $545A
melody_hi =*+$02 ; x-ref: $544C, $5455
$5444ad 00 55b_5444ldamelody_tbl; Self-modifying LDA; ptr lo=$5445, hi=$5446 walk melody table ; x-ref: $545D
$5447ee 45 54incmelody_lo; Advance melody ptr low byte
$544Ad0 03bneb_544F
$544Cee 46 54incmelody_hi; Page overflow: advance ptr high byte
$544Fc9 40b_544Fcmp#$40; >= $40 = end-of-sequence sentinel ; x-ref: $544A
$545190 0cbccb_545F
$5453a9 55lda#$55; Reset ptr hi to $55 (back to $5500)
$54558d 46 54stamelody_hi
$5458a9 00lda#$00
$545A8d 45 54stamelody_lo; Reset ptr lo to $00
$545Df0 e5beqb_5444; Z set by lda #$00; always branches — re-read first note
$545Fc9 30b_545Fcmp#$30; $30 = rest note ; x-ref: $5451
$5461f0 c0beqb_5423; Rest: exit without playing
$5463aatax; Load pitch index into X
$5464bd 80 56ldasid_freq_hi_tbl,x; Read frequency high byte into A
$5467a8tay
$5468bd 40 56ldasid_freq_lo_tbl,x; Read frequency low byte into A
$546Bae 2a 54ldxsfx_v23_toggle; Check voice toggle flag
$546Ef0 1abeqb_548A; If 0, use Voice 3. If !0, use Voice 2
$5470a2 00ldx#$00
$54728e 0b d4stx$d40b; Voice 2: Control Register
$54758d 07 d4sta$d407; Voice 2: Frequency Control - Low-Byte
$54788c 08 d4sty$d408; Voice 2: Frequency Control - High-Byte
$547B8e 0c d4stx$d40c; Voice 2: Attack / Decay Cycle Control
$547Ea9 balda#$ba
$54808d 0d d4sta$d40d; Voice 2: Sustain / Release Cycle Control
$5483a9 21lda#$21
$54858d 0b d4sta$d40b; Voice 2: Control Register
$5488d0 99bneb_5423
$548A8e 12 d4b_548Astx$d412; x-ref: $546E Voice 3: Control Register
$548D8d 0e d4sta$d40e; Voice 3: Frequency Control - Low-Byte
$54908c 0f d4sty$d40f; Voice 3: Frequency Control - High-Byte
$54938e 13 d4stx$d413; Voice 3: Attack / Decay Cycle Control
$5496a9 balda#$ba
$54988d 14 d4sta$d414; Voice 3: Sustain / Release Cycle Control
$549Ba9 21lda#$21
$549D8d 12 d4sta$d412; Voice 3: Control Register
$54A0d0 81bneb_5423
$54A2ee 29 54b_54A2incsfx_v23_idx; x-ref: $5438
$54A5a9 03lda#$03
$54A78d 28 54stasfx_v23_timer; 3-tick release gap between notes
$54AAa9 20lda#$20; %00100000 = triangle wave, gate OFF
$54ACae 2a 54ldxsfx_v23_toggle; Which voice was just playing?
$54AFf0 0bbeqb_54BC; toggle=0: V3 was playing → gate off V3
$54B1a2 00ldx#$00
$54B38e 2a 54stxsfx_v23_toggle; Clear toggle → next note plays on V3
$54B68d 0b d4sta$d40b; Voice 2: Control Register
$54B94c e2 56b_54B9jmpscan_keyboard_joystick; x-ref: $54C2
$54BCee 2a 54b_54BCincsfx_v23_toggle; Set toggle (non-zero) → next note plays on V2 ; x-ref: $54AF
$54BF8d 12 d4sta$d412; Gate off Voice 3 (it was playing); Voice 3: Control Register
$54C2d0 f5bneb_54B9
$54C4.fill12, $00
$54D0ad 00 d0j_54D0lda$d000; x-ref: $53F0 Sprite 0 X Pos
$54D3c9 0ccmp#$0c
$54D590 07bccb_54DE
$54D7c9 18cmp#$18
$54D990 0bbccb_54E6
$54DB4c 00 54jmpirq_handler_voice23
$54DEa9 ffb_54DElda#$ff; x-ref: $54D5
$54E08d 00 d0b_54E0sta$d000; x-ref: $54E8 Sprite 0 X Pos
$54E34c 00 54jmpirq_handler_voice23
$54E6a9 18b_54E6lda#$18; x-ref: $54D9
$54E8d0 f6bneb_54E0
$54EA.fill22, $00
$5500melody_tbl.byte$30, $12, $30, $0e, $10, $12, $30, $0e; x-ref: $5444
$5508.byte$12, $30, $10, $0e, $30, $09, $30, $0a
$5510.byte$0b, $0e, $10, $13, $30, $0e, $10, $0e
$5518.byte$10, $13, $30, $10, $30, $12, $0e, $10
$5520.byte$12, $30, $0e, $12, $30, $10, $0e, $30
$5528.byte$09, $30, $13, $30, $10, $30, $0e, $30
$5530.byte$0b, $30, $0b, $0b, $30, $02, $04, $07
$5538.byte$06, $30, $12, $0e, $10, $12, $30, $0e
$5540.byte$12, $30, $10, $0e, $30, $09, $30, $0a
$5548.byte$0b, $0e, $10, $13, $30, $0e, $10, $0e
$5550.byte$10, $13, $30, $10, $30, $0c, $30, $0d
$5558.byte$30, $13, $30, $10, $30, $0e, $30, $09
$5560.byte$30, $13, $30, $30, $12, $30, $30, $13
$5568.fill12, $30
$5574.byte$13, $10, $0e, $10, $0c, $10, $0b, $10
$557C.byte$09, $10, $07, $10, $05, $10, $0e, $0c
$5584.byte$0e, $0e, $0c, $0e, $0b, $0e, $09, $0e
$558C.byte$07, $0e, $05, $0e, $04, $0e, $0c, $0b
$5594.byte$0c, $0c, $0b, $0c, $09, $0c, $07, $0c
$559C.byte$05, $0c, $04, $0c, $03, $0c, $0b, $09
$55A4.byte$0b, $0b, $09, $0b, $08, $0b, $06, $0b
$55AC.byte$04, $0b, $02, $0b, $00, $0b, $09, $07
$55B4.byte$09, $0e, $0c, $0c, $10, $0e, $0e, $13
$55BC.byte$12, $13, $0e, $0b, $07, $09, $0b, $0c
$55C4.byte$0e, $10, $0e, $0c, $0b, $09, $0b, $07
$55CC.byte$06, $07, $09, $02, $06, $09, $0c, $0b
$55D4.byte$09, $0b, $07, $09, $0b, $0e, $0c, $0c
$55DC.byte$10, $0e, $0e, $13, $12, $13, $0e, $0b
$55E4.byte$07, $09, $0b, $04, $0e, $0c, $0b, $09
$55EC.byte$07, $02, $07, $06, $07, $0b, $0e, $13
$55F4.byte$0e, $0b, $07, $0b, $0e, $11, $0e, $0b
$55FC.byte$07, $0b, $0e, $10, $0c, $09, $06, $09
$5604.byte$0c, $0e, $0b, $07, $04, $07, $0b, $0c
$560C.byte$09, $06, $02, $06, $09, $0c, $0b, $09
$5614.byte$07, $0b, $0e, $13
$5618.fill8, $30
$5620.byte$80
$5621.byte$00, $ff, $00, $ff, $00, $ff, $00, $ff
$5629.byte$00, $ff, $00, $ff, $00, $ff, $00, $ff
$5631.byte$00, $ff, $00, $ff, $00, $ff, $00, $ff
$5639.byte$00, $ff, $00, $02, $00, $ff, $00
$5640sid_freq_lo_tbl.byte<$0893, <$0915, <$099f, <$0a3c, <$0acd; x-ref: $5468
$5645.byte<$0b72, <$0c20, <$0cd8, <$0d9c, <$0e6b
$564A.byte<$0f66, <$102f, <$1125, <$122a, <$133f
$564F.byte<$1464, <$159a, <$16e3, <$183f, <$19b1
$5654.byte<$1b38, <$1cd6, <$1e8d, <$205e, <$224b
$5659.byte<$2455, <$267e, <$28c8, <$2b34, <$2dc6
$565E.byte<$307f, <$3361, <$366f, <$39ac, <$3d7e
$5663.byte<$40bc, <$4495, <$0000, <$0000, <$0000
$5668.byte<$0000, <$0000, <$0000, <$0000, <$0000
$566D.byte<$0000, <$0000, <$0000, <$0000, <$0000
$5672.byte<$0000, <$0000, <$0000, <$0000, <$0000
$5677.byte<$0000, <$0000, <$0000, <$0000, <$0000
$567C.byte<$0000, <$0000, <$0000, <$0000
$5680sid_freq_hi_tbl.byte>$0893, >$0915, >$099f, >$0a3c, >$0acd; x-ref: $5464
$5685.byte>$0b72, >$0c20, >$0cd8, >$0d9c, >$0e6b
$568A.byte>$0f66, >$102f, >$1125, >$122a, >$133f
$568F.byte>$1464, >$159a, >$16e3, >$183f, >$19b1
$5694.byte>$1b38, >$1cd6, >$1e8d, >$205e, >$224b
$5699.byte>$2455, >$267e, >$28c8, >$2b34, >$2dc6
$569E.byte>$307f, >$3361, >$366f, >$39ac, >$3d7e
$56A3.byte>$40bc, >$4495, >$0000, >$0000, >$0000
$56A8.byte>$0000, >$0000, >$0000, >$0000, >$0000
$56AD.byte>$0000, >$0000, >$0000, >$0000, >$0000
$56B2.byte>$0000, >$0000, >$0000, >$0000, >$0000
$56B7.byte>$0000, >$0000, >$0000, >$0000, >$0000
$56BC.byte>$0000, >$0000, >$0000, >$0000
; Scans CIA1 keyboard matrix by driving Port B (rows) and reading Port A (cols).
; A = DDR-B mask (row to drive). Returns stable column byte in A (debounced).
$56C08d 03 dccia1_scan_rowsta$dc03; x-ref: $56EE, $5702, $5714 CIA1: Data Direction Register B
$56C3a9 00lda#$00
$56C58d 02 dcsta$dc02; CIA1: Data Direction Register A
$56C8ad 00 dcb_56C8lda$dc00; x-ref: $56CE CIA1: Data Port Register A
$56CBcd 00 dccmp$dc00; CIA1: Data Port Register A
$56CEd0 f8bneb_56C8
$56D060rts
; Scans CIA1 keyboard matrix by driving Port A (cols) and reading Port B (rows).
; A = DDR-A mask (column to drive). Returns stable row byte in A (debounced).
$56D18d 02 dccia1_scan_colsta$dc02; x-ref: $56F7, $570B, $5728 CIA1: Data Direction Register A
$56D4a9 00lda#$00
$56D68d 03 dcsta$dc03; CIA1: Data Direction Register B
$56D9ad 01 dcb_56D9lda$dc01; x-ref: $56DF CIA1: Data Port Register B
$56DCcd 01 dccmp$dc01; CIA1: Data Port Register B
$56DFd0 f8bneb_56D9
$56E160rts
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
; Custom keyboard/joystick scanner. Replaces part of the KERNAL's standard
; keyboard scan by directly driving the CIA1 matrix to read joystick port 2
; and specific keyboard rows/columns. Builds a combined key code and a
; joystick-format direction byte, then tail-calls into the KERNAL at $EA7E.
;
; Inputs: CIA1 hardware registers ($DC00-$DC03)
; Outputs: key_scan ($C5) = current key matrix code ($7F = no key)
; joy_state ($F5) = joystick state (active-low bits 0-4: U/D/L/R/Fire)
; Side Effects: Modifies CIA1 DDRs; tail-calls KERNAL $EA7E (no RTS)
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
scan_keyboard_joystick
$56E2a2 04ldx#$04; Clear CIA1 ports $DC00-$DC03 (via $DBFF+X, X=4..1) ; x-ref: $5423, $54B9
$56E4a9 00lda#$00
$56E69d ff dbb_56E6staf_DBFF,x; x-ref: $56EA
$56E9cadex
$56EAd0 fabneb_56E6
$56ECa9 10lda#$10; Drive row 4 → read joystick fire + key row
$56EE20 c0 56jsrcia1_scan_row
$56F109 7fora#%01111111; Keep bit 7 (fire); idle bits high
$56F385 c5stazp_key_scan; First scan result → key_scan
$56F5a9 01lda#$01; Drive column 0
$56F720 d1 56jsrcia1_scan_col
$56FA09 87ora#%10000111; Mask unused bits 3-6
$56FC25 c5andzp_key_scan; Combine row + column scans → final key code
$56FE85 c5stazp_key_scan; Final combined key state → key_scan ($7F = no key)
$5700a9 00lda#$00; Scan full row 0 to check for any key
$570220 c0 56jsrcia1_scan_row
$5705c9 ffcmp#$ff; Key pressed → skip joystick decode
$5707d0 31bneb_573A
$5709a9 00lda#$00; Scan full column 0
$570B20 d1 56jsrcia1_scan_col
$570Ec9 ffcmp#$ff
$5710d0 28bneb_573A; Key pressed → skip joystick decode
$5712a9 04lda#$04; Drive row 2 for direction bits
$571420 c0 56jsrcia1_scan_row
$5717aatax
$571809 efora#$ef; Isolate bit 4 (joy right)
$571A85 f5stazp_joy_state
$571C8atxa
$571D4alsra; Shift raw bits right ×3 for bits 2-3
$571E4alsra
$571F4alsra
$572009 f3ora#%11110011; Isolate bits 2-3 (joy up/down)
$572225 f5andzp_joy_state; Merge direction bits
$572485 f5stazp_joy_state
$5726a9 20lda#%00100000; Drive column 5 for left direction
$572820 d1 56jsrcia1_scan_col
$572B4alsra; Shift into position
$572Caatax
$572D09 feora#%11111110; Isolate bit 0 (joy up)
$572F25 f5andzp_joy_state
$573185 f5stazp_joy_state
$57338atxa; Shift right ×2 more
$57344alsra
$57354alsra
$573609 fdora#%11111101; Isolate bit 1 (joy down)
$573825 f5andzp_joy_state; Final merge of all direction bits
$573A09 e0b_573Aora#%11100000; Set upper 3 bits high (unused, always 1) ; x-ref: $5707, $5710
$573C85 f5stazp_joy_state
$573E4c 7e eajmpe_EA7E; Continue into KERNAL keyboard scan completion
$5741.fill47, $00
.encode
.enc"screen"
$5770.text"copyright colosoftware xrom system br"
$5798.text"ussels 1983 "
.endencode
$57A6.fill90, $00
$5800.binary"c64_burnin_rubber_5800.html"
; -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
$8000.wordKERNAL_RESET_VECTOR, cartridge_reset_entry
$8004.byte$c3, $c2, $cd, $38, $30, $20, $20, $20; CBM80
$800C.byte$20, $20, $20, $20
.encode
.enc"none"
; Each "tile" consists of $0400 (1024) bytes, what fits in a screen.
; Each level consists of different "tiles" that are defined in $4000
; block idx #00
level_tile_definition_tbl
$8010.text"EEEEEE@B BCEEEEEEE"; x-ref: $1329, $132D, $138D, $1391
$8038f_8038.text"EEEEEEAB BDEEEEEEE"; x-ref: $50D2
$8060.text"EEEEEE@B BCEEEEEEE"
$8088.text"EEEEEEAB BDEEEEEEE"
$80B0.text"EEEEEE@B BCEEEEEEE"
$80D8.text"EEEEEEAB BDEEEEEEE"
$8100.text"EEEEEE@B "
$8110f_8110.text" BCEEEEEEEEEEEEEAB "; x-ref: $1714
$8138.text" BDEEEEEEEEEEEEE@B "
$8160.text" BCEEEEEEEEEEEEEAB "
$8188.text" BDEEEEEEEEEEEEE@B "
$81B0.text" BCEEEEEEEEEEEEEAB "
$81D8.text" BDEEEEEEEEEEEEE@B "
$8200.text" B"
$8210f_8210.text"CEEEEEEEEEEEEEAB B"; x-ref: $171A
$8238.text"DEEEEEEEEEEEEE@B B"
$8260.text"CEEEEEEEEEEEEEAB B"
$8288.text"DEEEEEEEEEEEEE@B B"
$82B0.text"CEEEEEEEEEEEEEAB B"
$82D8.text"DEEEEEEEEEEEEE@B B"
$8300f_8300.text"CEEEEEEEEEEEEEAB B"; x-ref: $1720
$8328.text"DEEEEEEEEEEEEE@B B"
$8350.text"CEEEEEEEEEEEEEAB B"
$8378.text"DEEEEEEEEEEEEE@B B"
$83A0.text"CEEEEEEEEEEEEEAB B"
$83C8.text"DEEEEEEEEEEEEE@B B"
$83F0.text"CEEEEEEEEEEEEEAB "
; block idx #01
$8410.text"KKKKKKFG MLKKKKKKK"
$8438.text"KKKKKKKH NKKKKKKKK"
$8460.text"KKKKKKJI OPKKKKKKK"
$8488.text"KKKKKKH NKKKKKKK"
$84B0.text"KKKKKKFG MLKKKKKKKK"
$84D8.text"KKKKKKKH NKKKKKKKKK"
$8500.text"KKKKKKJI OPKKKKKKKK"
$8528.text"KKKKKKH NKKKKKKKK"
$8550.text"KKKKKKKFG MLKKKKKKKK"
$8578.text"KKKKKKKKH NKKKKKKKKK"
$85A0.text"KKKKKKKKH OPKKKKKKKK"
$85C8.text"KKKKKKKJI NKKKKKKKK"
$85F0.text"KKKKKKH MLKKKKKKKK"
$8618.text"KKKKKKFG NKKKKKKKKK"
$8640.text"KKKKKKKH NKKKKKKKKK"
$8668.text"KKKKKKJI RFG OPKKKKKKKK"
$8690.text"KKKKKKH NKH NKKKKKKK"
$86B8.text"KKKKKKFG QJI MLKKKKKKK"
$86E0.text"KKKKKKKH NKKKKKKKK"
$8708.text"KKKKKKJI OPKKKKKKK"
$8730.text"KKKKKKH NKKKKKKK"
$8758.text"KKKKKKFG MLKKKKKKK"
$8780.text"KKKKKKKH NKKKKKKKK"
$87A8.text"KKKKKKJI OPKKKKKKK"
$87D0.text"KKKKKKH NKKKKKKK"
$87F8.text" ", $c0, $c4, $c6, $c8, $ca, $cc, $ce, $d0
; block idx #02
$8810.text"KKKKKKKFG NKKKKKKK"
$8838.text"KKKKKKKKFG NKKKKKKK"
$8860.text"KKKKKKKKKFG NKKKKKKK"
$8888.text"KKKKKKKKKKFG NKKKKKKK"
$88B0.text"KKKKKKKKKKKFG MLKKKKKKK"
$88D8.text"KKKKKKKKKKKKFG MLKKKKKKKK"
$8900.text"KKKKKKKKKKKKKFG MLKKKKKKKKK"
$8928.text"KKKKKKKKKKKKKKH MLKKKKKKKKKK"
$8950.text"KKKKKKKKKKKKKKH MLKKKKKKKKKKK"
$8978.text"KKKKKKKKKKKKKKH NKKKKKKKKKKKK"
$89A0.text"KKKKKKKKKKKKKKH NKKKKKKKKKKKK"
$89C8.text"KKKKKKKKKKKKKKH OPKKKKKKKKKKK"
$89F0.text"KKKKKKKKKKKKKJI OPKKKKKKKKKK"
$8A18.text"KKKKKKKKKKKKJI OPKKKKKKKKK"
$8A40.text"KKKKKKKKKKKJI NKKKKKKKKK"
$8A68.text"KKKKKKKKKKJI NKKKKKKKKK"
$8A90.text"KKKKKKKKKJI NKKKKKKKKK"
$8AB8.text"KKKKKKKKJI NKKKKKKKKK"
$8AE0.text"KKKKKKKJI NKKKKKKKKK"
$8B08.text"KKKKKKJI RFG NKKKKKKKKK"
$8B30.text"KKKKKKH NKH NKKKKKKKKK"
$8B58.text"KKKKKKH QJI OPKKKKKKKK"
$8B80.text"KKKKKKH OPKKKKKKK"
$8BA8.text"KKKKKKH NKKKKKKK"
$8BD0.text"KKKKKKH NKKKKKKK"
$8BF8.text" ", $c0, $c4, $c6, $c8, $ca, $cc, $ce, $d0
; block idx #03
$8C10.text"acacacUWB Wcacacacacacacacacacacacac"
$8C38.text"bdbdbdWWB Bbdbdbdbdbdbdbdbdbdbdbdbdbd"
$8C60.text"KKFBBBBBB BBBBBBBBBBBBBBBBBBBLKKKKKKK"
$8C88.text"KKKFG RFG NKKKKKKKK"
$8CB0.text"KKKKH NKH OPKKKKKKK"
$8CD8.text"KKKKH QJI NKKKKKKK"
$8D00.text"KKKKH MLKKKKKKK"
$8D28.text"KKKKH NKKKKKKKK"
$8D50.text"KKKKH OPKKKKKKK"
$8D78.text"KKKKH NKKKKKKK"
$8DA0.text"KKKKKKKKKKKKKH MLKKKKKKK"
$8DC8.text"KKKKKKKKKKKKJI MLKKKKKKKK"
$8DF0.text"KKKKKKKKKKKKH MLKKKKKKKKK"
$8E18.text"KKKKKKKKKKKJI MLKKKKKKKKKK"
$8E40.text"KKKKKKKKKKJI NKKKKKKKKKKK"
$8E68.text"KKKKKKKKKH MLKKKKKKKKKKKK"
$8E90.text"KKKKKKKKJI NKKKKKKKKKKKKK"
$8EB8.text"KKKKKKKJI OPKKKKKKKKKKKK"
$8EE0.text"KKKKKKJI OPKKKKKKKKKKK"
$8F08.text"KKKKKKH OPKKKKKKKKKK"
$8F30.text"KKKKKKH OPKKKKKKKKK"
$8F58.text"KKKKKKFG RFG OPKKKKKKKK"
$8F80.text"KKKKKKKH NKH OPKKKKKKK"
$8FA8.text"KKKKKKJI QJI NKKKKKKK"
$8FD0.text"KKKKKKH NKKKKKKK"
$8FF8.text" ", $c0, $c4, $c6, $c8, $ca, $cc, $ce, $d0
; block idx #04
$9010.text"]_]_]_^WB BYY]_]_]_]_]_]_]_]_]_]_]_]_"
$9038.text"^`^`^`^WB BY^`^`^`^`^`^`^`^`^`^`^`^`^"
$9060.text"aaaaaaVXB Z\aaaaaaaaaaaaaaaaaaaaaaaa"
$9088.text"aaaaaaUWB Y[aaaaaaaaaaaaaaaaaaaaaaaa"
$90B0.text"aaaaaaVXB BZ\aaaaaaaacacacaaaaaaaaaaa"
$90D8.text"aaaaaaUW BY[aaaaaaabdbdbdbdaaaaaaaaa"
$9100.text"aaaaaaVX BZ\aaaaaaUWeeeeeeY[aaaaaaaa"
$9128.text"aaaaaaUW BY[aaaaaaVXeeeeeeZ\aaaaaaaa"
$9150.text"aaaaaaVX BZ\aaaaaaUWeeeeeeY[aaaaaaaa"
$9178.text"aaaaaaUW BY[aaaaaaVXeeeeeeZ\aaaaaaaa"
$91A0.text"aaaaaaVXB BZ\aaaaaaUWeeeeeeY[aaaaaaaa"
$91C8.text"aaaaaaUWB BY[aaaaaaVXeeeeeeZ\aaaaaaaa"
$91F0.text"aaaaaaVXB BZ\aaaaaaUWeeeeeeY[aaaaaaaa"
$9218.text"aaaaaaUWB Y[aaaaaaVXeeeeeeZ\aaaaaaaa"
$9240.text"aaaaaaVXB Z\aaaaaaUWeeeeeeY[aaaaaaaa"
$9268.text"aaaaaaUWB Y[aaaaaaa]_]_]_]_aaaaaaaaa"
$9290.text"aaaaaaVXB Z\aaaaaaa^`^`^`^aaaaaaaaaa"
$92B8.text"aaaaaaUWB Y[aaaaaaaaaaaaaaaaaaaaaaaa"
$92E0.text"aaaaaaVX Z\aaaaaaaaaaaaaaaaaaaaaaaa"
$9308.text"aaaaaaUW BY[aaaaaaaaaaaaaaaaaaaaaaaa"
$9330.text"aaaaaaVX BZ\aaaaaaaaaaaaaaaaaaaaaaaa"
$9358.text"aaaaaaUW BY[aaaaaaaaaaaaaaaaaaaaaaaa"
$9380.text"aaaaaaVX BY[aaaaaaaaaaaaaaaaaaaaaaaa"
$93A8.text"aaaaaaUWB BY[aaaaaaaaaaaaaaaaaaaaaaaa"
$93D0.text"aaaaaaVXB BZ\aaaaaaaaaaaaaaaaaaaaaaaa"
$93F8.text" ", $c0, $c4, $c6, $c8, $ca, $cc, $ce, $d0
; block idx #05
$9410.text"aaaaaaaaaaUWB BY[aaaaaaaaaa"
$9438.text"aaaaaaaaaaVXB BZ\aaaaaaaaaa"
$9460.text"aaaaaaaaaaUWB Y[aaaaaaaaaa"
$9488.text"aaaaaaaaaaVXB Z\aaaaaaaaaa"
$94B0.text"aaaaaaaaaaUWB Y[aaaaaaaaaa"
$94D8.text"aaaaaaaaaaVXB Z\aaaaaaaaaa"
$9500.text"aaaaaaaaaaUWB Y[aaaaaaaaaa"
$9528.text"aaaaaaaaaaVXB BZ\aaaaaaaaaa"
$9550.text"aaaaaaaaaaUWB BY[aaaaaaaaaa"
$9578.text"aaaaaaaaaaVX BZ\aaaaaaaaaa"
$95A0.text"aaaaaaaaaaUW BY[aaaaaaaaaa"
$95C8.text"aaaaaaaaaaVX BZ\aaaaaaaaaa"
$95F0.text"aaaaaaaaaaUW BY[aaaaaaaaaa"
$9618.text"aaaaaaaaaaVXB BZ\aaaaaaaaaa"
$9640.text"aaaaaaaaaaUWB BY[aaaaaaaaaa"
$9668.text"aaaaaaaaaaVXB BZ\aaaaaaaaaa"
$9690.text"aaaaaaaaaaUW Y[aaaaaaaaaa"
$96B8.text"aaaaaaaaaaVX Z\aaaaaaaaaa"
$96E0.text"aaaaaaaaaaUW Y[aaaaaaaaaa"
$9708.text"aaaaaaaaaaVX BZ\aaaaaaaaaa"
$9730.text"aaaaaaaaaaUW BY[aaaaaaaaaa"
$9758.text"aaaaaaaaaaVX BZ\aaaaaaaaaa"
$9780.text"aaaaaaaaaaUWB BY[aaaaaaaaaa"
$97A8.text"aaaaaaaaaaVXB BZ\aaaaaaaaaa"
$97D0.text"aaaaaaaaaaUWB Y[aaaaaaaaaa"
$97F8.text"aaaaaaaaaaVXB "
; block idx #06
$9810.text"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
$9838.text"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
$9860.text"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
$9888.text"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
$98B0.text"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
$98D8.text"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
$9900.text"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
$9928.text"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
$9950.text"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
$9978.text"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
$99A0.text"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
$99C8.text"aaaaaaaaaaaa^`^`^`^`^`^`^`^`aaaaaaaaaaaa"
$99F0.text"aaaaaaaaaaaabdbdbdbdbdbdbdbdaaaaaaaaaaaa"
$9A18.text"aaaaaaaaaaUWB BY[aaaaaaaaaa"
$9A40.text"aaaaaaaaaaVXB BZ\aaaaaaaaaa"
$9A68.text"aaaaaaaaaaUWB BY[aaaaaaaaaa"
$9A90.text"aaaaaaaaaaVXB Z\aaaaaaaaaa"
$9AB8.text"aaaaaaaaaaUWB Y[aaaaaaaaaa"
$9AE0.text"aaaaaaaaaaVX Z\aaaaaaaaaa"
$9B08.text"aaaaaaaaaaUW Y[aaaaaaaaaa"
$9B30.text"aaaaaaaaaaVX Z\aaaaaaaaaa"
$9B58.text"aaaaaaaaaaUW BY[aaaaaaaaaa"
$9B80.text"aaaaaaaaaaVX BZ\aaaaaaaaaa"
$9BA8.text"aaaaaaaaaaUW BY[aaaaaaaaaa"
$9BD0.text"aaaaaaaaaaVXB BZ\aaaaaaaaaa"
$9BF8.text" ", $c0, $c4, $c6, $c8, $ca, $cc, $ce, $d0
; block idx #07
$9C10.text"aaaaaaaaaaUWB BY[aaaaaaaaaa"
$9C38.text"aaaaaaaaaaUWB BY[aaaaaaaaaa"
$9C60.text"aaaaaaaaaaVXB BZ\aaaaaaaaaa"
$9C88.text"aaaaaaaaaaUW BY[aaaaaaaaaa"
$9CB0.text"aaaaaaaaaaVX BZ\aaaaaaaaaa"
$9CD8.text"aaaaaaaaaaUW BY[aaaaaaaaaa"
$9D00.text"aaaaaaaaaaVX Z\aaaaaaaaaa"
$9D28.text"aaaaaaaaaaUW Y[aaaaaaaaaa"
$9D50.text"aaaaaaaaaaVXB BZ\aaaaaaaaaa"
$9D78.text"aaaaaaaaaaUWB BY[aaaaaaaaaa"
$9DA0.text"aaaaaaaaaaVXB Z\aaaaaaaaaa"
$9DC8.text"aaaaaaaaaaUWB Y[aaaaaaaaaa"
$9DF0.text"aaaaaaaaaaa^]_]_]_]_]_]_]_]_`aaaaaaaaaaa"
$9E18.text"aaaaaaaaaaaa^`^`^`^`^`^`^`^`aaaaaaaaaaaa"
$9E40.text"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
$9E68.text"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
$9E90.text"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
$9EB8.text"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
$9EE0.text"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
$9F08.text"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
$9F30.text"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
$9F58.text"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
$9F80.text"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
$9FA8.text"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
$9FD0.text"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
$9FF8.text"aaaaaaaaaaaaaaaaaaaaaaaa"
; block idx #08
$A010.text"aaaaaaVXB Z\aaaaaaaaaaaaaaaaaaaaaaaa"
$A038.text"aaaaaaUWB Y[aaaaaaaaaaaaaaaaaaaaaaaa"
$A060.text"aaaaaaVXB Z\aaaaaaaaaaaaaaaaaaaaaaaa"
$A088.text"aaaaaaUWB Y[aaaaaaaaaaaaaaaaaaaaaaaa"
$A0B0.text"aaaaaaVXB Z\aaaaaaaaaaaaaaaaaaaaaaaa"
$A0D8.text"aaaaaaUWB BY[aaaaaaaaaaaaaaaaaaaaaaaa"
$A100.text"aaaaaaVX BZ\aaaaaaaaaaaaaaaaaaaaaaaa"
$A128.text"aaaaaaUW BY[aaaaaaaaaaaaaaaaaaaaaaaa"
$A150.text"aaaaaaVX BZ\aaaaaaaaaaaaaaaaaaaaaaaa"
$A178.text"aaaaaaUW BY[aaaaaaaaaaaaaaaaaaaaaaaa"
$A1A0.text"aaaaaaVXB BZ\aaaaaaabdbdbdbdaaaaaaaaa"
$A1C8.text"aaaaaaUWB BY[aaaaaabeeeeeeeedaaaaaaaa"
$A1F0.text"aaaaaaVXB Z\aaaaUWeeeeeeeeeeY[aaaaaa"
$A218.text"aaaaaaUWB Y[aaaaVXeeeeeeeeeeZ\aaaaaa"
$A240.text"aaaaaaVX Z\aaaaUWeeeeeeeeeeY[aaaaaa"
$A268.text"aaaaaaUW Y[aaaaVXeeeeeeeeeeZ\aaaaaa"
$A290.text"aaaaaaVX BZ\aaaaUWeeeeeeeeeeY[aaaaaa"
$A2B8.text"aaaaaaUW BY[aaaaVXeeeeeeeeeeZ\aaaaaa"
$A2E0.text"aaaaaaVX BZ\aaaaUWeeeeeeeeeeY[aaaaaa"
$A308.text"aaaaaaUW BY[aaaaVXeeeeeeeeeeZ\aaaaaa"
$A330.text"aaaaaaVXB BZ\aaaaaX]_]_]_]_]_Zaaaaaaa"
$A358.text"aaaaaaUWB BY[aaaaa^`^`^`^`^`^`aaaaaaa"
$A380.text"aaaaaaVXB BZ\aaaaaaaaaaaaaaaaaaaaaaaa"
$A3A8.text"aaaaaaUWB BY[aaaaaaaaaaaaaaaaaaaaaaaa"
$A3D0.text"aaaaaaVXB Z\aaaaaaaaaaaaaaaaaaaaaaaa"
$A3F8.text" ", $00, $ff, $00, $ff, $00, $ff, $00, $ff, $c0, $c4, $c6, $c8, $ca, $cc, $ce, $d0
; block idx #09
$A410.text"KKKKKKFG KKKH MNKKKKKKK"
$A438.text"KKKKKKKH KKKH NKKKKKKKK"
$A460.text"KKKKKKJI KKKFG OPKKKKKKK"
$A488.text"KKKKKKH KKKKH NKKKKKKK"
$A4B0.text"KKKKKKFG KKKJI MLKKKKKKK"
$A4D8.text"KKKKKKKH KKKH NKKKKKKKK"
$A500.text"KKKKKKJI KKKFG OPKKKKKKK"
$A528.text"KKKKKKH KKKKH NKKKKKKK"
$A550.text"KKKKKKFG KKKJI MLKKKKKKK"
$A578.text"KKKKKKKH KKKH RFG NKKKKKKKK"
$A5A0.text"KKKKKKJI KKKFGNKH OYKKKKKKK"
$A5C8.text"KKKKKKH KKKKHQJI NKKKKKKK"
$A5F0.text"KKKKKKFG KKKJI MLKKKKKKK"
$A618.text"KKKKKKKH KKKH NKKKKKKKK"
$A640.text"KKKKKKJI KKKFG OPKKKKKKK"
$A668.text"KKKKKKH KKKKH NKKKKKKK"
$A690.text"KKKKKKFG KKKJI MLKKKKKKK"
$A6B8.text"KKKKKKKH KKJI NKKKKKKKK"
$A6E0.text"KKKKKKJI KJI OPKKKKKKK"
$A708.text"KKKKKKH JI NKKKKKKK"
$A730.text"KKKKKKFG MLKKKKKKK"
$A758.text"KKKKKKKH NKKKKKKKK"
$A780.text"KKKKKKJIRFG OPKKKKKKK"
$A7A8.text"KKKKKKH NKH NKKKKKKK"
$A7D0.text"KKKKKKH QJI NKKKKKKK"
$A7F8.text" ", $00, $ff, $00, $ff, $00, $ff, $00, $ff, $c0, $c4, $c6, $c8, $ca, $cc, $ce, $d0
; block idx #10 ($0a)
$A810.text"KKKKKKFG MNKKKKKKK"
$A838.text"KKKKKKKH NKKKKKKKK"
$A860.text"KKKKKKJI OPKKKKKKK"
$A888.text"KKKKKKBBBBBBBBBBBBB NKKKKKKK"
$A8B0.text"KKKKKK]_]_]_]_]_]ZB MLKKKKKKK"
$A8D8.text"KKKKKK^`^`^`^`^`^WB NKKKKKKKK"
$A900.text"KKKKKKbdbdbdbdbdbdB OPKKKKKKK"
$A928.text"KKKKKKBBBBBBBBBBBBB NKKKKKKK"
$A950.text"KKKKKKFG MLKKKKKKK"
$A978.text"KKKKKKKH NKKKKKKKK"
$A9A0.text"KKKKKKJI OPKKKKKKK"
$A9C8.text"KKKKKKH BBBBBBBBBBBBBBBBKKKKKK"
$A9F0.text"KKKKKKFG B]_]_]_]_]_]_]_]KKKKKK"
$AA18.text"KKKKKKKH BY^`^`^`^`^`^`^`KKKKKK"
$AA40.text"KKKKKKJI BYbdbdbdbdbdbdbdKKKKKK"
$AA68.text"KKKKKKH BBBBBBBBBBBBBBBBKKKKKK"
$AA90.text"KKKKKKFG MLKKKKKKK"
$AAB8.text"KKKKKKKH NKKKKKKKK"
$AAE0.text"KKKKKKJI OPKKKKKKK"
$AB08.text"KKKKKKBBBBBBBBBBBBB NKKKKKKK"
$AB30.text"KKKKKK]_]_]_]_]_]YB MLKKKKKKK"
$AB58.text"KKKKKK^`^`^`^`^`^YB NKKKKKKKK"
$AB80.text"KKKKKKbdbdbdbdbdbdB OPKKKKKKK"
$ABA8.text"KKKKKKBBBBBBBBBBBBB NKKKKKKK"
$ABD0.text"KKKKKKH NKKKKKKK"
$ABF8.text" ", $00, $ff, $00, $ff, $00, $ff, $00, $ff, $c0, $c4, $c6, $c8, $ca, $cc, $ce, $d0
; block idx #11 ($0b)
$AC10.text"KKKKKKFG MNKKKKKKK"
$AC38.text"KKKKKKKH NKKKKKKKK"
$AC60.text"KKKKKKJI OPKKKKKKK"
$AC88.text"KKKKKKH NKKKKKKK"
$ACB0.text"KKKKKKFG MLKKKKKKK"
$ACD8.text"KKKKKKKH NKKKKKKKK"
$AD00.text"KKKKKKJI OPKKKKKKK"
$AD28.text"KKKKKKH FG NKKKKKKK"
$AD50.text"KKKKKKFG KFG MLKKKKKKK"
$AD78.text"KKKKKKKH KKFG NKKKKKKKK"
$ADA0.text"KKKKKKJI KKKFG OPKKKKKKK"
$ADC8.text"KKKKKKH KKKKH NKKKKKKK"
$ADF0.text"KKKKKKFG KKKJI MLKKKKKKK"
$AE18.text"KKKKKKKH KKKBBBBBBBBBBBBBBBBBKKKKKKK"
$AE40.text"KKKKKKJI KKK]_]_]_]_]_]_]_]_]KKKKKKK"
$AE68.text"KKKKKKH KKK^`^`^`^`^`^`^`^`^KKKKKKK"
$AE90.text"KKKKKKFG KKKbdbdbdbdbdbdbdbdbKKKKKKK"
$AEB8.text"KKKKKKKH KKKBBBBBBBBBBBBBBBBBKKKKKKK"
$AEE0.text"KKKKKKJI KKKFG OPKKKKKKK"
$AF08.text"KKKKKKH KKKKH NKKKKKKK"
$AF30.text"KKKKKKFG KKKJI MLKKKKKKK"
$AF58.text"KKKKKKKH KKKH NKKKKKKKK"
$AF80.text"KKKKKKJI KKKFG OPKKKKKKK"
$AFA8.text"KKKKKKH KKKKH NKKKKKKK"
$AFD0.text"KKKKKKH KKKJI NKKKKKKK"
$AFF8.text" ", $00, $ff, $00, $ff, $00, $ff, $00, $ff, $c0, $c4, $c6, $c8, $ca, $cc, $ce, $d0
; block idx #12 ($0c)
$B010.text"KKKKKKFG KKKH MNKKKKKKK"
$B038.text"KKKKKKKH KKKBBBBBBBBBBBBBBBBBKKKKKKK"
$B060.text"KKKKKKJI KKK]_]_]_]_]_]_]_]_]KKKKKKK"
$B088.text"KKKKKKH KKK^`^`^`^`^`^`^`^`^KKKKKKK"
$B0B0.text"KKKKKKFG KKKbdbdbdbdbdbdbdbdbKKKKKKK"
$B0D8.text"KKKKKKKH KKKBBBBBBBBBBBBBBBBBKKKKKKK"
$B100.text"KKKKKKJI KKKFG OPKKKKKKK"
$B128.text"KKKKKKH KKKKH NKKKKKKK"
$B150.text"KKKKKKFG KKKJI MLKKKKKKK"
$B178.text"KKKKKKKH KKKH RFG NKKKKKKKK"
$B1A0.text"KKKKKKJI KKKFGNKH OPKKKKKKK"
$B1C8.text"KKKKKKH KKKKHQJI NKKKKKKK"
$B1F0.text"KKKKKKFG KKKJI MLKKKKKKK"
$B218.text"KKKKKKKH KKKH NKKKKKKKK"
$B240.text"KKKKKKJI KKKFG OPKKKKKKK"
$B268.text"KKKKKKH KKKKH NKKKKKKK"
$B290.text"KKKKKKFG KKKJI MLKKKKKKK"
$B2B8.text"KKKKKKKH KKJI NKKKKKKKK"
$B2E0.text"KKKKKKJI KJI OPKKKKKKK"
$B308.text"KKKKKKH JI NKKKKKKK"
$B330.text"KKKKKKFG MLKKKKKKK"
$B358.text"KKKKKKKH NKKKKKKKK"
$B380.text"KKKKKKJIRFG OPKKKKKKK"
$B3A8.text"KKKKKKH NKH NKKKKKKK"
$B3D0.text"KKKKKKH QJI NKKKKKKK"
$B3F8.text" ", $00, $ff, $00, $ff, $00, $ff, $00, $ff, $c0, $c4, $c6, $c8, $ca, $cc, $ce, $d0
; block idx #13 ($0d)
$B410.text"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
$B438.text"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
$B460.text"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
$B488.text"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
$B4B0.text"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
$B4D8.text"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
$B500.text"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
$B528.text"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
$B550.text"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
$B578.text"aaaaaaaaaabdbdbdbdbdbdbdbdbdbaaaaaaaaaaa"
$B5A0.text"aaaaaaaaaUWeeeeeeeeeeeeeeeeeY[aaaaaaaaaa"
$B5C8.text"aaaaaaaaaVXeeeeeeeeeeeeeeeeeZ\aaaaaaaaaa"
$B5F0.text"aaaaaaaaaUWeeeeeeeeeeeeeeeeeY[aaaaaaaaaa"
$B618.text"aaaaaaaaaVXeeeeeeeeeeeeeeeeeZ\aaaaaaaaaa"
$B640.text"aaaaaaaaaUWeeeeeeeeeeeeeeeeeY[aaaaaaaaaa"
$B668.text"aaaaaaaaaVXeeeeeeeeeeeeeeeeeY[aaaaaaaaaa"
$B690.text"aaaaaaaaaVXeeeeeeeeeeeeeeeeeZ\aaaaaaaaaa"
$B6B8.text"aaaaaaaaaa]_]_]_]_]_]_]_]_]_]aaaaaaaaaaa"
$B6E0.text"aaaaaaaaaa^`^`^`^`^`^`^`^`^`^aaaaaaaaaaa"
$B708.text"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
$B730.text"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
$B758.text"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
$B780.text"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
$B7A8.text"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
$B7D0.text"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
$B7F8.text" ", $00, $ff, $00, $ff, $00, $ff, $00, $ff, $c0, $c4, $c6, $c8, $ca, $cc, $ce, $d0
; block idx #14 ($0e)
$B810.text"KKKKKKFG KKKH MNKKKKKKK"
$B838.text"KKKKKKKH KKKBBBBBBBBBBBBBBBBBKKKKKKK"
$B860.text"KKKKKKJI KKK]_]_]_]_]_]_]_]_]KKKKKKK"
$B888.text"KKKKKKH KKK^`^`^`^`^`^`^`^`^KKKKKKK"
$B8B0.text"KKKKKKFG KKKbdbdbdbdbdbdbdbdbKKKKKKK"
$B8D8.text"KKKKKKKH KKKBBBBBBBBBBBBBBBBBKKKKKKK"
$B900.text"KKKKKKJI KKKFG OPKKKKKKK"
$B928.text"KKKKKKH KKKKH NKKKKKKK"
$B950.text"KKKKKKFG KKKJI MLKKKKKKK"
$B978.text"KKKKKKKH KKKH RFG NKKKKKKKK"
$B9A0.text"KKKKKKJI KKKFGNKH OPKKKKKKK"
$B9C8.text"KKKKKKH KKKKHQJI NKKKKKKK"
$B9F0.text"KKKKKKFG KKKJI MLKKKKKKK"
$BA18.text"KKKKKKKH KKKH NKKKKKKKK"
$BA40.text"KKKKKKJI KKKFG OPKKKKKKK"
$BA68.text"KKKKKKH KKKKH NKKKKKKK"
$BA90.text"KKKKKKFG KKKJI MLKKKKKKK"
$BAB8.text"KKKKKKKH KKKH NKKKKKKKK"
$BAE0.text"KKKKKKJI KKKFG OPKKKKKKK"
$BB08.text"KKKKKKBBBBBBBKKKKH NKKKKKKK"
$BB30.text"KKKKKK]_]_]_]KKKJI MLKKKKKKK"
$BB58.text"KKKKKK^`^`^`^KKKH NKKKKKKKK"
$BB80.text"KKKKKKbdbdbdbKKKFG OPKKKKKKK"
$BBA8.text"KKKKKKBBBBBBBKKKKH NKKKKKKK"
$BBD0.text"KKKKKKH KKKJI NKKKKKKK"
$BBF8.text" ", $00, $ff, $00, $ff, $00, $ff, $00, $ff, $c0, $c4, $c6, $c8, $ca, $cc, $ce, $d0
; block idx #15 ($0f)
$BC10.text"KKKKKKH NKKKKKKK"
$BC38.text"KKKKKKBBBBBBBBBBBBBBBBBBBBBBBBBBBKKKKKKK"
$BC60.text"KKKKKK]_]_]_]_]_]_]_]_]_]_]_]_]_]KKKKKKK"
$BC88.text"KKKKKK^`^`^`^`^`^`^`^`^`^`^`^`^`^KKKKKKK"
$BCB0.text"KKKKKKbdbdbdbdbdbdbdbdbdbdbdbdbdbKKKKKKK"
$BCD8.text"KKKKKKBBBBBBBBBBBBBBBBBBBBBBBBBBBKKKKKKK"
$BD00.text"KKKKKKJI RFG OPKKKKKKK"
$BD28.text"KKKKKKH NKH NKKKKKKK"
$BD50.text"KKKKKKFG QJI MLKKKKKKK"
$BD78.text"KKKKKKKH NKKKKKKKK"
$BDA0.text"KKKKKKJI OPKKKKKKK"
$BDC8.text"KKKKKKH NKKKKKKK"
$BDF0.text"KKKKKKFG MLKKKKKKK"
$BE18.text"KKKKKKKH NKKKKKKKK"
$BE40.text"KKKKKKJI OPKKKKKKK"
$BE68.text"KKKKKKH NKKKKKKK"
$BE90.text"KKKKKKFG MLKKKKKKK"
$BEB8.text"KKKKKKKH NKKKKKKKK"
$BEE0.text"KKKKKKJI OPKKKKKKK"
$BF08.text"KKKKKKBBBBBBBBBBBBBBBBBBBBBBBBBBBBKKKKKK"
$BF30.text"KKKKKK]_]_]_]]_]_]_]_]_]_]_]_]_]_]KKKKKK"
$BF58.text"KKKKKK^`^`^`^`^`^`^`^`^`^`^`^`^`^`KKKKKK"
$BF80.text"KKKKKKbdbdbdbbdbdbdbdbdbdbdbdbdbdbKKKKKK"
$BFA8.text"KKKKKKBBBBBBBBBBBBBBBBBBBBBBBBBBBBKKKKKK"
$BFD0.text"KKKKKKH NKKKKKKK"
$BFF8.text" "
.endencode