| ;=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| ; |
| ; Auto-generated by Regenerator 2000 v0.9.17 |
| ; https://github.com/ricardoquesada/regenerator2000 |
| ; |
| ; Exported from: plus4_kikstart_8192.regen2000proj |
| ; |
| ; Assemble with 64tass: |
| ; 64tass -o plus4_kikstart_8192.prg plus4_kikstart_8192.asm |
| ; |
| ;=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
|
| ; EXTERNAL LABELS |
| ; zpf_ = Zero Page Field |
| ; zpa_ = Zero Page Absolute Address |
| ; zpp_ = Zero Page Pointer |
| ; f_ = Field |
| ; a_ = Absolute Address |
|
| zp_game_mode = $02 ; x-ref: $21C0, $2304, $2410, $25D0, $2635, $267C, $268C, $2696, ... |
| zp_frame_phase = $03 ; x-ref: $20BE, $20D2, $20F6, $2128, $212A, $2132, $2134 |
| zp_raster_split_a = $04 ; x-ref: $214D, $21BC, $246C, $24F4, $24FB, $250D, $2514, $262F, ... |
| zp_raster_split_b = $05 ; x-ref: $2158, $2477, $24E1, $24E8, $2631, $264F |
| zp_raster_target = $06 ; x-ref: $20C2, $2166, $2171 |
| zp_obstacle_flags = $10 ; x-ref: $223E, $225A, $2286, $2299, $22C0, $2526, $2572, $257A, ... |
| zp_obstacle_life = $14 ; x-ref: $2273, $22A6, $22CC, $2804, $2806, $2CA0, $2CE8 |
| zp_obstacle_pos_hi = $18 ; x-ref: $224E, $2254, $2534, $253D, $2541, $254B, $254F, $255B, ... |
| zp_obstacle_pos_lo = $1c ; x-ref: $2536, $253B, $2558, $255D, $2CC5, $2CCB |
| zp_obstacle_vel = $20 ; x-ref: $228F, $2530, $2539, $255F, $2563, $293C, $2943, $2CC1, ... |
| zp_ptr_obj_record_lo = $24 ; x-ref: $231A, $239E, $23EE, $2616, $294A, $2E1E, $2E28, $2E2E, ... |
| zp_ptr_obj_record_hi = $25 ; x-ref: $261A, $2E23, $2E2C, $2E34, $2E40 |
| zp_track_scroll_frac = $26 ; x-ref: $24D8, $24DD, $2633, $2651 |
| zp_bike_pos_x_hi = $27 ; x-ref: $23FB, $2482, $2497, $2690, $26B2, $2777, $27AD, $27B3, ... |
| zp_bike_pos_x_lo = $28 ; x-ref: $2403, $2686, $277B, $2911, $2916, $2956 |
| zp_bike_vel = $29 ; x-ref: $2688, $26F0, $28FD, $2907, $290B, $2914, $2958, $2E6F |
| zp_bike_throttle = $2a ; x-ref: $24DB, $2639, $2649, $26C5, $26FA, $277F, $278A, $2790, ... |
| zp_spawn_cooldown = $2b ; x-ref: $2680, $2813, $2C96, $2CA4 |
| zp_rng_state_lo = $2c ; x-ref: $27E0, $27E5, $27EB |
| zp_rng_state_mid = $2d ; x-ref: $27E7, $27ED, $27F3 |
| zp_rng_state_hi = $2e ; x-ref: $27EF, $27F5 |
| zp_course_index = $2f ; x-ref: $20B0, $2592, $29B4, $2A1A, $2A1C, $2A3D, $2A50, $2A85, ... |
| zp_lives_counter = $30 ; x-ref: $20B4, $21AD, $25A7, $25AB, $2645, $28A3, $28B3, $299C, ... |
| zp_scroll_dir_flag = $31 ; x-ref: $232C, $232E, $2653, $26A2 |
| zp_sprite_queue_count = $32 ; x-ref: $20B6, $21D8, $21FB, $2206, $23D0, $23E6 |
| zp_joystick_state = $33 ; x-ref: $2743, $2749, $274D, $2754, $2784, $2797, $27CF, $2DBD, ... |
| zp_music_step = $34 ; x-ref: $261E, $2AA0, $2AA2, $2AAA |
| zp_music_pos = $35 ; x-ref: $2622, $2AAC, $2AAE, $2AB6, $2AB8 |
| zp_track_progress = $36 ; x-ref: $26C1, $26DE, $2834, $289F, $28AB, $28AD, $28C4, $28C6, ... |
| zp_track_left_edge = $37 ; x-ref: $268E, $27B1, $2927, $295A, $2EBA |
| zp_track_flags = $38 ; x-ref: $27C1, $292D, $2E80 |
| zp_track_right_edge = $39 ; x-ref: $27AB, $2921, $2E76 |
| zp_prev_track_flags = $3a ; x-ref: $27C3 |
| zp_player_active = $3b ; x-ref: $21A3, $21A9, $2322, $233A, $233F, $2657 |
| zp_anim_frame_count = $3c ; x-ref: $2372, $2376, $2A42, $2BA8, $2D8B, $2DA8 |
| zp_raster_color = $3d ; x-ref: $2146, $21B4, $21D4 |
| zp_scroll_timer = $3e ; x-ref: $2504, $2509 |
| zp_frame_counter = $3f ; x-ref: $20D8, $236C, $256C, $2B33, $2BC4, $2DDE |
| zp_crash_debris_x = $40 ; x-ref: $2445, $244B, $2453, $2675, $26B0, $2764 |
| zp_crash_debris_y = $48 ; x-ref: $242C, $2436, $2441, $2457, $26B6, $276A, $2896 |
| zp_snd_pitch = $50 ; x-ref: $28E6, $2AFA, $2AFF, $2B01, $2B65, $2B7D, $2B8E, $2BAE, ... |
| zp_snd_pitch_delta = $51 ; x-ref: $28EA, $2AFD, $2B69, $2B81, $2B92, $2BB2, $2BD1, $2BE2, ... |
| zp_spawn_type = $52 ; x-ref: $2C5F, $2C9A, $2CA6 |
| zp_scroll_speed = $53 ; x-ref: $2507, $2A47, $2DAD |
| zp_snd_duration = $54 ; x-ref: $28EE, $2AF4, $2AF8, $2B61, $2B79, $2B96, $2BA0, $2BA6, ... |
| zp_snd_volume = $55 ; x-ref: $28F2, $2B1B, $2B6D, $2B85, $2B9A, $2BB6, $2BD5, $2BEA, ... |
| zp_title_row_anim = $56 ; x-ref: $2DB7, $2DC5, $2DCB, $2E0E |
| zp_title_char_idx = $57 ; x-ref: $2DEA, $2DF2, $2DF4, $2DF8, $2E10, $2E17 |
| zp_blit_scratch = $f7 ; x-ref: $2CF1, $2CF9, $2D18, $2D70, $2D75, $2D7B, $2D84 |
| zp_ted_ctrl_staging = $f8 ; x-ref: $2475, $248B, $248D, $24AF, $24C8, $28D9, $28DF, $2B03, ... |
| zp_pitch_hi = $f9 ; x-ref: $2480, $2493, $2495, $24AB, $24CA, $2B07, $2B0B, $2B0F, ... |
| zp_blit_col = $fc ; x-ref: $2210, $2229, $2233, $2252, $228D, $22C6, $22E6, $22E8, ... |
| zp_blit_row = $fd ; x-ref: $2215, $222B, $222F, $2275, $22A8, $22D1, $22FF, $23C8, ... |
| zp_blit_color_ptr = $fe ; x-ref: $21E2, $21EF, $21F9, $2221, $2231, $224C, $2297, $22D5, ... |
| zp_blit_char_idx = $ff ; x-ref: $21E7, $21F1, $21F5, $221C, $2227, $2258, $2260, $2264, ... |
| vec_irq_lo = $0314 ; x-ref: $2060 |
| vec_irq_hi = $0315 ; x-ref: $2065 |
| sprite_q_row_m1 = $03ff ; x-ref: $21DC |
| sprite_q_row = $0400 ; x-ref: $220A, $23D4 |
| sprite_q_col_m1 = $042f ; x-ref: $21E9 |
| sprite_q_col = $0430 ; x-ref: $2223, $23D9 |
| sprite_q_char = $0460 ; x-ref: $2219, $23DE |
| sprite_q_color = $0490 ; x-ref: $221E, $23E3 |
| COLOR_RAM_R0C0 = $0800 ; x-ref: $204F, $20A2 |
| COLOR_RAM_R1C0 = $0828 ; x-ref: $20A5 |
| COLOR_RAM_R6C8 = $08f8 ; x-ref: $2974 |
| COLOR_RAM_R6C16 = $0900 ; x-ref: $2052 |
| COLOR_RAM_R7C33 = $0939 ; x-ref: $2A95 |
| COLOR_RAM_R7C34 = $093a ; x-ref: $2A98 |
| COLOR_RAM_R8C8 = $0948 ; x-ref: $2979 |
| COLOR_RAM_R8C14 = $094e ; x-ref: $26D6 |
| COLOR_RAM_R10C8 = $0998 ; x-ref: $2A68, $2A7A |
| COLOR_RAM_R12C16 = $09f0 ; x-ref: $2DD8 |
| COLOR_RAM_R12C32 = $0a00 ; x-ref: $2055 |
| COLOR_RAM_R16C0 = $0a80 ; x-ref: $2080 |
| COLOR_RAM_R17C0 = $0aa8 ; x-ref: $207D |
| COLOR_RAM_R18C0 = $0ad0 ; x-ref: $207A |
| COLOR_RAM_R19C0 = $0af8 ; x-ref: $2077 |
| COLOR_RAM_R19C8 = $0b00 ; x-ref: $2058 |
| COLOR_RAM_R20C0 = $0b20 ; x-ref: $2074 |
| COLOR_RAM_R21C0 = $0b48 ; x-ref: $2071 |
| COLOR_RAM_R22C39 = $0b97 ; x-ref: $25B5 |
| COLOR_RAM_R23C0 = $0b98 ; x-ref: $258C, $25B8, $25C5 |
| COLOR_RAM_R23C1 = $0b99 ; x-ref: $25BB |
| COLOR_RAM_R23C23 = $0baf ; x-ref: $25A1 |
| COLOR_RAM_R24C0 = $0bc0 ; x-ref: $25C8 |
| SCREEN_RAM_R0C0 = $0c00 ; x-ref: $2041, $2094, $2D95 |
| SCREEN_RAM_R0C7 = $0c07 ; x-ref: $2199, $2349, $234F, $2358, $237A, $2380, $2389, $2981, ... |
| SCREEN_RAM_R0C8 = $0c08 ; x-ref: $298A, $2E9A, $2EA6 |
| SCREEN_RAM_R0C10 = $0c0a ; x-ref: $2993 |
| SCREEN_RAM_R0C11 = $0c0b ; x-ref: $2363 |
| SCREEN_RAM_R0C19 = $0c13 ; x-ref: $29CA, $29D0, $29D9, $29E9, $29FB |
| SCREEN_RAM_R0C32 = $0c20 ; x-ref: $29EC, $29FE |
| SCREEN_RAM_R1C0 = $0c28 ; x-ref: $209C, $2D9B |
| SCREEN_RAM_R1C7 = $0c2f ; x-ref: $234C, $235D, $237D, $238E, $2EAB |
| SCREEN_RAM_R1C8 = $0c30 ; x-ref: $2EAE |
| SCREEN_RAM_R1C9 = $0c31 ; x-ref: $20B8, $2DA3 |
| SCREEN_RAM_R1C11 = $0c33 ; x-ref: $2366 |
| SCREEN_RAM_R1C19 = $0c3b ; x-ref: $29CD, $29DE, $2A01 |
| SCREEN_RAM_R1C32 = $0c48 ; x-ref: $2A04 |
| SCREEN_RAM_R2C0 = $0c50 ; x-ref: $2A30 |
| SCREEN_RAM_R6C8 = $0cf8 ; x-ref: $2969 |
| SCREEN_RAM_R6C16 = $0d00 ; x-ref: $2044 |
| SCREEN_RAM_R6C29 = $0d0d ; x-ref: $284F, $2852, $285B, $2863, $2987 |
| SCREEN_RAM_R6C30 = $0d0e ; x-ref: $2866, $2990 |
| SCREEN_RAM_R6C31 = $0d0f ; x-ref: $2869, $2999 |
| SCREEN_RAM_R7C33 = $0d39 ; x-ref: $2A82 |
| SCREEN_RAM_R7C34 = $0d3a ; x-ref: $2A90 |
| SCREEN_RAM_R8C8 = $0d48 ; x-ref: $296F |
| SCREEN_RAM_R8C14 = $0d4e ; x-ref: $26D1 |
| SCREEN_RAM_R8C16 = $0d50 ; x-ref: $2A33 |
| SCREEN_RAM_R8C29 = $0d5d ; x-ref: $286E, $2871, $287A, $2882 |
| SCREEN_RAM_R8C30 = $0d5e ; x-ref: $2885, $29A1 |
| SCREEN_RAM_R8C31 = $0d5f ; x-ref: $2888, $29A7 |
| SCREEN_RAM_R10C8 = $0d98 ; x-ref: $2A63, $2A75 |
| SCREEN_RAM_R12C16 = $0df0 ; x-ref: $2DD3 |
| SCREEN_RAM_R12C22 = $0df6 ; x-ref: $2E04 |
| SCREEN_RAM_R12C23 = $0df7 ; x-ref: $2DFE |
| SCREEN_RAM_R12C32 = $0e00 ; x-ref: $2047 |
| SCREEN_RAM_R16C0 = $0e80 ; x-ref: $23A6 |
| SCREEN_RAM_R17C0 = $0ea8 ; x-ref: $23AC |
| SCREEN_RAM_R18C0 = $0ed0 ; x-ref: $23B2 |
| SCREEN_RAM_R19C0 = $0ef8 ; x-ref: $23B8 |
| SCREEN_RAM_R19C8 = $0f00 ; x-ref: $204A |
| SCREEN_RAM_R20C0 = $0f20 ; x-ref: $23BE |
| SCREEN_RAM_R21C0 = $0f48 ; x-ref: $206C |
| SCREEN_RAM_R23C0 = $0f98 ; x-ref: $2086 |
| SCREEN_RAM_R24C0 = $0fc0 ; x-ref: $208E |
|
| ; ENUMS |
| ; Enum: GameMode |
| GameMode = { |
| NORMAL_RIDE: $00, |
| CRASH_DEBRIS: $01, |
| ACTIVE_RIDE: $02, |
| STARTING_GATE: $03, |
| TRACK_SCROLL: $04, |
| DEBRIS_WAIT: $05, |
| RESULTS_SCREEN: $06, |
| VELOCITY_INTEGRATE: $07, |
| NEXT_LAP_INIT: $08 |
| } |
|
| ; charset |
| $1000 | | .fill8, $00 |
| $1008 | | .byte$ee, $b7, $be, $eb, $ac, $ea, $9a, $aa |
| $1010 | | .byte$55, $55, $ff, $ff, $f9, $bf, $3a, $eb |
| $1018 | | .byte$55, $55, $ff, $cf, $fb, $ef, $e6, $eb |
| $1020 | | .byte$ff, $df, $ff, $fc, $ff, $3f, $ff, $fd |
| $1028 | | .byte$ff, $cf, $ff, $fd, $ff, $7b, $ff, $ff |
| $1030 | | .byte$00, $00, $00, $80, $40, $b0, $98, $2e |
| $1038 | | .byte$00, $00, $00, $00, $00, $00, $00, $82 |
| $1040 | | .byte$00, $00, $00, $03, $02, $0e, $29, $ea |
| $1048 | | .byte$55, $55, $02, $0a, $28, $28, $0a, $3f |
| $1050 | | .byte$55, $55, $82, $00, $00, $00, $ff, $3c |
| $1058 | | .byte$55, $55, $80, $a0, $28, $28, $a0, $fc |
| $1060 | | .byte$03, $0f, $3c, $35, $32, $f6, $ca, $da |
| $1068 | | .byte$c0, $e0, $68, $48, $98, $9a, $f2, $f6 |
| $1070 | | .byte$da, $ca, $f7, $33, $35, $3c, $0e, $02 |
| $1078 | | .byte$f6, $f2, $da, $d8, $48, $68, $a0, $80 |
| $1080 | | .byte$fd, $fd, $fd, $55, $df, $df, $df, $55 |
| $1088 | | .byte$ff, $de, $ff, $ef, $f3, $7f, $ee, $bb |
| $1090 | | .byte$7f, $1f, $07, $01, $00, $00, $00, $00 |
| $1098 | | .byte$f4, $d0, $40, $00, $00, $00, $00, $00 |
| $10A0 | | .byte$0f, $3f, $35, $f5, $d5, $d5, $d5, $d5 |
| $10A8 | | .byte$ff, $ff, $75, $75, $75, $75, $75, $fd |
| $10B0 | | .byte$c0, $f0, $70, $7c, $5c, $5c, $5c, $5c |
| $10B8 | | .byte$ff, $ff, $d5, $d5, $d5, $d5, $d5, $ff |
| $10C0 | | .byte$ff, $57, $55, $55, $55, $55, $55, $ff |
| $10C8 | | .byte$fc, $fc, $5c, $5c, $5c, $5c, $5c, $fc |
| $10D0 | | .byte$ff, $fc, $f3, $cf, $cd, $cf, $fd, $ff |
| $10D8 | | .byte$ff, $fc, $ff, $ff, $55, $ff, $55, $ff |
| $10E0 | | .byte$fc, $fc, $3c, $cc, $cc, $cc, $fc, $fc |
| $10E8 | | .byte$df, $df, $ff, $eb, $eb, $2b, $28, $28 |
| $10F0 | | .byte$57, $ff, $ff, $03, $ff, $ff, $00, $00 |
| $10F8 | | .byte$dc, $dc, $fc, $ac, $ac, $a0, $a0, $a0 |
| $1100 | | .byte$00, $03, $0f, $0e, $0f, $37, $3f, $fb |
| $1108 | | .byte$cc, $3c, $fb, $ef, $bc, $ef, $ef, $bf |
| $1110 | | .byte$00, $00, $c0, $c0, $c0, $f0, $70, $fc |
| $1118 | | .byte$fb, $cb, $3e, $fe, $ee, $fb, $2f, $fb |
| $1120 | | .byte$bf, $ee, $ee, $ee, $fb, $7b, $fb, $fe |
| $1128 | | .byte$bc, $f0, $fc, $cc, $fc, $e0, $bc, $fc |
| $1130 | | .byte$fe, $3e, $df, $fb, $cb, $3e, $3f, $0f |
| $1138 | | .byte$fe, $cb, $bb, $bb, $ef, $ef, $ff, $ef |
| $1140 | | .byte$cc, $fc, $e0, $ec, $bc, $b0, $c0, $f0 |
| $1148 | | .byte$0c, $03, $00, $00, $00, $00, $02, $eb |
| $1150 | | .byte$ed, $ef, $20, $20, $a8, $a8, $ee, $ab |
| $1158 | | .byte$80, $00, $00, $00, $00, $00, $00, $ac |
| $1160 | | .byte$c0, $55, $55, $0f, $33, $55, $55, $00 |
| $1168 | | .byte$00, $55, $55, $00, $c0, $55, $55, $03 |
| $1170 | | .byte$00, $55, $55, $00, $03, $5f, $7d, $c0 |
| $1178 | | .byte$03, $5f, $7d, $f0, $c0, $55, $55, $00 |
| $1180 | | .byte$00, $55, $55, $03, $0f, $7d, $f5, $c0 |
| $1188 | | .byte$0f, $7d, $f5, $c0, $00, $55, $55, $00 |
| $1190 | | .byte$c0, $55, $55, $03, $00, $55, $55, $00 |
| $1198 | | .byte$00, $55, $55, $c0, $f0, $55, $55, $03 |
| $11A0 | | .byte$18, $18, $18, $18, $30, $30, $30, $30 |
| $11A8 | | .byte$60, $60, $60, $60, $c3, $cf, $ff, $f3 |
| $11B0 | | .byte$c6, $06, $06, $06, $0c, $0c, $0c, $0c |
| $11B8 | | .byte$00, $3c, $7e, $7e, $7e, $7e, $3c, $00 |
| $11C0 | | .byte$0f, $3f, $3f, $f7, $f7, $ff, $ff, $ff |
| $11C8 | | .byte$ff, $ff, $3f, $3f, $0f, $01, $04, $01 |
| $11D0 | | .byte$00, $01, $00, $00, $00, $00, $00, $00 |
| $11D8 | | .byte$c0, $f0, $f0, $fc, $fc, $fc, $fc, $fc |
| $11E0 | | .byte$fc, $cc, $30, $f0, $c0, $00, $00, $00 |
| $11E8 | | .byte$40 |
| $11E9 | | .fill9, $00 |
| $11F2 | | .byte$0f, $3f, $3f, $f7, $f7, $ff, $ff, $ff |
| $11FA | | .byte$ff, $ff, $3f, $3f, $0f, $01, $04, $01 |
| $1202 | | .byte$00, $01, $00, $00, $00, $00, $00, $00 |
| $120A | | .byte$c0, $f0, $f0, $fc, $fc, $fc, $fc, $fc |
| $1212 | | .byte$fc, $cc, $30, $f0, $c0, $00, $00, $00 |
| $121A | | .byte$40 |
| $121B | | .fill9, $00 |
| $1224 | | .byte$0f, $3f, $3f, $f7, $f7, $ff, $ff, $ff |
| $122C | | .byte$ff, $ff, $3f, $3f, $0f, $01, $04, $01 |
| $1234 | | .byte$00, $01, $00, $00, $00, $00, $00, $00 |
| $123C | | .byte$c0, $f0, $f0, $fc, $fc, $fc, $fc, $fc |
| $1244 | | .byte$fc, $cc, $30, $f0, $c0, $00, $00, $00 |
| $124C | | .byte$40 |
| $124D | | .fill9, $00 |
| $1256 | | .byte$0f, $3f, $3f, $f7, $f7, $ff, $ff, $ff |
| $125E | | .byte$ff, $ff, $3f, $3f, $0f, $01, $04, $01 |
| $1266 | | .byte$00, $01, $00, $00, $00, $00, $00, $00 |
| $126E | | .byte$c0, $f0, $f0, $fc, $fc, $fc, $fc, $fc |
| $1276 | | .byte$fc, $cc, $30, $f0, $c0, $00, $00, $00 |
| $127E | | .byte$40, $00, $0f, $0f, $03, $03, $03, $03 |
| $1286 | | .byte$fd, $fd, $c3, $c3, $03, $03, $03, $03 |
| $128E | | .fill14, $00 |
| $129C | | .byte$0c, $0c, $fc, $fc, $00, $00, $00, $00 |
| $12A4 | | .byte$c0, $c0 |
| $12A6 | | .fill12, $00 |
| $12B2 | | .byte$3c, $3c, $0f, $0f, $03, $03, $01, $0d |
| $12BA | | .byte$3f, $f3, $c3, $f3, $30 |
| $12BF | | .fill12, $00 |
| $12CB | | .byte$30, $3c, $0c, $3c, $f0, $c0, $00, $00 |
| $12D3 | | .byte$00, $c0, $c0, $f0, $f0 |
| $12D8 | | .fill14, $00 |
| $12E6 | | .byte$30, $f0, $cc, $0f, $01, $01, $0f, $0c |
| $12EE | | .byte$30, $30, $3c, $0c |
| $12F2 | | .fill10, $00 |
| $12FC | | .byte$c0, $f0, $30, $30, $c0, $c0, $00, $00 |
| $1304 | | .byte$c0, $cc, $3c, $30 |
| $1308 | | .fill14, $00 |
| $1316 | | .byte$03, $03, $00, $03, $33, $ff, $cd, $c1 |
| $131E | | .byte$03, $03, $0f, $0c, $0f, $03 |
| $1324 | | .fill11, $00 |
| $132F | | .byte$c0, $c0, $c0, $00, $00, $0c, $cc, $fc |
| $1337 | | .byte$30 |
| $1338 | | .fill12, $00 |
| $1344 | | .byte$3c, $f3, $3f, $03, $00, $00, $03, $3f |
| $134C | | .byte$cf, $ff, $f3, $00, $00, $00, $c3, $ff |
| $1354 | | .byte$3c, $ff, $fc, $f0, $00, $00, $00, $f0 |
| $135C | | .byte$ff, $3c, $f0, $00, $00, $0c, $3f, $cf |
| $1364 | | .byte$ff, $ff, $f3, $3f, $00, $00, $0c, $3f |
| $136C | | .byte$f3, $3f, $fc, $cf, $00, $00, $00, $0c |
| $1374 | | .byte$fc, $fc, $ff, $f3, $00, $00, $30, $fc |
| $137C | | .byte$3c, $ff, $cf, $fc, $00, $00, $00, $02 |
| $1384 | | .byte$02, $02, $02, $01, $2d, $2a, $ba, $ce |
| $138C | | .byte$32, $fe, $de, $dc, $fc, $30, $00, $00 |
| $1394 | | .byte$00, $00, $00, $00, $30, $d0, $90, $80 |
| $139C | | .byte$80, $20, $04, $41, $5a, $9a, $9e, $6c |
| $13A4 | | .byte$63, $cf, $0d, $0d, $0f, $03 |
| $13AA | | .fill15, $00 |
| $13B9 | | .byte$80, $80, $c0, $00, $c0, $c0, $c0, $c0 |
| $13C1 | | .fill15, $00 |
| $13D0 | | .byte$08, $0a, $2e, $33, $0c, $3f, $37, $37 |
| $13D8 | | .byte$3f, $0c, $00, $00, $00, $00, $00, $00 |
| $13E0 | | .byte$0c, $34, $24, $a0, $a0, $88, $81, $50 |
| $13E8 | | .byte$56, $a6, $a6, $91, $98, $b3, $83, $03 |
| $13F0 | | .byte$03 |
| $13F1 | | .fill14, $00 |
| $13FF | | .byte$40, $80, $a0, $e0, $30, $c0, $f0, $70 |
| $1407 | | .byte$70, $f0, $c0 |
| $140A | | .fill14, $00 |
| $1418 | | .byte$02, $02, $0b, $0c, $03, $0f, $0d, $0d |
| $1420 | | .byte$0f, $03, $00, $00, $00, $00, $00, $00 |
| $1428 | | .byte$03, $0d, $09, $28, $28, $22, $20, $14 |
| $1430 | | .byte$d5, $a9, $a9, $e6, $26, $ec, $e0, $c0 |
| $1438 | | .byte$c0 |
| $1439 | | .fill13, $00 |
| $1446 | | .byte$40, $10, $a0, $a8, $e8, $cc, $30, $fc |
| $144E | | .byte$dc, $dc, $fc, $30 |
| $1452 | | .fill16, $00 |
| $1462 | | .byte$02, $03, $00, $03, $03, $03, $03 |
| $1469 | | .fill8, $00 |
| $1471 | | .byte$03, $02, $0a, $0a, $08, $08, $05, $85 |
| $1479 | | .byte$aa, $ea, $39, $c9, $fb, $78, $70, $f0 |
| $1481 | | .byte$c0, $00, $00, $00, $00, $00, $00, $c0 |
| $1489 | | .byte$40, $40, $00, $00, $80, $10, $04, $68 |
| $1491 | | .byte$6a, $6e, $b3, $8c, $3f, $37, $37, $3f |
| $1499 | | .byte$0c |
| $149A | | .fill11, $00 |
| $14A5 | | .byte$02, $02, $02, $02, $01, $2d, $2a, $ba |
| $14AD | | .byte$ce, $32, $fe, $de, $dc, $fc, $30, $00 |
| $14B5 | | .byte$00, $00, $00, $00, $00, $30, $d0, $90 |
| $14BD | | .byte$80, $80, $20, $04, $41, $5a, $9a, $9e |
| $14C5 | | .byte$6c, $63, $cf, $0d, $0d, $0f, $03 |
| $14CC | | .fill15, $00 |
| $14DB | | .byte$80, $80, $c0, $00, $c0, $c0, $c0, $c0 |
| $14E3 | | .fill15, $00 |
| $14F2 | | .byte$08, $0a, $2e, $33, $0c, $3f, $37, $37 |
| $14FA | | .byte$3f, $0c, $00, $00, $00, $00, $00, $00 |
| $1502 | | .byte$0c, $34, $24, $a0, $a0, $88, $81, $50 |
| $150A | | .byte$56, $a6, $a6, $91, $98, $b3, $83, $03 |
| $1512 | | .byte$03 |
| $1513 | | .fill14, $00 |
| $1521 | | .byte$40, $80, $a0, $e0, $30, $c0, $f0, $70 |
| $1529 | | .byte$70, $f0, $c0 |
| $152C | | .fill14, $00 |
| $153A | | .byte$02, $02, $0b, $0c, $03, $0f, $0d, $0d |
| $1542 | | .byte$0f, $03, $00, $00, $00, $00, $00, $00 |
| $154A | | .byte$03, $0d, $09, $28, $28, $22, $20, $14 |
| $1552 | | .byte$d5, $a9, $a9, $e6, $26, $ec, $e0, $c0 |
| $155A | | .byte$c0 |
| $155B | | .fill13, $00 |
| $1568 | | .byte$40, $10, $a0, $a8, $e8, $cc, $30, $fc |
| $1570 | | .byte$dc, $dc, $fc, $30 |
| $1574 | | .fill16, $00 |
| $1584 | | .byte$02, $03, $00, $03, $03, $03, $03 |
| $158B | | .fill8, $00 |
| $1593 | | .byte$03, $02, $0a, $0a, $08, $08, $05, $85 |
| $159B | | .byte$aa, $ea, $39, $c9, $fb, $78, $70, $f0 |
| $15A3 | | .byte$c0, $00, $00, $00, $00, $00, $00, $c0 |
| $15AB | | .byte$40, $40, $00, $00, $80, $10, $04, $68 |
| $15B3 | | .byte$6a, $6e, $b3, $8c, $3f, $37, $37, $3f |
| $15BB | | .byte$0c |
| $15BC | | .fill11, $00 |
| $15C7 | | .byte$02, $02, $02, $02, $01, $2d, $2a, $ba |
| $15CF | | .byte$ce, $32, $fe, $de, $dc, $fc, $30, $00 |
| $15D7 | | .byte$00, $00, $00, $00, $00, $30, $d0, $90 |
| $15DF | | .byte$80, $80, $20, $04, $41, $5a, $9a, $9e |
| $15E7 | | .byte$6c, $63, $cf, $0d, $0d, $0f, $03 |
| $15EE | | .fill15, $00 |
| $15FD | | .byte$80, $80, $c0, $00, $c0, $c0, $c0, $c0 |
| $1605 | | .fill15, $00 |
| $1614 | | .byte$08, $0a, $2e, $33, $0c, $3f, $37, $37 |
| $161C | | .byte$3f, $0c, $00, $00, $00, $00, $00, $00 |
| $1624 | | .byte$0c, $34, $24, $a0, $a0, $88, $81, $50 |
| $162C | | .byte$56, $a6, $a6, $91, $98, $b3, $83, $03 |
| $1634 | | .byte$03 |
| $1635 | | .fill14, $00 |
| $1643 | | .byte$40, $80, $a0, $e0, $30, $c0, $f0, $70 |
| $164B | | .byte$70, $f0, $c0 |
| $164E | | .fill14, $00 |
| $165C | | .byte$02, $02, $0b, $0c, $03, $0f, $0d, $0d |
| $1664 | | .byte$0f, $03, $00, $00, $00, $00, $00, $00 |
| $166C | | .byte$03, $0d, $09, $28, $28, $22, $20, $14 |
| $1674 | | .byte$d5, $a9, $a9, $e6, $26, $ec, $e0, $c0 |
| $167C | | .byte$c0 |
| $167D | | .fill13, $00 |
| $168A | | .byte$40, $10, $a0, $a8, $e8, $cc, $30, $fc |
| $1692 | | .byte$dc, $dc, $fc, $30 |
| $1696 | | .fill16, $00 |
| $16A6 | | .byte$02, $03, $00, $03, $03, $03, $03 |
| $16AD | | .fill8, $00 |
| $16B5 | | .byte$03, $02, $0a, $0a, $08, $08, $05, $85 |
| $16BD | | .byte$aa, $ea, $39, $c9, $fb, $78, $70, $f0 |
| $16C5 | | .byte$c0, $00, $00, $00, $00, $00, $00, $c0 |
| $16CD | | .byte$40, $40, $00, $00, $80, $10, $04, $68 |
| $16D5 | | .byte$6a, $6e, $b3, $8c, $3f, $37, $37, $3f |
| $16DD | | .byte$0c |
| $16DE | | .fill11, $00 |
| $16E9 | | .byte$02, $02, $02, $02, $01, $2d, $2a, $ba |
| $16F1 | | .byte$ce, $32, $fe, $de, $dc, $fc, $30, $00 |
| $16F9 | | .byte$00, $00, $00, $00, $00, $30, $d0, $90 |
| $1701 | | .byte$80, $80, $20, $04, $41, $5a, $9a, $9e |
| $1709 | | .byte$6c, $63, $cf, $0d, $0d, $0f, $03 |
| $1710 | | .fill15, $00 |
| $171F | | .byte$80, $80, $c0, $00, $c0, $c0, $c0, $c0 |
| $1727 | | .fill15, $00 |
| $1736 | | .byte$08, $0a, $2e, $33, $0c, $3f, $37, $37 |
| $173E | | .byte$3f, $0c, $00, $00, $00, $00, $00, $00 |
| $1746 | | .byte$0c, $34, $24, $a0, $a0, $88, $81, $50 |
| $174E | | .byte$56, $a6, $a6, $91, $98, $b3, $83, $03 |
| $1756 | | .byte$03 |
| $1757 | | .fill14, $00 |
| $1765 | | .byte$40, $80, $a0, $e0, $30, $c0, $f0, $70 |
| $176D | | .byte$70, $f0, $c0 |
| $1770 | | .fill14, $00 |
| $177E | | .byte$02, $02, $0b, $0c, $03, $0f, $0d, $0d |
| $1786 | | .byte$0f, $03, $00, $00, $00, $00, $00, $00 |
| $178E | | .byte$03, $0d, $09, $28, $28, $22, $20, $14 |
| $1796 | | .byte$d5, $a9, $a9, $e6, $26, $ec, $e0, $c0 |
| $179E | | .byte$c0 |
| $179F | | .fill13, $00 |
| $17AC | | .byte$40, $10, $a0, $a8, $e8, $cc, $30, $fc |
| $17B4 | | .byte$dc, $dc, $fc, $30 |
| $17B8 | | .fill16, $00 |
| $17C8 | | .byte$02, $03, $00, $03, $03, $03, $03 |
| $17CF | | .fill8, $00 |
| $17D7 | | .byte$03, $02, $0a, $0a, $08, $08, $05, $85 |
| $17DF | | .byte$aa, $ea, $39, $c9, $fb, $78, $70, $f0 |
| $17E7 | | .byte$c0, $00, $00, $00, $00, $00, $00, $c0 |
| $17EF | | .byte$40, $40, $00, $00, $80, $10, $04, $68 |
| $17F7 | | .byte$6a, $6e, $b3, $8c, $3f, $37, $37, $3f |
| $17FF | | .byte$0c |
| ; double-height characters charst |
| $1800 | | .fill8, $00 |
| $1808 | | .byte$3c, $3c, $66, $66, $c0, $c0, $c0, $c0 |
| $1810 | | .byte$7e, $7e, $60, $60, $60, $60, $7c, $7c |
| $1818 | | .byte$3e, $3e, $60, $60, $c0, $c0, $ce, $ce |
| $1820 | | .byte$c6, $c6, $c6, $c6, $c6, $c6, $fe, $fe |
| $1828 | | .byte$7e, $7e, $18, $18, $18, $18, $18, $18 |
| $1830 | | .byte$c6, $c6, $ee, $ee, $fe, $fe, $fe, $fe |
| $1838 | | .byte$7c, $7c, $c6, $c6, $c6, $c6, $c6, $c6 |
| $1840 | | .byte$fc, $fc, $e6, $e6, $c6, $c6, $cc, $cc |
| $1848 | | .byte$78, $78, $cc, $cc, $c0, $c0, $7c, $7c |
| $1850 | | .byte$7e, $7e, $18, $18, $18, $18, $18, $18 |
| $1858 | | .byte$38, $38, $4c, $4c, $c6, $c6, $c6, $c6 |
| $1860 | | .byte$18, $18, $38, $38, $18, $18, $18, $18 |
| $1868 | | .byte$7c, $7c, $c6, $c6, $0e, $0e, $3c, $3c |
| $1870 | | .byte$7e, $7e, $0c, $0c, $18, $18, $3c, $3c |
| $1878 | | .byte$1c, $1c, $3c, $3c, $6c, $6c, $cc, $cc |
| $1880 | | .byte$fc, $fc, $c0, $c0, $fc, $fc, $06, $06 |
| $1888 | | .byte$3c, $3c, $60, $60, $c0, $c0, $fc, $fc |
| $1890 | | .byte$fe, $fe, $06, $06, $0c, $0c, $18, $18 |
| $1898 | | .byte$78, $78, $c4, $c4, $e4, $e4, $78, $78 |
| $18A0 | | .byte$7c, $7c, $c6, $c6, $c6, $c6, $7e, $7e |
| $18A8 | | .byte$c0, $c0, $66, $66, $3c, $3c, $00, $00 |
| $18B0 | | .byte$60, $60, $60, $60, $7e, $7e, $00, $00 |
| $18B8 | | .byte$c6, $c6, $66, $66, $3e, $3e, $00, $00 |
| $18C0 | | .byte$c6, $c6, $c6, $c6, $c6, $c6, $00, $00 |
| $18C8 | | .byte$18, $18, $18, $18, $7e, $7e, $00, $00 |
| $18D0 | | .byte$d6, $d6, $c6, $c6, $c6, $c6, $00, $00 |
| $18D8 | | .byte$c6, $c6, $c6, $c6, $7c, $7c, $00, $00 |
| $18E0 | | .byte$f8, $f8, $dc, $dc, $ce, $ce, $00, $00 |
| $18E8 | | .byte$06, $06, $c6, $c6, $7c, $7c, $00, $00 |
| $18F0 | | .byte$18, $18, $18, $18, $18, $18, $00, $00 |
| $18F8 | | .byte$c6, $c6, $64, $64, $38, $38, $00, $00 |
| $1900 | | .byte$18, $18, $18, $18, $7e, $7e, $00, $00 |
| $1908 | | .byte$78, $78, $e0, $e0, $fe, $fe, $00, $00 |
| $1910 | | .byte$06, $06, $c6, $c6, $7c, $7c, $00, $00 |
| $1918 | | .byte$fe, $fe, $0c, $0c, $0c, $0c, $00, $00 |
| $1920 | | .byte$06, $06, $c6, $c6, $7c, $7c, $00, $00 |
| $1928 | | .byte$c6, $c6, $c6, $c6, $7c, $7c, $00, $00 |
| $1930 | | .byte$30, $30, $30, $30, $30, $30, $00, $00 |
| $1938 | | .byte$9e, $9e, $86, $86, $7c, $7c, $00, $00 |
| $1940 | | .byte$06, $06, $0c, $0c, $78, $78, $00, $00 |
| ; Packed music notes. High nibble=Voice 2, Low nibble=Voice 1 |
| $1948 | | music_packed_notes.byte$91, $91, $91, $94, $94, $94, $72, $72; x-ref: $2ABA, $2AD0 |
| $1950 | | .byte$72, $74, $74, $74, $41, $41, $41, $44 |
| $1958 | | .byte$44, $44, $72, $72, $92, $d4, $d4, $94 |
| $1960 | | .byte$c4, $c4, $c4, $b8, $b8, $b8, $a6, $a6 |
| $1968 | | .byte$86, $88, $88, $88, $64, $64, $64, $68 |
| $1970 | | .byte$68, $68, $66, $66, $66, $68, $68, $68 |
| $1978 | | .byte$84, $84, $84, $88, $88, $88, $66, $66 |
| $1980 | | .byte$66, $68, $68, $68, $44, $44, $44, $48 |
| $1988 | | .byte$48, $48, $66, $66, $86, $d8, $d8, $e8 |
| $1990 | | .byte$d3, $d3, $d3, $c7, $c7, $c7, $a5, $a5 |
| $1998 | | .byte$95, $97, $97, $97, $c4, $c4, $c4, $a8 |
| $19A0 | | .byte$a8, $a8, $96, $96, $86, $88, $88, $88 |
| $19A8 | | .byte$91, $91, $91, $94, $94, $94, $72, $72 |
| $19B0 | | .byte$72, $74, $74, $74, $41, $41, $41, $44 |
| $19B8 | | .byte$44, $44, $72, $72, $92, $d4, $d4, $94 |
| $19C0 | | .byte$c4, $c4, $c4, $b8, $b8, $b8, $a6, $a6 |
| $19C8 | | .byte$86, $88, $88, $88, $64, $64, $64, $68 |
| $19D0 | | .byte$68, $68, $66, $66, $66, $68, $68, $68 |
| $19D8 | | .byte$c4, $c4, $c4, $b8, $b8, $b8, $a6, $a6 |
| $19E0 | | .byte$86, $88, $88, $88, $64, $64, $64, $68 |
| $19E8 | | .byte$68, $68, $46, $46, $46, $48, $48, $48 |
| $19F0 | | .byte$71, $71, $71, $74, $74, $74, $72, $72 |
| $19F8 | | .byte$72, $74, $74, $74, $71, $71, $71, $74 |
| $1A00 | | .byte$74, $74, $72, $72, $72, $74, $74, $74 |
| ; Voice 2 frequency low bytes for music |
| $1A08 | | voice_2_freq_lo.byte<$0000, <$0000, <$0000, <$0000, <$0304; x-ref: $2AC4 |
| $1A0D | | .byte<$0320, <$0338, <$0343, <$0358, <$036a |
| $1A12 | | .byte<$0373, <$037b, <$0382, <$0390, <$039c |
| $1A17 | | .byte<$0000 |
| $1A18 | | voice_2_freq_hi.byte>$0000, >$0000, >$0000, >$0000, >$0304; x-ref: $2ACA |
| $1A1D | | .byte>$0320, >$0338, >$0343, >$0358, >$036a |
| $1A22 | | .byte>$0373, >$037b, >$0382, >$0390, >$039c |
| $1A27 | | .byte>$0000 |
| ; Voice 1 frequency low bytes for music |
| $1A28 | | voice_1_freq_lo.byte<$0000, <$010d, <$01a9, <$01ca, <$0208; x-ref: $2AD6 |
| $1A2D | | .byte<$023f, <$0270, <$0287, <$02b0, <$0000 |
| $1A32 | | .byte<$0000, <$0000, <$0000, <$0000, <$0000 |
| $1A37 | | .byte<$0000 |
| $1A38 | | voice_1_freq_hi.byte>$0000, >$010d, >$01a9, >$01ca, >$0208; x-ref: $2ADC |
| $1A3D | | .byte>$023f, >$0270, >$0287, >$02b0, >$0000 |
| $1A42 | | .byte>$0000, >$0000, >$0000, >$0000, >$0000 |
| $1A47 | | .byte>$0000 |
| $1A48 | | .byte$00, $00, $00, $00, $2f, $2a, $ba, $ce |
| $1A50 | | .byte$32, $fe, $de, $dc, $fc, $30, $00, $00 |
| $1A58 | | .byte$00, $00, $04, $01, $2a, $aa, $ae, $ac |
| $1A60 | | .byte$a3, $cf, $0d, $0d, $0f, $03, $00, $00 |
| $1A68 | | .byte$00, $00, $00, $00, $00, $80, $80, $c0 |
| $1A70 | | .byte$00, $c0, $c0, $c0, $c0, $00, $00, $00 |
| $1A78 | | .byte$b0, $bc, $bf, $bf, $bc, $b0, $80, $80; flag upper |
| $1A80 | | .byte$80, $80, $80, $80, $80, $80, $00, $00; flag bottom |
| $1A88 | | .byte$18, $18, $08, $08, $10, $10, $00, $00 |
| $1A90 | | .byte$38, $4c, $c6, $c6, $c6, $64, $38, $00; 0 |
| $1A98 | | .byte$18, $38, $18, $18, $18, $18, $7e, $00 |
| $1AA0 | | .byte$7c, $c6, $0e, $3c, $78, $e0, $fe, $00 |
| $1AA8 | | .byte$7e, $0c, $18, $3c, $06, $c6, $7c, $00 |
| $1AB0 | | .byte$1c, $3c, $6c, $cc, $fe, $0c, $0c, $00 |
| $1AB8 | | .byte$fc, $c0, $fc, $06, $06, $c6, $7c, $00 |
| $1AC0 | | .byte$3c, $60, $c0, $fc, $c6, $c6, $7c, $00 |
| $1AC8 | | .byte$fe, $c6, $0c, $18, $30, $30, $30, $00 |
| $1AD0 | | .byte$78, $c4, $e4, $78, $9e, $86, $7c, $00 |
| $1AD8 | | .byte$7c, $c6, $c6, $7e, $06, $0c, $78, $00 |
| $1AE0 | | .byte$00, $00, $00, $00, $00, $18, $18, $00 |
| $1AE8 | | .byte$00, $00, $00, $00, $00, $18, $08, $10 |
| $1AF0 | | .byte$1c, $1c, $1c, $18, $00, $18, $18, $00 |
| $1AF8 | | .byte$18, $08, $10, $00, $00, $00, $00, $00; ' |
| $1B00 | | .byte$00, $00, $00, $3c, $3c, $00, $00, $00; - |
| $1B08 | | .byte$38, $6c, $c6, $c6, $fe, $c6, $c6, $00 |
| $1B10 | | .byte$fc, $c6, $c6, $fc, $c6, $c6, $fc, $00 |
| $1B18 | | .byte$3c, $66, $c0, $c0, $c0, $66, $3c, $00 |
| $1B20 | | .byte$f8, $cc, $c6, $c6, $c6, $cc, $f8, $00 |
| $1B28 | | .byte$7e, $60, $60, $7c, $60, $60, $7e, $00 |
| $1B30 | | .byte$7e, $60, $60, $7c, $60, $60, $60, $00 |
| $1B38 | | .byte$3e, $60, $c0, $ce, $c6, $66, $3e, $00 |
| $1B40 | | .byte$c6, $c6, $c6, $fe, $c6, $c6, $c6, $00 |
| $1B48 | | .byte$7e, $18, $18, $18, $18, $18, $7e, $00 |
| $1B50 | | .byte$06, $06, $06, $06, $06, $c6, $7c, $00 |
| $1B58 | | .byte$c6, $cc, $d8, $f0, $f8, $dc, $ce, $00 |
| $1B60 | | .byte$60, $60, $60, $60, $60, $60, $7e, $00 |
| $1B68 | | .byte$c6, $ee, $fe, $fe, $d6, $c6, $c6, $00 |
| $1B70 | | .byte$c6, $e6, $f6, $fe, $de, $ce, $c6, $00 |
| $1B78 | | .byte$7c, $c6, $c6, $c6, $c6, $c6, $7c, $00 |
| $1B80 | | .byte$fc, $c6, $c6, $c6, $fc, $c0, $c0, $00 |
| $1B88 | | .byte$7c, $c6, $c6, $c6, $ce, $cc, $7a, $00 |
| $1B90 | | .byte$fc, $e6, $c6, $cc, $f8, $dc, $ce, $00 |
| $1B98 | | .byte$78, $cc, $c0, $7c, $06, $c6, $7c, $00 |
| $1BA0 | | .byte$7e, $18, $18, $18, $18, $18, $18, $00 |
| $1BA8 | | .byte$c6, $c6, $c6, $c6, $c6, $c6, $7c, $00 |
| $1BB0 | | .byte$c6, $c6, $c6, $ee, $7c, $38, $10, $00 |
| $1BB8 | | .byte$c6, $c6, $d6, $fe, $fe, $6c, $44, $00 |
| $1BC0 | | .byte$c6, $ee, $7c, $38, $7c, $ee, $c6, $00; x |
| $1BC8 | | .byte$66, $66, $66, $3c, $18, $18, $18; y |
| $1BCF | | .fill49, $00 |
| $1C00 | | track_column_colors.byte$00, $49, $4b, $4d, $49, $4b, $4d, $49; x-ref: $2083 |
| $1C08 | | .byte$4b, $4d, $49, $4b, $4d, $49, $4b, $4d |
| $1C10 | | .byte$00, $00, $00, $00, $00, $00, $00 |
| $1C17 | | .fill16, $4f |
| $1C27 | | .byte$00 |
| $1C28 | | track_tile_indices.byte$00, $00, $0a, $05, $06, $02, $00, $0b; x-ref: $2091, $2D92 |
| $1C30 | | .byte$0b, $51, $0b, $0b, $00, $09, $01, $07 |
| $1C38 | | .byte$08, $02, $00, $0b, $0b, $0b, $0b, $0b |
| $1C40 | | .byte$0b, $0b, $00, $04, $05, $03, $04, $00 |
| $1C48 | | .byte$0b, $0b, $0b, $0c, $0b, $0b, $0b, $00 |
| $1C50 | | screen_row_addr_lo.byte<$0c00, <$0c28, <$0c50, <$0c78, <$0ca0; x-ref: $21DF, $220D |
| $1C55 | | .byte<$0cc8, <$0cf0, <$0d18, <$0d40, <$0d68 |
| $1C5A | | .byte<$0d90, <$0db8, <$0de0, <$0e08, <$0e30 |
| $1C5F | | .byte<$0e58, <$0e80, <$0ea8, <$0ed0, <$0ef8 |
| $1C64 | | .byte<$0f20, <$0f48, <$0f70, <$0f98 |
| $1C68 | | screen_row_addr_hi.byte>$0c00, >$0c28, >$0c50, >$0c78, >$0ca0; x-ref: $21E4, $2212 |
| $1C6D | | .byte>$0cc8, >$0cf0, >$0d18, >$0d40, >$0d68 |
| $1C72 | | .byte>$0d90, >$0db8, >$0de0, >$0e08, >$0e30 |
| $1C77 | | .byte>$0e58, >$0e80, >$0ea8, >$0ed0, >$0ef8 |
| $1C7C | | .byte>$0f20, >$0f48, >$0f70, >$0f98 |
| $1C80 | | debris_vel_x.byte$ff, $ff, $ff, $00, $01, $01, $01, $00; x-ref: $2448 |
| $1C88 | | debris_vel_y.byte$ff, $00, $01, $01, $01, $00, $ff, $ff; x-ref: $2433 |
| obstacle_color_normal |
| $1C90 | | .byte$3a, $4d, $5f, $2e, $3a, $4d, $5f, $2e; x-ref: $2249 |
| | .encode |
| | .enc"none" |
| $1C98 | | level_select_text.text"level", $00, "RR"; x-ref: $2DD0 |
| | .endencode |
| $1CA0 | | obstacle_col_deltas.byte$00, $01, $01, $fe, $01, $01, $00, $00; x-ref: $22F3 |
| $1CA8 | | obstacle_color_wide.fill8, $79; x-ref: $2294 |
| $1CB0 | | .byte$69, $59, $49, $39, $29, $19, $09, $09 |
| $1CB8 | | .byte$09, $09, $19, $29, $39, $49, $59, $69 |
| $1CC0 | | .fill8, $79 |
| $1CC8 | | bike_char_base.byte$70, $79, $82, $8b; x-ref: $2472, $247D |
| $1CCC | | bike_subpos_offset.byte$00, $24, $48, $6c; x-ref: $2487, $248F |
| debris_start_x_positions |
| $1CD0 | | .byte$18, $18, $18, $10, $08, $08, $08, $10; x-ref: $2672 |
| $1CD8 | | .byte$13, $0b, $03, $03, $03, $0b, $13, $13 |
| | .encode |
| | .enc"none" |
| ; Text for 'game over' or course end |
| $1CE0 | | course_end_text.text"game", $00, "over", $00, "^^^^", $00, $00; x-ref: $26CE |
| ; Text for 'bonus for time left' |
| $1CF0 | | time_bonus_text.text"bonus", $00, "for", $00, "time", $00, "left", $00, $00, "RRR"; x-ref: $2966 |
| ; Text for 'bikes left bonus' |
| bikes_left_bonus_text |
| $1D08 | | .text"bikes", $00, "left", $00, "bonus", $00, $00, $00, $00, $00; x-ref: $296C |
| | .endencode |
| $1D1D | | .byte$52, $52, $52 |
| $1D20 | | .fill24, $00 |
| ; First character of the bonus score amount |
| $1D38 | | bonus_value_char1.byte$00, $53, $54, $56, $59, $5b, $00, $00; x-ref: $299E |
| ; Second character of the bonus score amount |
| $1D40 | | bonus_value_char2.byte$00, $52, $57, $52, $57, $5b, $00, $00; x-ref: $29A4 |
| | .encode |
| | .enc"none" |
| ; Text for 'extra bike awarded' |
| extra_bike_awarded_text |
| $1D48 | | .text"extra", $00, "bike", $00, "awarded\\\\\\"; x-ref: $2A60 |
| ; Text for 'five bikes left still' |
| $1D60 | | five_bikes_left_text.text"five", $00, "bikes", $00, "left", $00, "still\\\"; x-ref: $2A72 |
| | .endencode |
| ; Color attributes for obstacles/characters |
| $1D78 | | obstacle_attributes.byte$00, $00, $67, $67, $67, $67, $00, $67; x-ref: $209F |
| $1D80 | | .byte$67, $67, $67, $67, $00, $35, $35, $35 |
| $1D88 | | .byte$35, $35, $00, $35, $35, $35, $35, $35 |
| $1D90 | | .byte$35, $35, $00, $44, $44, $44, $44, $00 |
| $1D98 | | .fill8, $44 |
| ; Offsets into spawn tables for different types |
| $1DA0 | | spawn_type_offsets.byte$10, $10, $10, $10, $00, $00, $00, $00; x-ref: $2C67 |
| $1DA8 | | .fill8, $20 |
| ; Bitmasks to check if spawning an obstacle is allowed |
| $1DB0 | | spawn_allowed_masks.byte$80, $40, $20, $10, $80, $40, $20; x-ref: $2C6E |
| $1DB7 | | .fill9, $10 |
| ; Course number string digits (units). Used for the title selection screen. Values are screen character codes ($52='0', $53='1', etc.) |
| $1DC0 | | course_digits_units.byte$53, $54, $55, $56, $57, $58, $59, $5a; x-ref: $2DFB |
| $1DC8 | | .byte$5b, $52, $53, $54, $55, $56, $57, $58 |
| ; Course number string digits (tens). Used for the title selection screen. Values are screen character codes ($52='0', $53='1', etc.) |
| $1DD0 | | course_digits_tens.fill9, $52; x-ref: $2E01 |
| $1DD9 | | .byte$53, $53, $53, $53, $53, $53, $53 |
| $1DE0 | | course_scroll_speeds.byte$00, $40, $20, $20, $20, $20, $40, $20; x-ref: $2A44, $2DAA |
| $1DE8 | | .byte$80, $40, $80, $40, $40, $80, $c0, $40 |
| ; Per-course random threshold for obstacle spawning. A PRNG roll must be < this threshold to spawn. $00 means no spawns, $FF means max spawns. |
| spawn_prob_thresholds |
| $1DF0 | | .byte$00, $ff, $10, $10, $10, $18, $10, $08; x-ref: $2C7B |
| $1DF8 | | .byte$ff, $08, $08, $10, $10, $04, $40, $10 |
| $1E00 | | .fill16, $00 |
| ; Number of track scroll tile steps per frame per course (1-5). Used by update_scroll_tiles to control track speed, and displayed in the speed footer. |
| $1E10 | | course_scroll_steps.byte$01, $01, $02, $02, $02, $03, $03, $03; x-ref: $29B9, $2A8A, $2D6D |
| $1E18 | | .byte$04, $04, $04, $04, $05, $05, $05, $05 |
| ; Obstacle spawn configuration table. Indexed by course_index + f1DA0[spawn_type]. Specifies if a spawn is allowed (when ANDed with mask) and the cooldown timer (lower 4 bits + 6). |
| obstacle_spawn_params |
| $1E20 | | .byte$00, $00, $1f, $00, $00, $1c, $7c, $fc; x-ref: $2C6B, $2C8E, $2CD2 |
| $1E28 | | .byte$86, $f6, $00, $f4, $00, $c0, $80, $f4 |
| $1E30 | | .byte$00, $70, $70, $70, $00, $70, $70, $70 |
| $1E38 | | .byte$80, $f0, $00, $70, $00, $00, $80, $f0 |
| $1E40 | | .byte$00, $00, $00, $00, $1c, $00, $00, $3c |
| $1E48 | | .byte$00, $00, $5f, $00, $7c, $78, $f0, $74 |
| ; Low bytes of 16-bit pointers to the level data for each course. |
| $1E50 | | levels_ptr_lo.byte<level_0, <level_1, <level_2, <level_3, <level_4; x-ref: $2E1B |
| $1E55 | | .byte<level_5, <level_6, <level_7, <level_8, <level_9 |
| $1E5A | | .byte<level_10, <level_11, <level_12, <level_13, <level_14 |
| $1E5F | | .byte<level_15 |
| $1E60 | | levels_ptr_hi.byte>level_0, >level_1, >level_2, >level_3, >level_4; x-ref: $2E20 |
| $1E65 | | .byte>level_5, >level_6, >level_7, >level_8, >level_9 |
| $1E6A | | .byte>level_10, >level_11, >level_12, >level_13, >level_14 |
| $1E6F | | .byte>level_15 |
| $1E70 | | course_anim_frames.byte$14, $1e, $1e, $1e, $20, $1e, $1e, $20; x-ref: $2A21, $2A3F |
| $1E78 | | .byte$10, $24, $1e, $24, $2c, $2c, $1c, $30 |
| ; ROM tile color descriptor table (64 entries). |
| ; Bits 0-1: used for sprite shape selection |
| ; Bits 2-5: foreground TED color index offset by $33. |
| ; Bits 6-7: background color field. |
| tile_color_descriptors |
| $1E80 | | .byte$18, $88, $88, $88, $84, $84, $84, $88; x-ref: $23F3, $23FE |
| $1E88 | | .byte$88, $88, $84, $84, $84, $14, $10, $0c |
| $1E90 | | .byte$08, $04, $10, $10, $10, $10, $0c, $0c |
| $1E98 | | .byte$0c, $0c, $54, $54, $54, $50, $50, $50 |
| $1EA0 | | .byte$4c, $4c, $4c, $48, $48, $48, $94, $94 |
| $1EA8 | | .byte$94, $90, $90, $90, $14, $10, $0c, $08 |
| $1EB0 | | .byte$04, $14, $10, $0c, $08, $04, $90, $88 |
| $1EB8 | | .byte$88, $90, $00, $00, $00, $18, $18, $18 |
| $1EC0 | | tile_chars_row0.byte$00, $00, $00, $00, $14, $15, $16, $00; x-ref: $23A3 |
| $1EC8 | | .byte$00, $00, $20, $21, $22, $00, $00, $00 |
| $1ED0 | | .byte$00, $03 |
| $1ED2 | | .fill30, $00 |
| $1EF0 | | .byte$10, $00, $00, $00, $00, $05, $00, $00 |
| $1EF8 | | .byte$00, $00, $00, $00, $00, $12, $12, $13 |
| $1F00 | | tile_chars_row1.byte$00, $14, $15, $16, $17, $18, $19, $20; x-ref: $23A9 |
| $1F08 | | .byte$21, $22, $23, $24, $25, $00, $00, $00 |
| $1F10 | | .byte$03, $04 |
| $1F12 | | .fill17, $00 |
| $1F23 | | .byte$09, $0a, $0b |
| $1F26 | | .fill9, $00 |
| $1F2F | | .byte$10, $10, $00, $00, $00, $05, $04, $00 |
| $1F37 | | .byte$0c, $0d, $00, $00, $00, $00, $00, $00 |
| $1F3F | | .byte$00 |
| $1F40 | | tile_chars_row2.byte$00, $17, $18, $19, $1a, $1b, $1c, $23; x-ref: $23AF |
| $1F48 | | .byte$24, $25, $26, $27, $28, $00, $00, $03 |
| $1F50 | | .byte$04, $05, $00, $00, $00, $00, $2c, $2d |
| $1F58 | | .byte$2e, $2f, $00, $00, $00, $00, $00, $00 |
| $1F60 | | .byte$09, $0a, $0b, $04, $05, $04 |
| $1F66 | | .fill8, $00 |
| $1F6E | | .byte$10, $10, $10, $00, $00, $05, $04, $05 |
| $1F76 | | .byte$00, $0e, $0f, $00, $00, $00, $00, $00 |
| $1F7E | | .byte$00, $00 |
| $1F80 | | tile_chars_row3.byte$00, $1a, $1b, $1c, $1d, $1e, $1f, $26; x-ref: $23B5 |
| $1F88 | | .byte$27, $28, $29, $2a, $2b, $00, $03, $04 |
| $1F90 | | .byte$05, $04, $2c, $2d, $2e, $2f, $30, $31 |
| $1F98 | | .byte$32, $33, $00, $00, $00, $09, $0a, $0b |
| $1FA0 | | .byte$04, $05, $04, $05, $04, $05, $00, $00 |
| $1FA8 | | .byte$00, $06, $07, $08, $00, $10, $10, $10 |
| $1FB0 | | .byte$10, $00, $05, $04, $05, $04, $0c, $0d |
| $1FB8 | | .byte$0c, $0d, $00, $00, $00, $00, $00, $00 |
| $1FC0 | | tile_chars_row4.byte$00, $1d, $1e, $1f, $11, $11, $11, $29; x-ref: $23BB |
| $1FC8 | | .byte$2a, $2b, $11, $11, $11, $02, $11, $11 |
| $1FD0 | | .byte$11, $11, $30, $31, $32, $33, $11, $11 |
| $1FD8 | | .byte$11, $11, $09, $0a, $0b |
| $1FDD | | .fill9, $11 |
| $1FE6 | | .byte$06, $07, $08, $11, $11, $11, $10, $10 |
| $1FEE | | .byte$10, $10, $10, $11, $11, $11, $11, $11 |
| $1FF6 | | .byte$0e, $0f, $0e, $0f, $00, $00, $00, $00 |
| $1FFE | | .byte$00, $00 |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| ; Main entry point for Kikstart (Commodore Plus/4). |
| ; Performs a full cold-start initialization: |
| ; 1. TED chip reset: colors set, audio muted, video matrix configured. |
| ; 2. Screen RAM (4 pages) cleared; attribute RAM filled with color $39. |
| ; 3. Game IRQ handler installed at $0314/$0315 (KERNAL shadow vector). |
| ; 4. Track/tile color tables initialized from ROM data tables. |
| ; 5. TED Timer 1 configured and started to drive per-frame IRQs. |
| ; 6. IRQs enabled; falls into the raster-synced main game loop. |
| ; |
| ; The main loop is 3-phase, synchronized to the TED Timer 1 IRQ (handled |
| ; by the routine at p2118). The IRQ increments RAM_ZPVEC1 each tick: |
| ; Phase 1 ($01): 8 game-logic subsystem update subroutines. |
| ; Phase 2 ($02): 7 more update subroutines, then repeats from phase 1. |
| ; Phase 0 ($00): Internal raster task dispatched inside the IRQ handler. |
| ; |
| ; Inputs: None (cold start) |
| ; Outputs: None |
| ; Side Effects: TED chip fully configured, IRQ vector patched to p2118, |
| ; TED Timer 1 running, game loop active indefinitely. |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| $2000 | 78 | startsei; Disable IRQs during hardware init |
| $2001 | a2 ff | ldx#$ff |
| $2003 | 9a | txs; Init stack pointer to top of page $01 |
| $2004 | a9 00 | lda#$00 |
| $2006 | 8d 15 ff | sta$ff15; TED: background color = black |
| $2009 | a9 71 | lda#$71 |
| $200B | 8d 16 ff | sta$ff16; TED: color register #1 = $71 |
| $200E | a9 39 | lda#$39 |
| $2010 | 8d 17 ff | sta$ff17; TED: color register #2 = $39 |
| $2013 | a9 00 | lda#$00 |
| $2015 | 8d 19 ff | sta$ff19; TED: color reg #4 = $00 (also used as IRQ frame-sync flag) |
| $2018 | a9 00 | lda#$00 |
| $201A | 8d 11 ff | sta$ff11; TED: mute audio output (volume = 0) |
| $201D | 8d 0e ff | sta$ff0e; TED: silence voice 1 frequency (low byte) |
| $2020 | 8d 12 ff | sta$ff12; TED: silence voice 1 frequency (high bits) |
| $2023 | 8d 0f ff | sta$ff0f; TED: silence voice 2 frequency (low byte) |
| $2026 | 8d 10 ff | sta$ff10; TED: silence voice 2 frequency (high bits) |
| $2029 | a9 10 | lda#$10 |
| $202B | 8d 13 ff | sta$ff13; TED: clock status = $10 |
| $202E | a9 08 | lda#$08 |
| $2030 | 8d 14 ff | sta$ff14; TED: video matrix/color memory base address = $08 |
| $2033 | a9 1b | lda#$1b |
| $2035 | 8d 06 ff | sta$ff06; TED control reg 1: $1B (standard bitmap/text mode) |
| $2038 | a9 98 | lda#$98 |
| $203A | 8d 07 ff | sta$ff07; TED control reg 2: $98 |
| $203D | a2 00 | ldx#$00 |
| $203F | a9 00 | b_203Flda#$00; Clear screen RAM ; x-ref: $205C |
| $2041 | 9d 00 0c | staSCREEN_RAM_R0C0,x |
| $2044 | 9d 00 0d | staSCREEN_RAM_R6C16,x |
| $2047 | 9d 00 0e | staSCREEN_RAM_R12C32,x |
| $204A | 9d 00 0f | staSCREEN_RAM_R19C8,x |
| $204D | a9 39 | lda#$39; Color RAM with attribute $39 |
| $204F | 9d 00 08 | staCOLOR_RAM_R0C0,x |
| $2052 | 9d 00 09 | staCOLOR_RAM_R6C16,x |
| $2055 | 9d 00 0a | staCOLOR_RAM_R12C32,x |
| $2058 | 9d 00 0b | staCOLOR_RAM_R19C8,x |
| $205B | e8 | inx |
| $205C | d0 e1 | bneb_203F |
| $205E | a9 18 | lda#<irq_handler; Install game IRQ handler: low byte of p2118 → $0314 |
| $2060 | 8d 14 03 | stavec_irq_lo |
| $2063 | a9 21 | lda#>irq_handler; High byte of p2118 → $0315 (KERNAL IRQ shadow vector) |
| $2065 | 8d 15 03 | stavec_irq_hi |
| $2068 | a2 27 | ldx#$27; Init 40 entries ($27...$00) of track/tile color & char pointer tables |
| $206A | a9 01 | b_206Alda#$01; x-ref: $20A9 |
| $206C | 9d 48 0f | staSCREEN_RAM_R21C0,x; Track data init: store $01 |
| $206F | a9 3d | lda#$3d |
| $2071 | 9d 48 0b | staCOLOR_RAM_R21C0,x |
| $2074 | 9d 20 0b | staCOLOR_RAM_R20C0,x |
| $2077 | 9d f8 0a | staCOLOR_RAM_R19C0,x |
| $207A | 9d d0 0a | staCOLOR_RAM_R18C0,x |
| $207D | 9d a8 0a | staCOLOR_RAM_R17C0,x |
| $2080 | 9d 80 0a | staCOLOR_RAM_R16C0,x |
| $2083 | bd 00 1c | ldatrack_column_colors,x; Load bitmap color for this column from BMCOLR table |
| $2086 | 9d 98 0f | staSCREEN_RAM_R23C0,x; Store to display color table |
| $2089 | f0 03 | beqb_208E |
| $208B | 18 | clc; Non-zero: add 1 to color for alternate-row shading |
| $208C | 69 01 | adc#$01 |
| $208E | 9d c0 0f | b_208EstaSCREEN_RAM_R24C0,x; x-ref: $2089 |
| $2091 | bd 28 1c | ldatrack_tile_indices,x; Load character pointer from ROM table at $1C28 |
| $2094 | 9d 00 0c | staSCREEN_RAM_R0C0,x; Set TED screen character pointer |
| $2097 | f0 03 | beqb_209C |
| $2099 | 18 | clc; Non-zero: add $14 (20) — row-offset into char/tile data |
| $209A | 69 14 | adc#$14 |
| $209C | 9d 28 0c | b_209CstaSCREEN_RAM_R1C0,x; x-ref: $2097 |
| $209F | bd 78 1d | ldaobstacle_attributes,x; Load attribute byte from ROM table at $1D78 |
| $20A2 | 9d 00 08 | staCOLOR_RAM_R0C0,x; Set TED attribute byte for this column |
| $20A5 | 9d 28 08 | staCOLOR_RAM_R1C0,x |
| $20A8 | ca | dex |
| $20A9 | 10 bf | bplb_206A |
| $20AB | 20 14 26 | jsrreset_basic_runtime_state; Additional game state initialization (called once) |
| $20AE | a9 ff | lda#$ff |
| $20B0 | 85 2f | stazp_course_index |
| $20B2 | a9 00 | lda#$00 |
| $20B4 | 85 30 | stazp_lives_counter |
| $20B6 | 85 32 | stazp_sprite_queue_count |
| $20B8 | 8d 31 0c | staSCREEN_RAM_R1C9 |
| $20BB | ea | nop |
| $20BC | a9 ff | lda#$ff |
| $20BE | 85 03 | stazp_frame_phase; Frame phase counter = $FF (wraps to 0 on first IRQ increment) |
| $20C0 | a9 14 | lda#$14 |
| $20C2 | 85 06 | stazp_raster_target |
| $20C4 | a9 12 | lda#$12; TED Timer 1 latch low byte = $12 (controls IRQ rate) |
| $20C6 | 8d 0b ff | sta$ff0b; TED Timer 1 control: enable + start — IRQs will fire each frame |
| $20C9 | a9 02 | lda#$02 |
| $20CB | 8d 0a ff | sta$ff0a |
| $20CE | 58 | cli; Enable IRQs — game loop begins |
| $20CF | ad 19 ff | b_20CFlda$ff19; Spin-wait: read $FF19 to acknowledge TED IRQ, then check phase ; x-ref: $20D6, $2112 |
| $20D2 | a5 03 | ldazp_frame_phase |
| $20D4 | c9 01 | cmp#$01; Wait until IRQ advances frame phase to 1 |
| $20D6 | d0 f7 | bneb_20CF |
| $20D8 | e6 3f | inczp_frame_counter; Increment global frame counter |
| $20DA | 20 04 23 | jsrupdate_obstacle_positions; --- Phase 1 subsystem updates begin --- |
| $20DD | 20 24 25 | jsrupdate_obstacle_physics |
| $20E0 | 20 ec 23 | jsrupdate_tile_colors |
| $20E3 | 20 04 27 | jsrread_joystick |
| $20E6 | 20 88 25 | jsrdraw_hud_progress_bar |
| $20E9 | 20 d0 25 | jsrhandle_game_mode |
| $20EC | 20 ec 2a | jsrsound_engine_tick |
| $20EF | 20 4c 2c | jsrobstacle_spawn_and_collide |
| $20F2 | ea | nop |
| $20F3 | ad 19 ff | b_20F3lda$ff19; Spin-wait: acknowledge TED IRQ, wait until phase advances to 2 ; x-ref: $20FA |
| $20F6 | a5 03 | ldazp_frame_phase |
| $20F8 | c9 02 | cmp#$02; Wait until IRQ advances frame phase to 2 |
| $20FA | d0 f7 | bneb_20F3 |
| $20FC | 20 d8 21 | jsrsprite_erase; --- Phase 2 subsystem updates begin --- |
| $20FF | 20 c0 21 | jsrselect_raster_color |
| $2102 | 20 d8 24 | jsrtrack_scroll_engine |
| $2105 | 20 10 24 | jsrrender_debris_or_bike |
| $2108 | 20 9c 23 | jsrrender_track_tiles |
| $210B | 20 3c 22 | jsrrender_obstacles |
| $210E | 20 04 22 | jsrsprite_draw |
| $2111 | 18 | clc |
| $2112 | 90 bb | bccb_20CF; Unconditional loop back to phase-1 wait (BCC always taken) |
| $2114 | | .byte$00, $00, $00, $00 |
| ; TED Timer 1 IRQ handler. |
| ; Fires each raster frame. Acknowledges the TED timer IRQ, increments the |
| ; 3-phase frame counter in RAM_ZPVEC1 (wraps 0→1→2→0), then dispatches |
| ; raster state machine tasks for phase 0. Phases 1 and 2 are handled by |
| ; the spin-waits in the main loop (main_init). Non-timer IRQs are chained |
| ; to the KERNAL handler at $FCC3. |
| $2118 | ad 09 ff | irq_handlerlda$ff09; Read $FF09: check which IRQ source fired ; x-ref: $205E, $2063 |
| $211B | 29 02 | and#$02; Bit 1 = TED Timer 1 IRQ |
| $211D | d0 03 | bneb_2122 |
| $211F | 4c c3 fc | jmp$fcc3; Not our IRQ — chain to KERNAL handler at $FCC3 |
| $2122 | a9 02 | b_2122lda#$02; x-ref: $211D |
| $2124 | 8d 09 ff | sta$ff09; Acknowledge TED Timer 1 IRQ (write $02 to $FF09) |
| $2127 | ea | nop |
| $2128 | e6 03 | inczp_frame_phase; Advance frame phase counter: 0→1→2→0 |
| $212A | a5 03 | ldazp_frame_phase |
| $212C | c9 03 | cmp#$03; Wrap counter at 3 |
| $212E | 90 04 | bccb_2134 |
| $2130 | a9 00 | lda#$00 |
| $2132 | 85 03 | stazp_frame_phase |
| $2134 | a5 03 | b_2134ldazp_frame_phase; x-ref: $212E |
| $2136 | c9 00 | cmp#$00; Phase 0: dispatch raster task A |
| $2138 | f0 0c | beqb_2146 |
| $213A | c9 01 | cmp#$01; Phase 1: dispatch raster task B |
| $213C | f0 13 | beqb_2151 |
| $213E | c9 02 | cmp#$02; Phase 2: dispatch raster task C |
| $2140 | f0 1a | beqb_215C |
| $2142 | 4c c3 fc | jmp$fcc3 |
| $2145 | ea | nop |
| $2146 | a5 3d | b_2146ldazp_raster_color; x-ref: $2138 |
| $2148 | 48 | pha |
| $2149 | a0 83 | ldy#$83 |
| $214B | a9 90 | lda#$90 |
| $214D | 05 04 | orazp_raster_split_a |
| $214F | d0 12 | bneb_2163 |
| $2151 | a9 10 | b_2151lda#$10; x-ref: $213C |
| $2153 | 48 | pha |
| $2154 | a0 b3 | ldy#$b3 |
| $2156 | a9 90 | lda#$90 |
| $2158 | 05 05 | orazp_raster_split_b |
| $215A | d0 07 | bneb_2163 |
| $215C | a9 18 | b_215Clda#$18; x-ref: $2140 |
| $215E | 48 | pha |
| $215F | a0 14 | ldy#$14 |
| $2161 | a9 90 | lda#$90 |
| $2163 | ae 1d ff | b_2163ldx$ff1d; x-ref: $214F, $215A, $2168 |
| $2166 | e4 06 | cpxzp_raster_target |
| $2168 | d0 f9 | bneb_2163 |
| $216A | 8d 07 ff | sta$ff07 |
| $216D | 68 | pla |
| $216E | 8d 13 ff | sta$ff13 |
| $2171 | 84 06 | styzp_raster_target |
| $2173 | 98 | tya |
| $2174 | 38 | sec |
| $2175 | e9 02 | sbc#$02 |
| $2177 | 8d 0b ff | sta$ff0b |
| $217A | a9 02 | lda#$02 |
| $217C | 8d 0a ff | sta$ff0a |
| $217F | 4c c3 fc | jmp$fcc3 |
| $2182 | | .fill14, $00 |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| ; Title/attract-mode collision detector. Checks whether any scrolling |
| ; obstacle (slots 4,3,1,0; slot 2 skipped as the player slot) has reached |
| ; the left-edge sentinel position ($0B in $0C07,x). If any slot hits the |
| ; sentinel, exits early (obstacle still in transit). Once all slots are |
| ; checked with none at $0B AND player_active is clear, arms the crash: |
| ; sets player_active=$FF, lives_counter=1, and calls trigger_crash (debris |
| ; explosion + mode 5). Called every frame from the title scroll loop. |
| ; |
| ; Inputs: $0C07,x (screen X positions for 5 slots), player_active |
| ; Outputs: player_active=$FF, lives_counter=1 (only when triggered) |
| ; Side Effects: Calls trigger_crash (debris, sound, game_mode=5) |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| check_title_obstacle_collision |
| $2190 | ea | nop; x-ref: $2369 |
| $2191 | ea | nop |
| $2192 | ea | nop |
| $2193 | a2 04 | ldx#$04; check slots 4,3,1,0 (skip 2 = player slot) |
| $2195 | e0 02 | b_2195cpx#$02; x-ref: $21A1 |
| $2197 | f0 07 | beqb_21A0 |
| $2199 | bd 07 0c | ldaSCREEN_RAM_R0C7,x; has this obstacle reached the left-edge sentinel ($0B)? |
| $219C | c9 0b | cmp#$0b |
| $219E | d0 12 | bner_21B2 |
| $21A0 | ca | b_21A0dex; x-ref: $2197 |
| $21A1 | 10 f2 | bplb_2195 |
| $21A3 | a5 3b | ldazp_player_active; all slots clear: is player already active? -> skip if so |
| $21A5 | d0 0b | bner_21B2 |
| $21A7 | a9 ff | lda#$ff; arm crash: mark player active, set 1 lap, trigger debris + mode 5 |
| $21A9 | 85 3b | stazp_player_active |
| $21AB | a9 01 | lda#$01 |
| $21AD | 85 30 | stazp_lives_counter |
| $21AF | 20 ac 26 | jsrtrigger_crash |
| $21B2 | 60 | r_21B2rts; x-ref: $219E, $21A5 |
| $21B3 | | .byte$00 |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| ; Conditionally clears raster_split_a when the game is in a stationary mode. |
| ; If raster_colour==$18 (dark orange, set by select_raster_colour for modes |
| ; 0/4/6 — but specifically when stationary), zeroes raster_split_a to |
| ; prevent a spurious raster split from leaking through during non-riding |
| ; modes. Called after the scroll timer updates raster_split_a; this |
| ; guards against that value being applied when no split is wanted. |
| ; |
| ; Inputs: raster_colour (set by select_raster_colour), raster_split_a |
| ; Outputs: raster_split_a=0 (only if raster_colour==$18) |
| ; Side Effects: None (split value read later by IRQ handler) |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| clear_split_if_stationary |
| $21B4 | a5 3d | ldazp_raster_color; is raster colour $18 (stationary mode)? ; x-ref: $251D |
| $21B6 | c9 18 | cmp#$18 |
| $21B8 | d0 04 | bner_21BE |
| $21BA | a9 00 | lda#$00; yes -> zero the raster split (no split during stationary modes) |
| $21BC | 85 04 | stazp_raster_split_a |
| $21BE | 60 | r_21BErts; x-ref: $21B8 |
| $21BF | | .byte$00 |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| ; Selects the playfield background colour for the raster split. |
| ; Modes 0 (normal ride), 4 (track scroll), 6 (results screen) use $18 |
| ; (TED: luminance 1, colour 8 = dark orange/brown). |
| ; All other modes use $10 (TED: luminance 1, colour 0 = black). |
| ; The value is read by irq_handler and written to $FF13 (TED background |
| ; colour register) during raster phase 0. |
| ; |
| ; Inputs: game_mode |
| ; Outputs: raster_colour ($10 or $18) |
| ; Side Effects: None (colour applied later by IRQ handler) |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| $21C0 | a5 02 | select_raster_colorldazp_game_mode; x-ref: $20FF |
| $21C2 | c9 00 | cmp#GameMode.NORMAL_RIDE; mode 0 (normal ride) -> dark orange |
| $21C4 | f0 0c | beqb_21D2 |
| $21C6 | c9 04 | cmp#GameMode.TRACK_SCROLL; mode 4 (track scroll) -> dark orange |
| $21C8 | f0 08 | beqb_21D2 |
| $21CA | c9 06 | cmp#GameMode.RESULTS_SCREEN; mode 6 (results screen) -> dark orange |
| $21CC | f0 04 | beqb_21D2 |
| $21CE | a9 10 | lda#$10; $10 = black background (active gameplay) |
| $21D0 | d0 02 | bneb_21D4 |
| $21D2 | a9 18 | b_21D2lda#$18; $18 = dark orange/brown background (stationary modes) ; x-ref: $21C4, $21C8, $21CC |
| $21D4 | 85 3d | b_21D4stazp_raster_color; store for IRQ handler to apply during raster phase 0 ; x-ref: $21D0 |
| $21D6 | 60 | rts |
| $21D7 | | .byte$00 |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| ; Sprite erase - clears previous frame's character sprites from screen. |
| ; Iterates the sprite queue backwards (sprite_queue_count..1). For each entry: |
| ; 1. Looks up screen row address from f1C50/f1C68 (24-entry row table) |
| ; using the row index stored in f03FF[Y]. |
| ; 2. Writes $00 (blank) to screen RAM at (ptr),column. |
| ; 3. Toggles hi byte bit 2 (EOR #$04) to switch from screen RAM ($0Cxx) |
| ; to colour RAM ($08xx) and writes $3D (default colour attribute). |
| ; 4. Decrements sprite_queue_count and repeats until zero. |
| ; |
| ; First step of the double-buffer sprite technique: |
| ; erase old (this) -> run game logic -> draw new (sprite_draw). |
| ; |
| ; Inputs: sprite_queue_count, f03FF[1..N] (row indices), f042F[1..N] (col) |
| ; Outputs: Screen + colour RAM cleared at previous sprite positions, |
| ; sprite_queue_count = 0 |
| ; Side Effects: Direct writes to screen RAM ($0C00+) and colour RAM ($0800+) |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| $21D8 | a4 32 | sprite_eraseldyzp_sprite_queue_count; any sprites in the erase queue? ; x-ref: $20FC, $21FD |
| $21DA | f0 23 | beqr_21FF; queue empty -> nothing to erase |
| $21DC | be ff 03 | ldxsprite_q_row_m1,y; X = screen row index from sprite queue |
| $21DF | bd 50 1c | ldascreen_row_addr_lo,x; screen row address lo (40-col row table) |
| $21E2 | 85 fe | stazp_blit_color_ptr |
| $21E4 | bd 68 1c | ldascreen_row_addr_hi,x; screen row address hi ($0C-$0F pages) |
| $21E7 | 85 ff | stazp_blit_char_idx |
| $21E9 | b9 2f 04 | ldasprite_q_col_m1,y; Y = column offset within the row |
| $21EC | a8 | tay |
| $21ED | a9 00 | lda#$00 |
| $21EF | 91 fe | sta(zp_blit_color_ptr),y; write $00 (blank char) to screen RAM |
| $21F1 | a5 ff | ldazp_blit_char_idx |
| $21F3 | 49 04 | eor#$04; toggle bit 2: screen RAM -> colour RAM ($0Cxx<->$08xx) |
| $21F5 | 85 ff | stazp_blit_char_idx |
| $21F7 | a9 3d | lda#$3d; $3D = default colour attribute |
| $21F9 | 91 fe | sta(zp_blit_color_ptr),y; restore default colour in colour RAM |
| $21FB | c6 32 | deczp_sprite_queue_count; pop entry, loop until all sprites erased |
| $21FD | d0 d9 | bnesprite_erase |
| $21FF | 60 | r_21FFrts; x-ref: $21DA |
| $2200 | | .byte$00, $00, $00, $00 |
| $2204 | a0 00 | sprite_drawldy#$00; x-ref: $210E |
| $2206 | c4 32 | b_2206cpyzp_sprite_queue_count; x-ref: $2238 |
| $2208 | b0 2d | bcsb_2237 |
| $220A | be 00 04 | ldxsprite_q_row,y |
| $220D | bd 50 1c | ldascreen_row_addr_lo,x |
| $2210 | 85 fc | stazp_blit_col |
| $2212 | bd 68 1c | ldascreen_row_addr_hi,x |
| $2215 | 85 fd | stazp_blit_row |
| $2217 | 98 | tya |
| $2218 | 48 | pha |
| $2219 | b9 60 04 | ldasprite_q_char,y |
| $221C | 85 ff | stazp_blit_char_idx |
| $221E | b9 90 04 | ldasprite_q_color,y |
| $2221 | 85 fe | stazp_blit_color_ptr |
| $2223 | b9 30 04 | ldasprite_q_col,y |
| $2226 | a8 | tay |
| $2227 | a5 ff | ldazp_blit_char_idx |
| $2229 | 91 fc | sta(zp_blit_col),y |
| $222B | a5 fd | ldazp_blit_row |
| $222D | 49 04 | eor#$04 |
| $222F | 85 fd | stazp_blit_row |
| $2231 | a5 fe | ldazp_blit_color_ptr |
| $2233 | 91 fc | sta(zp_blit_col),y |
| $2235 | 68 | pla |
| $2236 | a8 | tay |
| $2237 | c8 | b_2237iny; x-ref: $2208 |
| $2238 | 10 cc | bplb_2206 |
| $223A | 60 | rts |
| $223B | | .byte$00 |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| ; Obstacle sprite renderer - draws all active obstacles as character sprites. |
| ; Iterates 4 slots (X=3..0), dispatching to normal or wide renderers. |
| ; |
| ; Normal obstacles (type 0-7): 2x3 character grid |
| ; Colour from f1C90[type]. Screen col = pos_hi >> 2. |
| ; Char base = ((sub_pos | type_hi_bit) * 6) + $38. |
| ; Blits 6 cells via sprite_queue_push + obstacle_blit_advance. |
| ; Column deltas from f1CA0: (0,+1,+1,-2,+1,+1) = two 3-wide rows. |
| ; |
| ; Wide obstacles (type >= 8): 4-tall vertical column |
| ; Screen col = (flags & $03) + 3. |
| ; Colour from f1CA8[vel & $1F] (32-entry pulsating gradient). |
| ; Char base = (flags & $04) + $68 (two animation variants). |
| ; Blits 4 vertical cells, each at obstacle_life + Y. |
| ; If bit 4 set: render_wide_flash_bar adds 3-char horizontal bar. |
| ; |
| ; Inputs: obstacle_flags/pos_hi/life/vel[0..3], f1C90, f1CA0, f1CA8 |
| ; Outputs: Sprite queue entries via sprite_queue_push |
| ; Side Effects: None (deferred rendering) |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| $223C | a2 03 | render_obstaclesldx#$03; x-ref: $210B |
| $223E | b5 10 | b_223Eldazp_obstacle_flags,x; x-ref: $22B9 |
| $2240 | c9 ff | cmp#$ff; $FF = dead slot, skip to next |
| $2242 | f0 74 | beqb_22B8 |
| $2244 | c9 08 | cmp#$08; type >= 8? -> wide obstacle renderer |
| $2246 | b0 3e | bcsb_2286 |
| $2248 | a8 | tay |
| $2249 | b9 90 1c | ldaobstacle_color_normal,y; --- Normal: colour from f1C90[type] --- |
| $224C | 85 fe | stazp_blit_color_ptr |
| $224E | b5 18 | ldazp_obstacle_pos_hi,x |
| $2250 | 4a | lsra; screen col = pos_hi >> 2 |
| $2251 | 4a | lsra |
| $2252 | 85 fc | stazp_blit_col |
| $2254 | b5 18 | ldazp_obstacle_pos_hi,x |
| $2256 | 29 03 | and#$03; sub-pixel X = pos_hi & $03 (4 animation phases) |
| $2258 | 85 ff | stazp_blit_char_idx |
| $225A | b5 10 | ldazp_obstacle_flags,x |
| $225C | c9 04 | cmp#$04; type >= 4? -> use alternate animation set (bit 2) |
| $225E | 90 06 | bccb_2266 |
| $2260 | a5 ff | ldazp_blit_char_idx |
| $2262 | 09 04 | ora#$04 |
| $2264 | 85 ff | stazp_blit_char_idx |
| $2266 | 06 ff | b_2266aslzp_blit_char_idx; char_idx = idx * 6 + $38 (via ASL + ADC trick) ; x-ref: $225E |
| $2268 | a5 ff | ldazp_blit_char_idx |
| $226A | 0a | asla |
| $226B | 18 | clc |
| $226C | 65 ff | adczp_blit_char_idx |
| $226E | 18 | clc |
| $226F | 69 38 | adc#$38 |
| $2271 | 85 ff | stazp_blit_char_idx |
| $2273 | b5 14 | ldazp_obstacle_life,x; vertical position = obstacle lifetime counter |
| $2275 | 85 fd | stazp_blit_row |
| $2277 | a0 00 | ldy#$00 |
| $2279 | 20 c8 23 | b_2279jsrsprite_queue_push; blit 6 cells: 2x3 grid (3 cols x 2 rows) ; x-ref: $2281 |
| $227C | 20 f0 22 | jsrobstacle_blit_advance |
| $227F | c0 06 | cpy#$06 |
| $2281 | d0 f6 | bneb_2279 |
| $2283 | 18 | clc |
| $2284 | 90 32 | bccb_22B8 |
| $2286 | b5 10 | b_2286ldazp_obstacle_flags,x; --- Wide: screen col = (flags & $03) + 3 --- ; x-ref: $2246 |
| $2288 | 29 03 | and#$03 |
| $228A | 18 | clc |
| $228B | 69 03 | adc#$03 |
| $228D | 85 fc | stazp_blit_col |
| $228F | b5 20 | ldazp_obstacle_vel,x |
| $2291 | 29 1f | and#$1f; colour from f1CA8[vel & $1F] (pulsating gradient) |
| $2293 | a8 | tay |
| $2294 | b9 a8 1c | ldaobstacle_color_wide,y |
| $2297 | 85 fe | stazp_blit_color_ptr |
| $2299 | b5 10 | ldazp_obstacle_flags,x |
| $229B | 29 04 | and#$04 |
| $229D | 18 | clc |
| $229E | 69 68 | adc#$68; char base = (flags & $04) + $68 (2 anim variants) |
| $22A0 | 85 ff | stazp_blit_char_idx |
| $22A2 | a0 00 | ldy#$00 |
| $22A4 | 98 | b_22A4tya; blit 4 vertical cells at life+0, life+1, life+2, life+3 ; x-ref: $22B2 |
| $22A5 | 18 | clc |
| $22A6 | 75 14 | adczp_obstacle_life,x |
| $22A8 | 85 fd | stazp_blit_row |
| $22AA | 20 c8 23 | jsrsprite_queue_push |
| $22AD | c8 | iny |
| $22AE | e6 ff | inczp_blit_char_idx |
| $22B0 | c0 04 | cpy#$04 |
| $22B2 | d0 f0 | bneb_22A4 |
| $22B4 | 20 c0 22 | jsrrender_wide_flash_bar; render flash bar if bit 4 set (sound-triggered) |
| $22B7 | ea | nop |
| $22B8 | ca | b_22B8dex; x-ref: $2242, $2284 |
| $22B9 | 10 83 | bplb_223E |
| $22BB | 60 | rts |
| $22BC | | .byte$00, $00, $00, $00 |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| ; Wide obstacle flash bar - renders a 3-char horizontal bar when bit 4 of |
| ; obstacle_flags is set (sound-triggered visual effect). |
| ; Chars $34-$36 (cycling), colour $71, at blit_col+1, row = life+1. |
| ; Extends rightward until column >= $10. |
| ; |
| ; Inputs: obstacle_flags[X] (bit 4), obstacle_life[X], blit_col |
| ; Outputs: Sprite queue entries |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| render_wide_flash_bar |
| $22C0 | b5 10 | ldazp_obstacle_flags,x; x-ref: $22B4 |
| $22C2 | 29 10 | and#$10; bit 4 clear? -> no flash bar |
| $22C4 | f0 28 | beqr_22EE |
| $22C6 | e6 fc | inczp_blit_col |
| $22C8 | a9 34 | lda#$34; chars $34-$36 (cycling), colour $71 |
| $22CA | 85 ff | stazp_blit_char_idx |
| $22CC | b5 14 | ldazp_obstacle_life,x |
| $22CE | 18 | clc |
| $22CF | 69 01 | adc#$01 |
| $22D1 | 85 fd | stazp_blit_row |
| $22D3 | a9 71 | lda#$71 |
| $22D5 | 85 fe | stazp_blit_color_ptr |
| $22D7 | 20 c8 23 | b_22D7jsrsprite_queue_push; blit bar chars rightward until col >= $10 ; x-ref: $22EC |
| $22DA | e6 ff | inczp_blit_char_idx |
| $22DC | a5 ff | ldazp_blit_char_idx |
| $22DE | c9 37 | cmp#$37 |
| $22E0 | d0 04 | bneb_22E6 |
| $22E2 | a9 34 | lda#$34 |
| $22E4 | 85 ff | stazp_blit_char_idx |
| $22E6 | e6 fc | b_22E6inczp_blit_col; x-ref: $22E0 |
| $22E8 | a5 fc | ldazp_blit_col |
| $22EA | c9 10 | cmp#$10 |
| $22EC | 90 e9 | bccb_22D7 |
| $22EE | 60 | r_22EErts; x-ref: $22C4 |
| $22EF | | .byte$00 |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| ; Normal obstacle blit advance helper. |
| ; Increments Y and blit_char_idx. Applies column delta from f1CA0[Y] |
| ; (pattern: 0,+1,+1,-2,+1,+1 = two 3-wide rows). Increments blit_row |
| ; when Y reaches 3 (start of second row). |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| obstacle_blit_advance |
| $22F0 | c8 | iny; advance Y, char_idx; apply col delta from f1CA0[Y] ; x-ref: $227C |
| $22F1 | e6 ff | inczp_blit_char_idx |
| $22F3 | b9 a0 1c | ldaobstacle_col_deltas,y |
| $22F6 | 18 | clc |
| $22F7 | 65 fc | adczp_blit_col |
| $22F9 | 85 fc | stazp_blit_col |
| $22FB | c0 03 | cpy#$03; at cell 3? -> inc row (start 2nd row of 2x3 grid) |
| $22FD | d0 02 | bner_2301 |
| $22FF | e6 fd | inczp_blit_row |
| $2301 | 60 | r_2301rts; x-ref: $22FD |
| $2302 | | .byte$00, $00 |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| ; Per-frame update of obstacle and player bike screen positions. |
| ; Called every game frame (phase 1 of the IRQ-driven 3-phase main loop). |
| ; |
| ; Guards on a02 (game mode): only active for modes 1, 2, 5, or >=7; |
| ; returns immediately for menus, attract, or paused states. |
| ; |
| ; Reads the obstacle type byte at offset $10 of the object record pointed |
| ; to by p24 ($24/$25): |
| ; $FE -> clears a3B (player-active flag), calls s2694 (crash/reset) |
| ; $FD -> sets a31=1 (state-change signal) |
| ; |
| ; Decrement path (a3B=0, obstacles scrolling right->left): |
| ; Loops over slots X=4,3,1 (slot 2 skipped): decrements f0C07,x and |
| ; f0C2F,x by 1 each frame. Wraps at $0A back to $14/$28 (track boundary). |
| ; Calls s2190 to check if any slot crossed the finish threshold. |
| ; |
| ; Increment path (a3B!=0, player in motion, even frames only): |
| ; Loops over slots X=1,0: increments f0C07,x and f0C2F,x. Wraps at |
| ; $15 back down to $0B/$1F. Calls s2E90 to check for a finish-line |
| ; or bike collision. |
| ; |
| ; Inputs: a02 (game mode), a3B (player-active flag), a31, a3C, a3F |
| ; (frame counter), (p24)+$10 (obstacle type), f0C07/f0C2F tables |
| ; Outputs: f0C07,x / f0C2F,x (updated screen positions), a3B, a31 |
| ; Side Effects: May call s2694 (crash/reset), s2190 (lap check), |
| ; s2E90 (finish-line/collision check) |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| update_obstacle_positions |
| $2304 | a5 02 | ldazp_game_mode; Load game mode byte ; x-ref: $20DA |
| $2306 | c9 01 | cmp#GameMode.CRASH_DEBRIS; Mode 1 -> active |
| $2308 | f0 0e | beqb_2318 |
| $230A | c9 02 | cmp#GameMode.ACTIVE_RIDE; Mode 2 -> active |
| $230C | f0 0a | beqb_2318 |
| $230E | c9 05 | cmp#GameMode.DEBRIS_WAIT; Mode 5 -> active |
| $2310 | f0 06 | beqb_2318 |
| $2312 | c9 07 | cmp#GameMode.VELOCITY_INTEGRATE; Mode >=7 -> active; all others fall through to RTS |
| $2314 | b0 02 | bcsb_2318; Inactive mode — skip all updates |
| $2316 | 60 | rts |
| $2317 | ea | nop |
| $2318 | a0 10 | b_2318ldy#$10; Y=$10: offset to obstacle type byte in object record ; x-ref: $2308, $230C, $2310, $2314 |
| $231A | b1 24 | lda(zp_ptr_obj_record_lo),y; Read obstacle type via p24 pointer (indirect indexed) |
| $231C | c9 fe | cmp#$fe; $FE = sentinel: clear player-active flag and call crash/reset handler |
| $231E | d0 06 | bneb_2326 |
| $2320 | a9 00 | lda#$00; Clear a3B: mark player as inactive (obstacle-scroll mode) |
| $2322 | 85 3b | stazp_player_active |
| $2324 | f0 08 | beqb_232E |
| $2326 | c9 fd | b_2326cmp#$fd; $FD = sentinel: signal state-change (set a31=1) ; x-ref: $231E |
| $2328 | d0 04 | bneb_232E |
| $232A | a9 01 | lda#$01; Set state-change flag |
| $232C | 85 31 | stazp_scroll_dir_flag |
| $232E | a5 31 | b_232Eldazp_scroll_dir_flag; a31=0 -> decrement path (obstacles scrolling); else increment path ; x-ref: $2324, $2328 |
| $2330 | f0 0d | beqb_233F |
| $2332 | ea | nop |
| $2333 | ea | nop |
| $2334 | ea | nop |
| $2335 | ea | nop |
| $2336 | ea | nop |
| $2337 | ea | nop |
| $2338 | a9 ff | lda#$ff; Set a3B=$FF (player active) and call crash/reset handler |
| $233A | 85 3b | stazp_player_active |
| $233C | 20 94 26 | jsrenter_mode_riding |
| $233F | a5 3b | b_233Fldazp_player_active; x-ref: $2330 |
| $2341 | d0 26 | bneb_2369 |
| $2343 | a2 04 | ldx#$04; Decrement path: start at slot X=4, work down to X=0 (skip slot 2) |
| $2345 | e0 02 | b_2345cpx#$02; Skip slot 2 (player slot) ; x-ref: $2361 |
| $2347 | f0 17 | beqb_2360 |
| $2349 | de 07 0c | decSCREEN_RAM_R0C7,x; Scroll obstacle left (decrement screen X position) |
| $234C | de 2f 0c | decSCREEN_RAM_R1C7,x; Scroll second position table in step |
| $234F | bd 07 0c | ldaSCREEN_RAM_R0C7,x |
| $2352 | c9 0a | cmp#$0a; At left edge ($0A)? Wrap obstacle back to right side ($14/$28) |
| $2354 | d0 0d | bneb_2363 |
| $2356 | a9 14 | lda#$14 |
| $2358 | 9d 07 0c | staSCREEN_RAM_R0C7,x |
| $235B | a9 28 | lda#$28 |
| $235D | 9d 2f 0c | staSCREEN_RAM_R1C7,x |
| $2360 | ca | b_2360dex; x-ref: $2347 |
| $2361 | 10 e2 | bplb_2345 |
| $2363 | ce 0b 0c | b_2363decSCREEN_RAM_R0C11; x-ref: $2354 |
| $2366 | ce 33 0c | decSCREEN_RAM_R1C11 |
| $2369 | 20 90 21 | b_2369jsrcheck_title_obstacle_collision; x-ref: $2341 |
| $236C | a5 3f | ldazp_frame_counter |
| $236E | 29 01 | and#$01 |
| $2370 | d0 25 | bner_2397 |
| $2372 | a5 3c | ldazp_anim_frame_count |
| $2374 | f0 21 | beqr_2397 |
| $2376 | c6 3c | deczp_anim_frame_count |
| $2378 | a2 01 | ldx#$01 |
| $237A | fe 07 0c | b_237AincSCREEN_RAM_R0C7,x; x-ref: $2392 |
| $237D | fe 2f 0c | incSCREEN_RAM_R1C7,x |
| $2380 | bd 07 0c | ldaSCREEN_RAM_R0C7,x |
| $2383 | c9 15 | cmp#$15 |
| $2385 | d0 0d | bneb_2394 |
| $2387 | a9 0b | lda#$0b |
| $2389 | 9d 07 0c | staSCREEN_RAM_R0C7,x |
| $238C | a9 1f | lda#$1f |
| $238E | 9d 2f 0c | staSCREEN_RAM_R1C7,x; Only run increment path on even frames (bit 0 of frame counter) |
| $2391 | ca | dex |
| $2392 | 10 e6 | bplb_237A; Secondary counter zero -> skip increment this frame |
| $2394 | 20 90 2e | b_2394jsrcheck_finish_line; Decrement secondary counter ; x-ref: $2385 |
| $2397 | 60 | r_2397rts; x-ref: $2370, $2374 |
| $2398 | | .byte$00, $00, $00, $00 |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| ; Track tile renderer - expands a 40-byte track row definition into a |
| ; 40x5 character tile grid at the bottom of the screen. |
| ; |
| ; For each of 40 columns (Y=0..39): |
| ; 1. Reads tile type from (ptr_obj_record_lo),Y |
| ; 2. Masks to 6-bit index (0-63 tile types) |
| ; 3. Looks up 5 ROM tables (f1EC0/f1F00/f1F40/f1F80/f1FC0) to get |
| ; the 5 characters that form the tile column vertically |
| ; 4. Writes them to 5 consecutive screen rows at the bottom: |
| ; $0E80+Y (row 19), $0EA8+Y (row 20), $0ED0+Y (row 21), |
| ; $0EF8+Y (row 22), $0F20+Y (row 23) |
| ; |
| ; Inputs: (ptr_obj_record_lo) -> 40-byte track row data, |
| ; f1EC0-f1FC0 (5 ROM tile expansion tables, 64 entries each) |
| ; Outputs: Screen RAM $0E80-$0F47 (5 rows x 40 cols at bottom of screen) |
| ; Side Effects: None (pure screen write) |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| $239C | a0 00 | render_track_tilesldy#$00; x-ref: $2108 |
| $239E | b1 24 | b_239Elda(zp_ptr_obj_record_lo),y; read tile type from track data row ; x-ref: $23C4 |
| $23A0 | 29 3f | and#$3f; mask to 6-bit tile type (0-63) |
| $23A2 | aa | tax |
| $23A3 | bd c0 1e | ldatile_chars_row0,x; tile row 0 -> screen row 19 ($0E80) |
| $23A6 | 99 80 0e | staSCREEN_RAM_R16C0,y |
| $23A9 | bd 00 1f | ldatile_chars_row1,x; tile row 1 -> screen row 20 ($0EA8) |
| $23AC | 99 a8 0e | staSCREEN_RAM_R17C0,y |
| $23AF | bd 40 1f | ldatile_chars_row2,x; tile row 2 -> screen row 21 ($0ED0) |
| $23B2 | 99 d0 0e | staSCREEN_RAM_R18C0,y |
| $23B5 | bd 80 1f | ldatile_chars_row3,x; tile row 3 -> screen row 22 ($0EF8) |
| $23B8 | 99 f8 0e | staSCREEN_RAM_R19C0,y |
| $23BB | bd c0 1f | ldatile_chars_row4,x; tile row 4 -> screen row 23 ($0F20) |
| $23BE | 99 20 0f | staSCREEN_RAM_R20C0,y |
| $23C1 | c8 | iny |
| $23C2 | c0 28 | cpy#$28; 40 columns (full screen width) |
| $23C4 | d0 d8 | bneb_239E |
| $23C6 | 60 | rts |
| $23C7 | | .byte$00 |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| ; Sprite queue push - adds one sprite entry to the draw queue. |
| ; Clips sprites with column >= 40 (off-screen right). |
| ; |
| ; Stores (blit_col, blit_row, blit_char_idx, blit_colour_ptr) into |
| ; four parallel arrays at f0400/f0430/f0460/f0490 indexed by |
| ; sprite_queue_count, then increments the count. |
| ; |
| ; The queue is processed by sprite_draw ($2204) to write chars to screen, |
| ; and by sprite_erase ($21D8) to clear them next frame. |
| ; |
| ; Inputs: blit_col (row idx), blit_row (col), blit_char_idx (char code), |
| ; blit_colour_ptr (colour attr), sprite_queue_count |
| ; Outputs: sprite_queue_count (incremented), queue arrays updated |
| ; Side Effects: None (deferred rendering) |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| $23C8 | a5 fd | sprite_queue_pushldazp_blit_row; x-ref: $2279, $22AA, $22D7, $2463, $24B7 |
| $23CA | c9 28 | cmp#$28; column >= 40? -> off-screen right, clip |
| $23CC | b0 1c | bcsr_23EA |
| $23CE | 8a | txa |
| $23CF | 48 | pha |
| $23D0 | a6 32 | ldxzp_sprite_queue_count; save X, use sprite_queue_count as queue index |
| $23D2 | a5 fc | ldazp_blit_col |
| $23D4 | 9d 00 04 | stasprite_q_row,x; store row index into queue |
| $23D7 | a5 fd | ldazp_blit_row |
| $23D9 | 9d 30 04 | stasprite_q_col,x; store column into queue |
| $23DC | a5 ff | ldazp_blit_char_idx |
| $23DE | 9d 60 04 | stasprite_q_char,x; store character code into queue |
| $23E1 | a5 fe | ldazp_blit_color_ptr |
| $23E3 | 9d 90 04 | stasprite_q_color,x; store colour attribute into queue |
| $23E6 | e6 32 | inczp_sprite_queue_count; advance queue pointer for next entry |
| $23E8 | 68 | pla |
| $23E9 | aa | tax |
| $23EA | 60 | r_23EArts; x-ref: $23CC |
| $23EB | | .byte$00 |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| ; Per-frame track tile colour attribute update. |
| ; Loops over 10 entries of the current object record (Y=$10,$12,...,$12; |
| ; word-stride, 10 iterations until Y=$14). For each entry: |
| ; 1. Reads the tile type byte from (p24)+Y and masks to 6 bits (type 0-63). |
| ; 2. Looks up a colour descriptor byte from the ROM table at f1E80[type]. |
| ; 3. Splits the descriptor into two TED colour fields: |
| ; bits 2-5 (& $3C) + $33 -> foreground/ink colour -> $27+Y |
| ; bits 6-7 (& $C0) -> background/paper colour -> $28+Y |
| ; 4. Writes both fields back into the object record via absolute indexed |
| ; addressing (@w a27,Y / @w a28,Y). |
| ; |
| ; The ROM table f1E80 encodes up to 64 tile type descriptors: |
| ; bits 2-5: foreground colour index (offset by $33 into TED palette) |
| ; bits 6-7: background colour field |
| ; bits 0-1: used by other routines (e.g. sprite shape selection in s2410) |
| ; |
| ; Inputs: p24 ($24/$25) -- pointer to current object record |
| ; f1E80 -- ROM tile colour descriptor table (64 entries) |
| ; Outputs: Object record bytes at $27+Y / $28+Y (Y=$10..$12) updated |
| ; with foreground and background TED colour attributes |
| ; Side Effects: None |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| $23EC | a0 10 | update_tile_colorsldy#$10; Y=$10: start at first tile slot in object record (word-stride loop) ; x-ref: $20E0 |
| $23EE | b1 24 | b_23EElda(zp_ptr_obj_record_lo),y; Read tile type byte from object record via p24 pointer ; x-ref: $240A |
| $23F0 | 29 3f | and#$3f; Mask to 6-bit type index (0-63 tile types) |
| $23F2 | aa | tax |
| $23F3 | bd 80 1e | ldatile_color_descriptors,x; Fetch color descriptor from ROM table f1E80[type] |
| $23F6 | 29 3c | and#$3c; Extract foreground colour field (bits 2-5), offset by $33 into TED palette |
| $23F8 | 18 | clc |
| $23F9 | 69 33 | adc#$33 |
| $23FB | 99 27 00 | sta@w zp_bike_pos_x_hi,y; Write foreground colour into object record at $27+Y |
| $23FE | bd 80 1e | ldatile_color_descriptors,x; Re-fetch same descriptor for background field |
| $2401 | 29 c0 | and#$c0; Extract background colour field (bits 6-7) |
| $2403 | 99 28 00 | sta@w zp_bike_pos_x_lo,y; Write background colour into object record at $28+Y |
| $2406 | c8 | iny; Advance by 2 (word stride through object record) |
| $2407 | c8 | iny |
| $2408 | c0 14 | cpy#$14; 10 entries done when Y=$14 (10 x 2-byte steps from $10) |
| $240A | d0 e2 | bneb_23EE |
| $240C | 60 | rts |
| $240D | | .byte$00, $00, $00 |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| ; Mode-dependent screen update: crash debris animation or bike renderer. |
| ; |
| ; Mode dispatch: |
| ; Modes 0, 6, 8 -> RTS (nothing to render) |
| ; Modes 1, 5 -> Crash debris animation (8 particles) |
| ; Modes 2,3,4,7 -> Bike renderer (3x3 character grid) |
| ; |
| ; Debris animation (modes 1, 5): |
| ; 8 particles (X=7..0) with independent X/Y velocities from f1C80/f1C88. |
| ; Each frame: pos += velocity, bounds check (Y >= 19 or X >= 40 -> kill), |
| ; blit char $52 / colour $37 via s23C8. Dead particles marked $FF. |
| ; |
| ; Bike renderer (modes 2, 3, 4, 7): |
| ; Renders bike as a 3x3 character grid. Animation frame derived from |
| ; raster_split_a/b sub-pixel positions (XOR $06, >> 1 -> f1CC8 lookup). |
| ; Horizontal sub-position from bike_pos_hi & $03 -> f1CCC offset. |
| ; Screen column from bike_pos_hi >> 2. Each cell blitted via s23C8 |
| ; with colour $39. Char index += 3 per row for sequential animation. |
| ; |
| ; Inputs: game_mode, crash_debris_x/y[0..7], raster_split_a/b, |
| ; bike_pos_hi, f1C80/f1C88, f1CC8/f1CCC |
| ; Outputs: Screen RAM (debris or bike chars), crash_debris_x/y (updated) |
| ; Side Effects: Calls s23C8 (character blit) for each visible element |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| render_debris_or_bike |
| $2410 | a5 02 | ldazp_game_mode; x-ref: $2105 |
| $2412 | c9 00 | cmp#GameMode.NORMAL_RIDE; modes 0, 6, 8 -> nothing to render, return |
| $2414 | f0 12 | beqr_2428 |
| $2416 | c9 06 | cmp#GameMode.RESULTS_SCREEN |
| $2418 | f0 0e | beqr_2428 |
| $241A | c9 08 | cmp#GameMode.NEXT_LAP_INIT |
| $241C | f0 0a | beqr_2428 |
| $241E | c9 01 | cmp#GameMode.CRASH_DEBRIS; modes 1, 5 -> crash debris animation |
| $2420 | f0 08 | beqb_242A |
| $2422 | c9 05 | cmp#GameMode.DEBRIS_WAIT |
| $2424 | f0 04 | beqb_242A |
| $2426 | d0 44 | bneb_246C; all other modes -> bike renderer |
| $2428 | 60 | r_2428rts; x-ref: $2414, $2418, $241C |
| $2429 | ea | nop |
| $242A | a2 07 | b_242Aldx#$07; --- Debris animation: 8 particles (X=7..0) --- ; x-ref: $2420, $2424 |
| $242C | b5 48 | b_242Cldazp_crash_debris_y,x; x-ref: $2467 |
| $242E | c9 ff | cmp#$ff; $FF = dead particle, skip |
| $2430 | f0 34 | beqb_2466 |
| $2432 | 18 | clc |
| $2433 | 7d 88 1c | adcdebris_vel_y,x; Y pos += velocity from f1C88 (signed: up/down) |
| $2436 | 95 48 | stazp_crash_debris_y,x |
| $2438 | 38 | sec |
| $2439 | e9 02 | sbc#$02 |
| $243B | c9 13 | cmp#$13; Y >= 19 (off bottom)? -> kill particle |
| $243D | 90 06 | bccb_2445 |
| $243F | a9 ff | b_243Flda#$ff; x-ref: $2451 |
| $2441 | 95 48 | stazp_crash_debris_y,x |
| $2443 | d0 21 | bneb_2466 |
| $2445 | b5 40 | b_2445ldazp_crash_debris_x,x; x-ref: $243D |
| $2447 | 18 | clc |
| $2448 | 7d 80 1c | adcdebris_vel_x,x; X pos += velocity from f1C80 (signed: left/right) |
| $244B | 95 40 | stazp_crash_debris_x,x |
| $244D | c9 28 | cmp#$28; X >= 40 (off sides)? -> kill particle |
| $244F | 90 04 | bccb_2455 |
| $2451 | b0 ec | bcsb_243F |
| $2453 | b5 40 | ldazp_crash_debris_x,x |
| $2455 | 85 fd | b_2455stazp_blit_row; x-ref: $244F |
| $2457 | b5 48 | ldazp_crash_debris_y,x |
| $2459 | 85 fc | stazp_blit_col |
| $245B | a9 52 | lda#$52; $52 = debris character, $37 = debris colour |
| $245D | 85 fe | stazp_blit_color_ptr |
| $245F | a9 37 | lda#$37 |
| $2461 | 85 ff | stazp_blit_char_idx |
| $2463 | 20 c8 23 | jsrsprite_queue_push; blit debris particle to screen |
| $2466 | ca | b_2466dex; x-ref: $2430, $2443 |
| $2467 | 10 c3 | bplb_242C |
| $2469 | 60 | rts |
| $246A | | .byte$00, $00 |
| $246C | a5 04 | b_246Cldazp_raster_split_a; --- Bike renderer: 3x3 character grid --- ; x-ref: $2426 |
| $246E | 49 06 | eor#$06; (split_a XOR $06) >> 1 -> sub-pixel frame index |
| $2470 | 4a | lsra |
| $2471 | aa | tax |
| $2472 | bd c8 1c | ldabike_char_base,x; f1CC8[frame] -> base char for top half of bike |
| $2475 | 85 f8 | stazp_ted_ctrl_staging |
| $2477 | a5 05 | ldazp_raster_split_b |
| $2479 | 49 06 | eor#$06 |
| $247B | 4a | lsra |
| $247C | aa | tax |
| $247D | bd c8 1c | ldabike_char_base,x; f1CC8[frame] -> base char for bottom half of bike |
| $2480 | 85 f9 | stazp_pitch_hi |
| $2482 | a5 27 | ldazp_bike_pos_x_hi |
| $2484 | 29 03 | and#$03; bike_pos_hi & $03 -> sub-position column offset |
| $2486 | aa | tax |
| $2487 | bd cc 1c | ldabike_subpos_offset,x; f1CCC[sub-pos] -> char offset for smooth horizontal motion |
| $248A | 18 | clc |
| $248B | 65 f8 | adczp_ted_ctrl_staging |
| $248D | 85 f8 | stazp_ted_ctrl_staging |
| $248F | bd cc 1c | ldabike_subpos_offset,x |
| $2492 | 18 | clc |
| $2493 | 65 f9 | adczp_pitch_hi |
| $2495 | 85 f9 | stazp_pitch_hi |
| $2497 | a5 27 | ldazp_bike_pos_x_hi |
| $2499 | 4a | lsra; screen column = bike_pos_hi >> 2 |
| $249A | 4a | lsra |
| $249B | 85 fc | stazp_blit_col |
| $249D | a0 00 | ldy#$00 |
| $249F | a9 10 | b_249Flda#$10; outer loop: 3 columns (Y=0..2) ; x-ref: $24D1 |
| $24A1 | 85 fd | stazp_blit_row |
| $24A3 | a2 00 | ldx#$00 |
| $24A5 | a5 fc | ldazp_blit_col |
| $24A7 | c9 10 | cmp#$10; select top or bottom half char base |
| $24A9 | 90 04 | bccb_24AF |
| $24AB | a5 f9 | ldazp_pitch_hi |
| $24AD | d0 02 | bneb_24B1 |
| $24AF | a5 f8 | b_24AFldazp_ted_ctrl_staging; x-ref: $24A9 |
| $24B1 | 85 ff | b_24B1stazp_blit_char_idx; x-ref: $24AD |
| $24B3 | a9 39 | lda#$39; $39 = bike colour attribute |
| $24B5 | 85 fe | stazp_blit_color_ptr |
| $24B7 | 20 c8 23 | b_24B7jsrsprite_queue_push; inner loop: blit 3 rows per column via s23C8 ; x-ref: $24C6 |
| $24BA | e8 | inx |
| $24BB | a5 ff | ldazp_blit_char_idx |
| $24BD | 18 | clc |
| $24BE | 69 03 | adc#$03; char_idx += 3 (next animation frame in sequence) |
| $24C0 | 85 ff | stazp_blit_char_idx |
| $24C2 | e6 fd | inczp_blit_row |
| $24C4 | e0 03 | cpx#$03 |
| $24C6 | d0 ef | bneb_24B7 |
| $24C8 | e6 f8 | inczp_ted_ctrl_staging; advance both char bases and column for next column |
| $24CA | e6 f9 | inczp_pitch_hi |
| $24CC | e6 fc | inczp_blit_col |
| $24CE | c8 | iny |
| $24CF | c0 03 | cpy#$03 |
| $24D1 | d0 cc | bneb_249F |
| $24D3 | 60 | rts |
| $24D4 | | .byte$00, $00, $00, $00 |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| ; Track scroll engine - converts throttle + course speed into smooth sub-pixel |
| ; scrolling via TED fine scroll registers. |
| ; |
| ; Uses a fractional accumulator technique: track_scroll_frac is decremented |
| ; by bike_throttle each frame. On underflow, a scroll step occurs (faster |
| ; throttle = more frequent steps = faster scroll). |
| ; |
| ; Two raster splits (raster_split_a/b) cycle through 4 sub-pixel positions |
| ; (0,2,4,6). On wrap past 6->0, a full character row scroll triggers: |
| ; raster_split_b wrap -> s2A0C (track screen update) + s2E28 (advance ptr) |
| ; raster_split_a wrap -> s27FC (obstacle position update) |
| ; |
| ; Dual scroll sources: |
| ; Phase 1: Throttle-driven (bike_throttle) - player speed |
| ; Phase 2: Timer-driven (scroll_speed) - base course rate, independent |
| ; |
| ; Inputs: track_scroll_frac, bike_throttle, raster_split_a/b, |
| ; scroll_timer, scroll_speed |
| ; Outputs: track_scroll_frac, raster_split_a/b, scroll_timer |
| ; Side Effects: s2A0C (track update), s2E28 (ptr advance), s27FC (obstacles), |
| ; s21B4 (raster colour) |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| $24D8 | a5 26 | track_scroll_engineldazp_track_scroll_frac; x-ref: $2102 |
| $24DA | 38 | sec |
| $24DB | e5 2a | sbczp_bike_throttle; frac -= throttle (higher throttle -> faster underflow) |
| $24DD | 85 26 | stazp_track_scroll_frac |
| $24DF | b0 23 | bcsb_2504; no underflow -> skip throttle-driven scroll |
| $24E1 | a5 05 | ldazp_raster_split_b |
| $24E3 | 38 | sec |
| $24E4 | e9 02 | sbc#$02; step split_b by 2 sub-pixels (cycles 0,2,4,6) |
| $24E6 | 29 06 | and#$06 |
| $24E8 | 85 05 | stazp_raster_split_b |
| $24EA | c9 06 | cmp#$06; wrapped past 6? -> full row scroll needed |
| $24EC | d0 06 | bneb_24F4 |
| $24EE | 20 0c 2a | jsrtick_scroll_tiles_if_active; full row scroll: update track screen content |
| $24F1 | 20 28 2e | jsradvance_course_data_ptr; advance track data pointer to next row |
| $24F4 | a5 04 | b_24F4ldazp_raster_split_a; x-ref: $24EC |
| $24F6 | 38 | sec |
| $24F7 | e9 02 | sbc#$02; step split_a by 2 sub-pixels (cycles 0,2,4,6) |
| $24F9 | 29 06 | and#$06 |
| $24FB | 85 04 | stazp_raster_split_a |
| $24FD | c9 06 | cmp#$06 |
| $24FF | d0 03 | bneb_2504 |
| $2501 | 20 fc 27 | jsrobstacle_life_tick; split_a wrapped: update obstacle positions |
| $2504 | a5 3e | b_2504ldazp_scroll_timer; x-ref: $24DF, $24FF |
| $2506 | 38 | sec |
| $2507 | e5 53 | sbczp_scroll_speed; timer -= scroll_speed (base course rate) |
| $2509 | 85 3e | stazp_scroll_timer |
| $250B | b0 10 | bcsb_251D; no underflow -> skip timer-driven scroll |
| $250D | a5 04 | ldazp_raster_split_a |
| $250F | 38 | sec |
| $2510 | e9 02 | sbc#$02; timer scroll: step split_a sub-pixels |
| $2512 | 29 06 | and#$06 |
| $2514 | 85 04 | stazp_raster_split_a |
| $2516 | c9 06 | cmp#$06 |
| $2518 | d0 03 | bneb_251D |
| $251A | 20 fc 27 | jsrobstacle_life_tick; timer split_a wrapped: update obstacle positions |
| $251D | 20 b4 21 | b_251Djsrclear_split_if_stationary; update raster colour state for IRQ handler ; x-ref: $250B, $2518 |
| $2520 | 60 | rts |
| $2521 | | .byte$00, $00, $00 |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| ; Per-frame obstacle physics update. Loops over 4 obstacle slots (X=3..0) |
| ; and integrates velocity into position, applies boundary bounce/wrap, and |
| ; triggers a collision sound when a height threshold is crossed. |
| ; |
| ; Per-slot zero-page layout (base + X): |
| ; f10,x ($10+X) -- type/flags: $FF=inactive; bits 0-2=type; |
| ; bit3=high-speed; bit4=sound-triggered |
| ; f14,x ($14+X) -- lifetime countdown |
| ; f18,x ($18+X) -- position high byte (integer Y) |
| ; f1C,x ($1C+X) -- position low byte (fractional / sub-pixel) |
| ; f20,x ($20+X) -- velocity (signed) |
| ; |
| ; Low-speed path (f10,x < $08, e.g. barrels): |
| ; Integrates f20 into f1C/f18 with carry. Boundary checks on f18: |
| ; $10-$2F -> negate velocity (bounce via s293C) |
| ; >= $30 -> nudge position down then bounce |
| ; < $10 -> nudge position up then bounce |
| ; |
| ; High-speed path (f10,x >= $08, e.g. tyres): |
| ; Adds f18 into f1C; carry propagates into f20. When (f20 & $1F)==$10 |
| ; AND ((X XOR frame_counter) & $03)==0: arms collision sound via s2C20 |
| ; and sets bit 4 of f10,x. Otherwise clears bit 4. |
| ; The frame-counter gate staggers triggers across 4 frames to prevent |
| ; multiple sounds firing simultaneously. |
| ; |
| ; Inputs: f10,x-f20,x (4 slots), a3F (frame counter) |
| ; Outputs: f18,x (position), f1C,x (sub-pixel), f20,x (velocity), |
| ; f10,x (flags) |
| ; Side Effects: May arm obstacle sound via s2C20 (JMPER, DSCPNT, a51, SIZE) |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| update_obstacle_physics |
| $2524 | a2 03 | ldx#$03; Loop over 4 obstacle slots (X=3..0) ; x-ref: $20DD |
| $2526 | b5 10 | b_2526ldazp_obstacle_flags,x; Load obstacle type/flags for this slot ; x-ref: $2581 |
| $2528 | c9 ff | cmp#$ff |
| $252A | f0 54 | beqb_2580; Slot inactive — skip to next |
| $252C | c9 08 | cmp#$08; type >= $08 -> high-speed path (tyres etc.) |
| $252E | b0 28 | bcsb_2558 |
| $2530 | b5 20 | ldazp_obstacle_vel,x; Load velocity; negative -> pre-decrement integer position for signed carry |
| $2532 | 10 02 | bplb_2536 |
| $2534 | d6 18 | deczp_obstacle_pos_hi,x; Pre-decrement integer pos to handle negative velocity carry correctly |
| $2536 | b5 1c | b_2536ldazp_obstacle_pos_lo,x; Integrate: fractional pos += velocity ; x-ref: $2532 |
| $2538 | 18 | clc |
| $2539 | 75 20 | adczp_obstacle_vel,x |
| $253B | 95 1c | stazp_obstacle_pos_lo,x |
| $253D | b5 18 | ldazp_obstacle_pos_hi,x; Propagate fractional carry into integer position |
| $253F | 69 00 | adc#$00 |
| $2541 | 95 18 | stazp_obstacle_pos_hi,x |
| $2543 | c9 10 | cmp#$10; Below upper boundary ($10)? -> nudge up path |
| $2545 | 90 08 | bccb_254F |
| $2547 | c9 30 | cmp#$30; Between $10-$2F -> bounce (negate velocity) |
| $2549 | 90 09 | bccb_2554 |
| $254B | d6 18 | deczp_obstacle_pos_hi,x; Above ceiling ($30): nudge position down, then bounce |
| $254D | d0 02 | bneb_2551 |
| $254F | f6 18 | b_254Finczp_obstacle_pos_hi,x; Below floor ($10): nudge position up ; x-ref: $2545 |
| $2551 | 20 3c 29 | b_2551jsrnegate_obstacle_vel; Negate velocity (bounce) ; x-ref: $254D |
| $2554 | 18 | b_2554clc; x-ref: $2549 |
| $2555 | 90 29 | bccb_2580 |
| $2557 | ea | nop |
| $2558 | b5 1c | b_2558ldazp_obstacle_pos_lo,x; --- High-speed path (f10,x >= $08, e.g. tyres) --- ; x-ref: $252E |
| $255A | 18 | clc |
| $255B | 75 18 | adczp_obstacle_pos_hi,x; Accumulator += integer position as velocity step; carry into f20 |
| $255D | 95 1c | stazp_obstacle_pos_lo,x |
| $255F | b5 20 | ldazp_obstacle_vel,x |
| $2561 | 69 00 | adc#$00 |
| $2563 | 95 20 | stazp_obstacle_vel,x; Check low 5 bits of velocity == $10 (mid-range threshold) |
| $2565 | 29 1f | and#$1f |
| $2567 | c9 10 | cmp#$10 |
| $2569 | d0 0f | bneb_257A; Gate: (slot XOR frame_counter) & $03 == 0 -> only 1 in 4 frames per slot |
| $256B | 8a | txa |
| $256C | 45 3f | eorzp_frame_counter |
| $256E | 29 03 | and#$03 |
| $2570 | d0 08 | bneb_257A |
| $2572 | b5 10 | ldazp_obstacle_flags,x; Arm collision sound + set bit 4 in f10,x (sound-triggered flag) |
| $2574 | 20 20 2c | jsrsfx_obstacle_collision_arm |
| $2577 | ea | nop |
| $2578 | d0 06 | bneb_2580 |
| $257A | b5 10 | b_257Aldazp_obstacle_flags,x; Not at threshold or wrong frame: clear bit 4 (reset sound-triggered flag) ; x-ref: $2569, $2570 |
| $257C | 29 ef | and#$ef |
| $257E | 95 10 | stazp_obstacle_flags,x |
| $2580 | ca | b_2580dex; Next slot; loop until X < 0 ; x-ref: $252A, $2555, $2578 |
| $2581 | 10 a3 | bplb_2526 |
| $2583 | 60 | rts |
| $2584 | | .byte$00, $00, $00, $00 |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| ; Draws the progress/lap HUD bar on two consecutive screen rows. |
| ; Phase 1: Clear 40-char row at $0B98 with blanks ($00). |
| ; Phase 2: Draw course progress markers ($3A) at $0BAF+X, one per completed |
| ; course (clamped to max 15), filling right-to-left. |
| ; Phase 3: Draw lap pips ($29) at $0B97+X, 3 chars per remaining lap, |
| ; filling right-to-left. |
| ; Phase 4: Copy the completed row to a second row at $0BC0 (shadow/duplicate). |
| ; |
| ; Inputs: course_index, lives_counter |
| ; Outputs: Screen RAM $0B98-$0BBF (row 1), $0BC0-$0BE7 (row 2) |
| ; Side Effects: None (pure screen write) |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| draw_hud_progress_bar |
| $2588 | a2 27 | ldx#$27; 40 chars = one full screen row ; x-ref: $20E6 |
| $258A | a9 00 | lda#$00 |
| $258C | 9d 98 0b | b_258CstaCOLOR_RAM_R23C0,x; clear HUD row with blanks ; x-ref: $2590 |
| $258F | ca | dex |
| $2590 | 10 fa | bplb_258C |
| $2592 | a5 2f | ldazp_course_index |
| $2594 | c9 0f | cmp#$0f; clamp course_index to max 15 |
| $2596 | 90 02 | bccb_259A |
| $2598 | a9 0f | lda#$0f |
| $259A | aa | b_259Atax; x-ref: $2596 |
| $259B | e0 ff | b_259Bcpx#$ff; x-ref: $25A5 |
| $259D | f0 08 | beqb_25A7 |
| $259F | a9 3a | lda#$3a; $3A = course progress marker char |
| $25A1 | 9d af 0b | staCOLOR_RAM_R23C23,x; draw one marker per completed course (right side of row) |
| $25A4 | ca | dex |
| $25A5 | 10 f4 | bplb_259B |
| $25A7 | a5 30 | b_25A7ldazp_lives_counter; X = lives_counter * 3 (3 chars per lap pip group) ; x-ref: $259D |
| $25A9 | 0a | asla |
| $25AA | 18 | clc |
| $25AB | 65 30 | adczp_lives_counter |
| $25AD | aa | tax |
| $25AE | ca | dex |
| $25AF | e0 00 | b_25AFcpx#$00; x-ref: $25C1 |
| $25B1 | 30 10 | bmib_25C3 |
| $25B3 | a9 29 | lda#$29; $29 = lap pip char (3 consecutive per lap) |
| $25B5 | 9d 97 0b | staCOLOR_RAM_R22C39,x; draw 3-char pip group (left side of row) |
| $25B8 | 9d 98 0b | staCOLOR_RAM_R23C0,x |
| $25BB | 9d 99 0b | staCOLOR_RAM_R23C1,x |
| $25BE | ca | dex; advance 3 positions for next pip group |
| $25BF | ca | dex |
| $25C0 | ca | dex |
| $25C1 | 10 ec | bplb_25AF |
| $25C3 | a2 27 | b_25C3ldx#$27; copy completed row to second row at $0BC0 (shadow) ; x-ref: $25B1 |
| $25C5 | bd 98 0b | b_25C5ldaCOLOR_RAM_R23C0,x; x-ref: $25CC |
| $25C8 | 9d c0 0b | staCOLOR_RAM_R24C0,x |
| $25CB | ca | dex |
| $25CC | 10 f7 | bplb_25C5 |
| $25CE | 60 | rts |
| $25CF | | .byte$00 |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| ; Main game state machine dispatcher - called once per frame from the main loop. |
| ; Reads game_mode and dispatches to the handler for the current game phase: |
| ; |
| ; Mode 0: handle_mode_normal_ride - Fire/jump button -> movement dispatch |
| ; Mode 1: handle_mode_crash_debris - Wait for debris landing -> respawn |
| ; Mode 2: handle_mode_active_ride - Throttle input, bounds, physics, FX |
| ; Mode 3: handle_mode_starting_gate - Left-edge enforce + throttle decay |
| ; Mode 4: handle_mode_track_scroll - Track scrolling + finish animation |
| ; Mode 5: handle_mode_debris_wait - Wait debris clear -> lap/course end |
| ; Mode 6: handle_mode_results_screen - Descending jingle -> return to menu |
| ; Mode 7: apply_velocity_and_integrate - Velocity + 4x position integration |
| ; Mode 8: handle_mode_next_lap_init - Poll readiness -> start next lap |
| ; |
| ; Game flow: 0->2 (ride), crash->1->0 (respawn), bounds->7 (correct), |
| ; 3 (decay)->4 (scroll)->5 (debris wait)->8 (next lap)->1 or 6 (results). |
| ; |
| ; Inputs: game_mode |
| ; Outputs: Delegates entirely to the target handler |
| ; Side Effects: All side effects come from the dispatched handler |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| $25D0 | a5 02 | handle_game_modeldazp_game_mode; read current game state ; x-ref: $20E9 |
| $25D2 | c9 00 | cmp#GameMode.NORMAL_RIDE |
| $25D4 | f0 21 | beqhandle_game_mode_0; mode 0: normal riding |
| $25D6 | c9 01 | cmp#GameMode.CRASH_DEBRIS |
| $25D8 | f0 20 | beqhandle_game_mode_1; mode 1: crash debris settle |
| $25DA | c9 02 | cmp#GameMode.ACTIVE_RIDE |
| $25DC | f0 1f | beqhandle_game_mode_2; mode 2: active riding |
| $25DE | c9 03 | cmp#GameMode.STARTING_GATE |
| $25E0 | f0 1e | beqhandle_game_mode_3; mode 3: starting gate |
| $25E2 | c9 04 | cmp#GameMode.TRACK_SCROLL |
| $25E4 | f0 1d | beqhandle_game_mode_4; mode 4: track scrolling |
| $25E6 | c9 05 | cmp#GameMode.DEBRIS_WAIT |
| $25E8 | f0 1c | beqhandle_game_mode_5; mode 5: debris wait / lap transition |
| $25EA | c9 06 | cmp#GameMode.RESULTS_SCREEN |
| $25EC | f0 1b | beqhandle_game_mode_6; mode 6: results screen |
| $25EE | c9 07 | cmp#GameMode.VELOCITY_INTEGRATE |
| $25F0 | f0 1a | beqhandle_game_mode_7; mode 7: velocity correction |
| $25F2 | c9 08 | cmp#GameMode.NEXT_LAP_INIT |
| $25F4 | f0 19 | beqhandle_game_mode_8; mode 8: next lap init |
| $25F6 | 60 | rts; unknown mode: no-op |
| $25F7 | 4c 54 27 | handle_game_mode_0jmphandle_mode_normal_ride; x-ref: $25D4 |
| $25FA | 4c 64 27 | handle_game_mode_1jmphandle_mode_crash_debris; x-ref: $25D8 |
| $25FD | 4c 84 27 | handle_game_mode_2jmphandle_mode_active_ride; x-ref: $25DC |
| $2600 | 4c b8 2e | handle_game_mode_3jmphandle_mode_starting_gate; x-ref: $25E0 |
| $2603 | 4c 34 28 | handle_game_mode_4jmphandle_mode_track_scroll; x-ref: $25E4 |
| $2606 | 4c 94 28 | handle_game_mode_5jmphandle_mode_debris_wait; x-ref: $25E8 |
| $2609 | 4c c4 28 | handle_game_mode_6jmphandle_mode_results_screen; x-ref: $25EC |
| $260C | 4c f8 28 | handle_game_mode_7jmpapply_velocity_and_integrate; x-ref: $25F0 |
| $260F | 4c 48 29 | handle_game_mode_8jmphandle_mode_next_lap_init; x-ref: $25F4 |
| $2612 | | .byte$00, $00 |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| ; Resets the CBM BASIC 3.5 interpreter runtime state to a clean baseline. |
| ; Zeroes or re-initialises a suite of zero-page BASIC variables (INDEX2, |
| ; FRESPC, SUBFLG[0-3], ZPVEC2, RESHO, SRCHTK, OLDOV, TEMPF1) and sets |
| ; several unlabelled scratch bytes to fixed sentinel values. Called during |
| ; level initialisation (after TED screen setup) to ensure no stale BASIC |
| ; engine state leaks between levels. |
| ; |
| ; Inputs: None |
| ; Outputs: None |
| ; Side Effects: Modifies RAM_INDEX2, RAM_FRESPC, RAM_SUBFLG[0-3], RAM_ZPVEC2, |
| ; RAM_RESHO, RAM_SRCHTK, RAM_OLDOV, RAM_TEMPF1; sets $25=$2F, |
| ; $34=$05, $2A=$80 |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| reset_basic_runtime_state |
| $2614 | a9 00 | lda#$00; Clear INDEX2 (utility pointer used by BASIC string/array ops) ; x-ref: $20AB, $28CC |
| $2616 | 85 24 | stazp_ptr_obj_record_lo |
| $2618 | a9 2f | lda#$2f |
| $261A | 85 25 | stazp_ptr_obj_record_hi; ZP scratch $25 = $2F (BASIC engine internal field) |
| $261C | a9 05 | lda#$05 |
| $261E | 85 34 | stazp_music_step; ZP scratch $34 = 5 (BASIC engine internal field) |
| $2620 | a9 ff | lda#$ff |
| $2622 | 85 35 | stazp_music_pos; FRESPC=$FF: mark string space as invalid/unallocated |
| $2624 | a2 03 | ldx#$03; X=3: fill SUBFLG[0..3] with $FF (disable subscript/user-fn flags) |
| $2626 | a9 ff | lda#$ff |
| $2628 | 95 10 | b_2628stazp_obstacle_flags,x; SUBFLG[X] = $FF; repeat for X=3,2,1,0 ; x-ref: $262B |
| $262A | ca | dex |
| $262B | 10 fb | bplb_2628 |
| $262D | a9 00 | lda#0 |
| $262F | 85 04 | stazp_raster_split_a |
| $2631 | 85 05 | stazp_raster_split_b |
| $2633 | 85 26 | stazp_track_scroll_frac |
| $2635 | 85 02 | stazp_game_mode; Zero ZPVEC2 (temp for renumber), RESHO (expression result high byte), SRCHTK (token search key) |
| $2637 | a9 80 | lda#$80 |
| $2639 | 85 2a | stazp_bike_throttle; $2A=$80: set high-bit state flag (signals BASIC engine not inside a loop) |
| $263B | 20 0c 2e | jsrreset_display_counters; Zero OLDOV (overflow flag) and TEMPF1 (FP temporary) |
| $263E | 60 | rts |
| $263F | | .byte$00 |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| ; Initializes all per-course game state for the start of a ride. |
| ; Resets lives_counter to 5, sets neutral throttle ($60), clears raster |
| ; split lines, scroll fraction, and scroll direction, marks player active |
| ; ($FF), then calls s2E14 (load course object-record pointer from |
| ; title_char_idx) and s2A3A (clear scroll tables, load anim_frame_count |
| ; and scroll_speed for the current course). |
| ; Called from handle_mode_normal_ride on the no-jump path. |
| ; |
| ; Inputs: title_char_idx = selected course/character index |
| ; Outputs: lives_counter=5, bike_throttle=$60, raster_split_a/b=0, |
| ; track_scroll_frac=0, scroll_dir_flag=0, player_active=$FF, |
| ; course_index, ptr_obj_record_lo/hi, anim_frame_count, scroll_speed |
| ; Side Effects: Scroll position tables cleared (via s2A2C inside s2A3A) |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| $2640 | 20 14 2e | init_course_statejsrload_course_layout; load course object-record pointer from title_char_idx ; x-ref: $275A |
| $2643 | a9 05 | lda#$05; start with 5 laps |
| $2645 | 85 30 | stazp_lives_counter |
| $2647 | a9 60 | lda#$60; neutral/mid throttle |
| $2649 | 85 2a | stazp_bike_throttle |
| $264B | a9 00 | lda#$00; clear raster splits, scroll fraction, and scroll direction |
| $264D | 85 04 | stazp_raster_split_a |
| $264F | 85 05 | stazp_raster_split_b |
| $2651 | 85 26 | stazp_track_scroll_frac |
| $2653 | 85 31 | stazp_scroll_dir_flag |
| $2655 | a9 ff | lda#$ff; mark player as active |
| $2657 | 85 3b | stazp_player_active |
| $2659 | 20 3a 2a | jsrclear_track_and_load_course; clear scroll tables, load anim_frame_count + scroll_speed for course |
| $265C | 20 64 26 | jsrinit_lap_start_anim |
| $265F | 60 | rts |
| $2660 | | .byte$00, $00, $00, $00 |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| ; Kills all 4 obstacle slots then initializes the lap-start debris animation. |
| ; Sets all obstacle_flags to $FF (inactive), then falls through into |
| ; init_lap_start_anim_no_kill to trigger the sound effect, load 16 debris |
| ; X-positions from f1CD0, enter game_mode=1, and clear spawn_cooldown. |
| ; Called from init_course_state at course start (full reset path). |
| ; |
| ; Inputs: None |
| ; Outputs: obstacle_flags[0..3]=$FF, crash_debris_x[0..15] from f1CD0, |
| ; game_mode=1, spawn_cooldown=0 |
| ; Side Effects: Sound triggered via s2BDC |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| $2664 | a2 03 | init_lap_start_animldx#$03; kill all 4 obstacle slots (flags=$FF = inactive) ; x-ref: $265C |
| $2666 | a9 ff | lda#$ff |
| $2668 | 95 10 | b_2668stazp_obstacle_flags,x; x-ref: $266B |
| $266A | ca | dex |
| $266B | 10 fb | bplb_2668 |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| ; Initializes the lap-start debris animation without killing obstacle slots. |
| ; Partial entry point: skips the obstacle_flags reset, jumps straight to |
| ; triggering the lap-start sound (s2BDC), loading 16 debris X-positions |
| ; from the f1CD0 table into crash_debris_x, setting game_mode=1, and |
| ; clearing spawn_cooldown. |
| ; Called from handle_mode_next_lap_init at lap transitions where obstacles |
| ; have already been cleared. |
| ; |
| ; Inputs: None |
| ; Outputs: crash_debris_x[0..15] from f1CD0, game_mode=1, spawn_cooldown=0 |
| ; Side Effects: Sound triggered via s2BDC |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| init_lap_start_anim_no_kill |
| $266D | 20 dc 2b | jsrsfx_lap_start; trigger lap-start sound (pitch=$C0, delta=$04, dur=$0F, vol=$50) ; x-ref: $295E |
| $2670 | a2 0f | ldx#$0f; load 16 debris X-positions from f1CD0 into crash_debris_x |
| $2672 | bd d0 1c | b_2672ldadebris_start_x_positions,x; x-ref: $2678 |
| $2675 | 95 40 | stazp_crash_debris_x,x |
| $2677 | ca | dex |
| $2678 | 10 f8 | bplb_2672 |
| $267A | a9 01 | lda#GameMode.CRASH_DEBRIS; game_mode = 1 (debris / lap-start animation), no obstacle spawning yet |
| $267C | 85 02 | stazp_game_mode |
| $267E | a9 00 | lda#$00 |
| $2680 | 85 2b | stazp_spawn_cooldown |
| $2682 | 60 | rts |
| $2683 | | .byte$00 |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| ; Stops the bike and resets it to the left track edge, entering mode 2 |
| ; (starting-gate / stopped state). Zeroes fractional position and velocity, |
| ; pins bike_pos_hi to track_left_edge, and sets game_mode=2. |
| ; Called on boundary violations and soft mode-transition recoveries. |
| ; |
| ; Inputs: track_left_edge = left boundary to pin bike to |
| ; Outputs: bike_pos_lo=0, bike_vel=0, game_mode=2, bike_pos_hi=track_left_edge |
| ; Side Effects: None |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| $2684 | a9 00 | stop_bike_and_resetlda#$00; zero fractional position and velocity ; x-ref: $2842, $2937 |
| $2686 | 85 28 | stazp_bike_pos_x_lo |
| $2688 | 85 29 | stazp_bike_vel |
| $268A | a9 02 | lda#GameMode.ACTIVE_RIDE; game_mode = 2 (starting gate / stopped) |
| $268C | 85 02 | stazp_game_mode |
| $268E | a5 37 | ldazp_track_left_edge; pin bike to left track boundary |
| $2690 | 85 27 | stazp_bike_pos_x_hi |
| $2692 | 60 | rts |
| $2693 | | .byte$00 |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| ; Transition: enter riding mode (mode 3). |
| ; Sets game_mode=3 (player active / in-play state). Called after setting |
| ; player_active=$FF, signaling the player has engaged from the starting gate |
| ; and normal bike-riding logic should take over. |
| ; |
| ; Inputs: None |
| ; Outputs: game_mode=3 |
| ; Side Effects: None |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| $2694 | a9 03 | enter_mode_ridinglda#GameMode.STARTING_GATE; game_mode = 3 (player active / riding) ; x-ref: $233C |
| $2696 | 85 02 | stazp_game_mode |
| $2698 | 60 | rts |
| $2699 | | .byte$00, $00, $00 |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| ; Transition: enter track scroll mode (mode 4). |
| ; Sets game_mode=4, clears scroll_dir_flag, calls s2964 to init scroll state. |
| ; Called when starting gate throttle reaches zero. |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| enter_mode_track_scroll |
| $269C | a9 04 | lda#GameMode.TRACK_SCROLL; game_mode = 4 (track scroll) ; x-ref: $282C |
| $269E | 85 02 | stazp_game_mode |
| $26A0 | a9 00 | lda#$00 |
| $26A2 | 85 31 | stazp_scroll_dir_flag |
| $26A4 | 20 64 29 | jsrinit_score_screen; initialize score screen (results display) |
| $26A7 | 60 | rts |
| $26A8 | | .byte$00, $00, $00, $00 |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| ; Trigger crash - initializes debris explosion and enters mode 5. |
| ; Sets all 8 debris particles to X=$10, Y=bike_pos_hi/4 (bike screen col). |
| ; Zeroes track_progress and bike_throttle, triggers crash sound (s2B8C). |
| ; Called on boundary violations and obstacle collisions. |
| ; |
| ; Inputs: bike_pos_hi |
| ; Outputs: crash_debris_x/y[0..7] (initialized), game_mode=5, |
| ; track_progress=0, bike_throttle=0 |
| ; Side Effects: Crash sound (s2B8C) |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| $26AC | a2 07 | trigger_crashldx#$07; --- Init 8 debris particles at bike position --- ; x-ref: $21AF, $27B7, $2933, $2D5D |
| $26AE | a9 10 | b_26AElda#$10; all particles start at X=$10 (center) ; x-ref: $26B9 |
| $26B0 | 95 40 | stazp_crash_debris_x,x |
| $26B2 | a5 27 | ldazp_bike_pos_x_hi |
| $26B4 | 4a | lsra; Y = bike screen column (pos_hi >> 2) |
| $26B5 | 4a | lsra |
| $26B6 | 95 48 | stazp_crash_debris_y,x |
| $26B8 | ca | dex |
| $26B9 | 10 f3 | bplb_26AE |
| $26BB | a9 05 | lda#GameMode.DEBRIS_WAIT; game_mode = 5 (debris wait) |
| $26BD | 85 02 | stazp_game_mode |
| $26BF | a9 00 | lda#$00 |
| $26C1 | 85 36 | stazp_track_progress |
| $26C3 | a9 00 | lda#$00 |
| $26C5 | 85 2a | stazp_bike_throttle |
| $26C7 | 20 8c 2b | jsrsfx_crash_explosion; trigger crash sound effect |
| $26CA | 60 | rts |
| $26CB | | .byte$00 |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| ; Setup course-end screen - copies 16-char text from f1CE0 to screen $0D4E |
| ; with colour $71, kills all 4 obstacle slots, resets track_progress, |
| ; and enters mode 6 (results screen). |
| ; Called when no laps remain after debris clears. |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| setup_course_end_screen |
| $26CC | a2 0f | ldx#$0f; x-ref: $28BD |
| $26CE | bd e0 1c | b_26CEldacourse_end_text,x; copy 16-char course-end text from f1CE0 to screen ; x-ref: $26DA |
| $26D1 | 9d 4e 0d | staSCREEN_RAM_R8C14,x |
| $26D4 | a9 71 | lda#$71; $71 = course-end text colour |
| $26D6 | 9d 4e 09 | staCOLOR_RAM_R8C14,x |
| $26D9 | ca | dex |
| $26DA | 10 f2 | bplb_26CE |
| $26DC | a9 00 | lda#$00 |
| $26DE | 85 36 | stazp_track_progress |
| $26E0 | a9 06 | lda#GameMode.RESULTS_SCREEN; game_mode = 6 (results screen) |
| $26E2 | 85 02 | stazp_game_mode |
| $26E4 | a2 03 | ldx#$03 |
| $26E6 | a9 ff | lda#$ff; kill all 4 obstacle slots ($FF) |
| $26E8 | 95 10 | b_26E8stazp_obstacle_flags,x; x-ref: $26EB |
| $26EA | ca | dex |
| $26EB | 10 fb | bplb_26E8 |
| $26ED | 60 | rts |
| $26EE | | .byte$00, $00 |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| ; Transition: enter velocity correction mode (mode 7). |
| ; Stores A into bike_vel, sets game_mode=7. |
| ; Called from physics boundary checks and throttle handlers. |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| enter_mode_vel_correct |
| $26F0 | 85 29 | stazp_bike_vel; store velocity (A) and set game_mode=7 ; x-ref: $2772, $2B5C, $2B74, $2E7C, $2E88 |
| $26F2 | a9 07 | lda#GameMode.VELOCITY_INTEGRATE |
| $26F4 | 85 02 | stazp_game_mode |
| $26F6 | 60 | rts |
| $26F7 | | .byte$00 |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| ; Transition: enter next lap mode (mode 8). |
| ; Sets bike_throttle=$60 (mid), game_mode=8. |
| ; Called when laps remain after debris clears. |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| $26F8 | a9 60 | enter_mode_next_laplda#$60; throttle=$60, game_mode=8 (next lap) ; x-ref: $28B9 |
| $26FA | 85 2a | stazp_bike_throttle |
| $26FC | a9 08 | lda#GameMode.NEXT_LAP_INIT |
| $26FE | 85 02 | stazp_game_mode |
| $2700 | 60 | rts |
| $2701 | | .byte$00, $00, $00 |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| ; Joystick input scanner for the Plus/4. |
| ; Reads the joystick port by scanning two keyboard matrix rows via $FD30 |
| ; (keyboard latch / row select) and $FF08 (TED keyboard input register). |
| ; Joystick signals are active-low on the hardware; this routine extracts |
| ; individual direction and fire bits from two matrix scans, remaps them |
| ; into a single byte, and inverts the direction nibble to active-high. |
| ; |
| ; Scan 1: $FD30=$FA -> $FF08 read -> Y (directions A + fire bit 6) |
| ; Scan 2: $FD30=$FD -> $FF08 read -> X (directions B) |
| ; Bit remap: X bits are merged into Y by conditionally clearing Y bits. |
| ; Final: a33 = ((Y & $0F) | ((Y & $40) << 1)) XOR $0F |
| ; |
| ; Output bit layout (a33): |
| ; Bit 0: Direction 1 Bit 4-6: Unused (0) |
| ; Bit 1: Direction 2 Bit 7: Fire button |
| ; Bit 2: Tilt back (subtract) (directions are active-high; |
| ; Bit 3: Tilt forward (add) fire is active-high) |
| ; |
| ; Inputs: $FD30, $FF08 (hardware keyboard matrix registers) |
| ; Outputs: a33 ($33) -- normalized joystick state byte |
| ; Side Effects: Briefly disables IRQs (SEI/CLI) during hardware scan |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| $2704 | 78 | read_joysticksei; Disable IRQs during keyboard matrix scan ; x-ref: $20E3 |
| $2705 | a9 fa | lda#$fa; Scan row 1: select keyboard matrix row $FA via $FD30 |
| $2707 | 8d 30 fd | sta$fd30 |
| $270A | 8d 08 ff | sta$ff08 |
| $270D | ac 08 ff | ldy$ff08; Y = row 1 result (directions A + fire in bit 6) |
| $2710 | a9 fd | lda#$fd; Scan row 2: select keyboard matrix row $FD via $FD30 |
| $2712 | 8d 30 fd | sta$fd30 |
| $2715 | 8d 08 ff | sta$ff08 |
| $2718 | ae 08 ff | ldx$ff08; X = row 2 result (directions B) |
| $271B | 58 | cli; Re-enable IRQs -- scan complete |
| $271C | 8a | txa; --- Bit remap: merge X direction bits into Y --- |
| $271D | 29 10 | and#$10; X bit 4 -> if clear, clear Y bit 1 |
| $271F | d0 04 | bneb_2725 |
| $2721 | 98 | tya |
| $2722 | 29 fd | and#$fd |
| $2724 | a8 | tay |
| $2725 | 8a | b_2725txa; X bit 2 -> if clear, clear Y bit 0 ; x-ref: $271F |
| $2726 | 29 04 | and#$04 |
| $2728 | d0 04 | bneb_272E |
| $272A | 98 | tya |
| $272B | 29 fe | and#$fe |
| $272D | a8 | tay |
| $272E | 8a | b_272Etxa; X bit 0 -> if clear, clear Y bit 2 ; x-ref: $2728 |
| $272F | 29 01 | and#$01 |
| $2731 | d0 04 | bneb_2737 |
| $2733 | 98 | tya |
| $2734 | 29 fb | and#$fb |
| $2736 | a8 | tay |
| $2737 | 8a | b_2737txa; X bit 3 -> if clear, clear Y bit 3 ; x-ref: $2731 |
| $2738 | 29 08 | and#$08 |
| $273A | d0 04 | bneb_2740 |
| $273C | 98 | tya |
| $273D | 29 f7 | and#$f7 |
| $273F | a8 | tay |
| $2740 | 98 | b_2740tya; --- Final assembly: combine directions + fire into a33 --- ; x-ref: $273A |
| $2741 | 29 0f | and#$0f |
| $2743 | 85 33 | stazp_joystick_state; Store direction nibble (bits 0-3) |
| $2745 | 98 | tya |
| $2746 | 29 40 | and#$40; Extract fire bit: Y bit 6 -> ASL -> bit 7 -> OR into a33 |
| $2748 | 0a | asla |
| $2749 | 05 33 | orazp_joystick_state |
| $274B | 49 0f | eor#$0f; Invert direction nibble: active-low -> active-high (fire bit 7 unchanged) |
| $274D | 85 33 | stazp_joystick_state; Final joystick state stored in a33 |
| $274F | 60 | rts |
| $2750 | | .byte$00, $00, $00, $00 |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| ; Game mode 0: Normal riding state - dispatches movement based on fire/jump button. |
| ; Reads joystick bit 7 (fire/jump); if held, calls the jump movement routine, |
| ; otherwise calls the standard forward movement routine. |
| ; |
| ; Inputs: joystick_state (bit 7 = fire/jump button) |
| ; Outputs: None (delegates to movement subroutines) |
| ; Side Effects: Calls s2640 (normal move) or s2DB4 (jump move) |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| handle_mode_normal_ride |
| $2754 | a5 33 | ldazp_joystick_state; x-ref: $25F7 |
| $2756 | 29 80 | and#$80; isolate fire/jump button (bit 7) |
| $2758 | d0 04 | bneb_275E; button held -> jump movement |
| $275A | 20 40 26 | jsrinit_course_state; normal movement (no jump) |
| $275D | 60 | rts |
| $275E | 20 b4 2d | b_275Ejsrhandle_jump_and_level_select; jump movement (fire held) ; x-ref: $2758 |
| $2761 | 60 | rts |
| $2762 | | .byte$00, $00 |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| ; Game mode 1: Crash debris flight - waits for debris to reach landing spot, |
| ; then respawns the bike at its starting position with neutral throttle. |
| ; The debris landing position is ($10, $0B). Once reached, bike_pos is reset |
| ; to $2A00 and throttle is set to $80 (neutral mid-point). |
| ; |
| ; Inputs: crash_debris_x, crash_debris_y (debris position) |
| ; Outputs: bike_pos_hi, bike_pos_lo (reset to $2A, $00), bike_throttle (reset to $80) |
| ; Side Effects: Calls s26F0 (likely sprite/screen reset at #$30) |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| handle_mode_crash_debris |
| $2764 | a5 40 | ldazp_crash_debris_x; x-ref: $25FA |
| $2766 | c9 10 | cmp#$10; debris landed at x=$10? |
| $2768 | d0 17 | bner_2781 |
| $276A | a5 48 | ldazp_crash_debris_y |
| $276C | c9 0b | cmp#$0b; debris landed at y=$0B? |
| $276E | d0 11 | bner_2781 |
| $2770 | a9 30 | lda#$30; trigger respawn display/sprite reset |
| $2772 | 20 f0 26 | jsrenter_mode_vel_correct |
| $2775 | a9 2a | lda#$2a |
| $2777 | 85 27 | stazp_bike_pos_x_hi; reset bike position hi = $2A |
| $2779 | a9 00 | lda#$00 |
| $277B | 85 28 | stazp_bike_pos_x_lo; reset bike position lo = $00 |
| $277D | a9 80 | lda#$80 |
| $277F | 85 2a | stazp_bike_throttle; reset throttle to neutral ($80) |
| $2781 | 60 | r_2781rts; x-ref: $2768, $276E |
| $2782 | | .byte$00, $00 |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| ; Game mode 2: Active riding - processes throttle input, enforces track |
| ; boundaries, updates bike physics, and triggers surface audio/visual effects. |
| ; - Joystick bit 3: throttle up (+3, capped at $F9) |
| ; - Joystick bit 2: throttle down (-3, floored at $63) |
| ; - If bike_pos_hi > track_right_edge or < track_left_edge: crash (s26AC) |
| ; - Otherwise: run bike physics update (s2E74) |
| ; - If track_flags & prev_track_flags & $40: trigger surface FX sound (s2B74) |
| ; - If fire not held: trigger idle sound/state (s2B5C with #$CC) |
| ; |
| ; Inputs: joystick_state, bike_throttle, bike_pos_hi, track_right_edge, track_left_edge, |
| ; track_flags, prev_track_flags |
| ; Outputs: bike_throttle (adjusted), delegates physics to s2E74 |
| ; Side Effects: May trigger crash (s26AC), physics (s2E74), sounds (s2B74, s2B5C) |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| handle_mode_active_ride |
| $2784 | a5 33 | ldazp_joystick_state; x-ref: $25FD |
| $2786 | 29 08 | and#$08; isolate throttle-up input (bit 3) |
| $2788 | f0 0d | beqb_2797; no throttle-up input -> skip |
| $278A | a5 2a | ldazp_bike_throttle |
| $278C | c9 f9 | cmp#$f9; already at max throttle ($F9)? |
| $278E | b0 07 | bcsb_2797; at cap -> skip increase |
| $2790 | a5 2a | ldazp_bike_throttle |
| $2792 | 18 | clc |
| $2793 | 69 03 | adc#$03; throttle += 3 |
| $2795 | 85 2a | stazp_bike_throttle |
| $2797 | a5 33 | b_2797ldazp_joystick_state; x-ref: $2788, $278E |
| $2799 | 29 04 | and#$04; isolate throttle-down input (bit 2) |
| $279B | f0 0d | beqb_27AA; no throttle-down input -> skip |
| $279D | a5 2a | ldazp_bike_throttle |
| $279F | c9 63 | cmp#$63; already at min throttle ($63)? |
| $27A1 | 90 07 | bccb_27AA; at floor -> skip decrease |
| $27A3 | a5 2a | ldazp_bike_throttle |
| $27A5 | 38 | sec |
| $27A6 | e9 03 | sbc#$03; throttle -= 3 |
| $27A8 | 85 2a | stazp_bike_throttle |
| $27AA | ea | b_27AAnop; x-ref: $279B, $27A1 |
| $27AB | a5 39 | ldazp_track_right_edge; right track edge limit |
| $27AD | c5 27 | cmpzp_bike_pos_x_hi |
| $27AF | 90 06 | bccb_27B7; bike past right edge -> crash |
| $27B1 | a5 37 | ldazp_track_left_edge; left track edge limit |
| $27B3 | c5 27 | cmpzp_bike_pos_x_hi |
| $27B5 | b0 04 | bcsb_27BB; bike within bounds -> normal physics |
| $27B7 | 20 ac 26 | b_27B7jsrtrigger_crash; out of bounds: trigger crash ; x-ref: $27AF |
| $27BA | 60 | rts |
| $27BB | 20 74 2e | b_27BBjsrcheck_right_boundary; in bounds: run bike physics update ; x-ref: $27B5 |
| $27BE | ea | nop |
| $27BF | ea | nop |
| $27C0 | ea | nop |
| $27C1 | a5 38 | ldazp_track_flags |
| $27C3 | 25 3a | andzp_prev_track_flags; both current & previous frame have bit 6 set |
| $27C5 | 29 40 | and#$40; bit 6: special surface flag (ramp/mud?) |
| $27C7 | f0 06 | beqb_27CF; no surface effect -> check fire button |
| $27C9 | a9 a0 | lda#$a0; surface effect sound/action ($A0) |
| $27CB | 20 74 2b | jsrsfx_surface_impact |
| $27CE | 60 | rts |
| $27CF | a5 33 | b_27CFldazp_joystick_state; x-ref: $27C7 |
| $27D1 | 29 80 | and#$80; fire/jump button held? (bit 7) |
| $27D3 | d0 06 | bner_27DB; fire held -> skip idle sound |
| $27D5 | a9 cc | lda#$cc; idle engine sound/state ($CC) |
| $27D7 | 20 5c 2b | jsrsfx_idle_landing |
| $27DA | 60 | rts |
| $27DB | 60 | r_27DBrts; x-ref: $27D3 |
| $27DC | | .byte$00, $00, $00, $00 |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| ; 24-bit linear congruential PRNG. |
| ; Advances a 3-byte state (rng_state_lo/mid/hi) using additive constants |
| ; $45, $72, $BD with inter-byte feedback. Returns result in A (= rng_state_hi). |
| ; |
| ; Inputs: rng_state_lo, rng_state_mid, rng_state_hi |
| ; Outputs: A = new rng_state_hi, all three state bytes updated |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| $27E0 | a5 2c | prng_nextldazp_rng_state_lo; x-ref: $2C5A, $2C78, $2CAC, $2CB6, $2CCD |
| $27E2 | 18 | clc |
| $27E3 | 69 45 | adc#$45 |
| $27E5 | 85 2c | stazp_rng_state_lo |
| $27E7 | a5 2d | ldazp_rng_state_mid |
| $27E9 | 69 72 | adc#$72 |
| $27EB | 65 2c | adczp_rng_state_lo |
| $27ED | 85 2d | stazp_rng_state_mid |
| $27EF | a5 2e | ldazp_rng_state_hi |
| $27F1 | 69 bd | adc#$bd |
| $27F3 | 65 2d | adczp_rng_state_mid |
| $27F5 | 85 2e | stazp_rng_state_hi |
| $27F7 | 60 | rts |
| $27F8 | | .byte$00, $00, $00, $00 |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| ; Obstacle life ticker - per-frame lifetime countdown for all 4 obstacle slots. |
| ; Decrements obstacle_life[X] for each active slot. When life underflows |
| ; to $FC, marks the slot dead (obstacle_flags = $FF). |
| ; Also increments spawn_cooldown each call, pacing new obstacle spawns. |
| ; |
| ; Always called in pairs during non-riding phases (gate, debris wait, scroll) |
| ; to age obstacles at double speed, clearing the screen faster. |
| ; |
| ; Inputs: obstacle_flags[0..3], obstacle_life[0..3], spawn_cooldown |
| ; Outputs: obstacle_life (decremented), obstacle_flags ($FF on expiry), |
| ; spawn_cooldown (incremented) |
| ; Side Effects: None |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| $27FC | a2 03 | obstacle_life_tickldx#$03; 4 obstacle slots (X=3..0) ; x-ref: $2501, $251A, $2818, $281B, $28A5, $28A8 |
| $27FE | b5 10 | b_27FEldazp_obstacle_flags,x; x-ref: $2811 |
| $2800 | c9 ff | cmp#$ff; dead slot ($FF)? -> skip |
| $2802 | f0 0c | beqb_2810 |
| $2804 | d6 14 | deczp_obstacle_life,x; decrement lifetime counter |
| $2806 | b5 14 | ldazp_obstacle_life,x |
| $2808 | c9 fc | cmp#$fc; underflowed to $FC? -> expired |
| $280A | d0 04 | bneb_2810 |
| $280C | a9 ff | lda#$ff; kill slot: mark dead ($FF) |
| $280E | 95 10 | stazp_obstacle_flags,x |
| $2810 | ca | b_2810dex; x-ref: $2802, $280A |
| $2811 | 10 eb | bplb_27FE |
| $2813 | e6 2b | inczp_spawn_cooldown; advance spawn cooldown timer |
| $2815 | 60 | rts |
| $2816 | | .byte$00, $00 |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| ; Starting gate throttle decay - per-frame handler during gate phase (mode 3). |
| ; Ages obstacle timers at double speed (s27FC x2), then decays bike_throttle |
| ; by 4 per frame (rounded to multiples of 4 via AND #$FC). |
| ; When throttle reaches zero, transitions to track scroll mode (mode 4) |
| ; via s269C. |
| ; |
| ; Inputs: bike_throttle, obstacle timers (via s27FC) |
| ; Outputs: bike_throttle (decreased by 4, clamped to mult of 4) |
| ; Side Effects: s27FC x2 (obstacle aging), s269C (mode 4 transition on zero) |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| starting_gate_throttle_decay |
| $2818 | 20 fc 27 | jsrobstacle_life_tick; age obstacle timers at double speed ; x-ref: $2EC1 |
| $281B | 20 fc 27 | jsrobstacle_life_tick |
| $281E | a5 2a | ldazp_bike_throttle |
| $2820 | c9 00 | cmp#$00; throttle already zero? |
| $2822 | f0 08 | beqb_282C; yes -> transition to track scroll mode |
| $2824 | 38 | sec |
| $2825 | e9 04 | sbc#$04; decay throttle by 4 per frame |
| $2827 | 29 fc | and#$fc; round down to nearest 4 (clear low 2 bits) |
| $2829 | 85 2a | stazp_bike_throttle |
| $282B | 60 | rts |
| $282C | 20 9c 26 | b_282Cjsrenter_mode_track_scroll; throttle zero: set game_mode=4 (track scroll) ; x-ref: $2822 |
| $282F | 60 | rts |
| $2830 | | .byte$00, $00, $00, $00 |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| ; Game mode 4: Track scrolling phase - advances track_progress each tick with |
| ; a matching engine pitch sound, handles the end-of-scroll stop, and runs the |
| ; finish-line digit countdown animation. |
| ; |
| ; Three phases based on track_progress: |
| ; != $A0 (scrolling): call s2BF4 to increment progress and update engine sound. |
| ; When progress hits $E0: stop bike (game_mode=2), reset position, clear |
| ; track display buffers (s2A2C). |
| ; == $A0 (finish anim): animate digit counters on screen RAM at $0D0D-$0D0F |
| ; and $0D5D-$0D5F (PETSCII cycling). When done, advance course_index |
| ; and load next course layout (s2A18). |
| ; |
| ; Inputs: track_progress, snd_pitch, course_index, |
| ; screen RAM $0D0D-$0D0F and $0D5D-$0D5F |
| ; Outputs: track_progress, course_index, game_mode, bike_throttle, |
| ; bike_pos_hi/lo, bike_vel, snd_pitch/delta/duration/volume, |
| ; screen RAM (digit counters and track buffers) |
| ; Side Effects: Screen buffer clear (s2A2C), next-course load (s2A18), |
| ; scroll tile update (s29B4) |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| handle_mode_track_scroll |
| $2834 | a5 36 | ldazp_track_progress; x-ref: $2603 |
| $2836 | c9 a0 | cmp#$a0; finish-line animation phase? |
| $2838 | f0 13 | beqb_284D; yes -> run digit countdown animation |
| $283A | 20 f4 2b | jsradvance_progress_and_engine_sfx; advance track_progress + update engine pitch sound |
| $283D | ea | nop |
| $283E | c9 e0 | cmp#$e0; has scroll reached end-of-course? |
| $2840 | d0 0a | bner_284C; no -> keep scrolling |
| $2842 | 20 84 26 | jsrstop_bike_and_reset; stop bike: zero pos/vel, set game_mode=2, pin bike to left edge |
| $2845 | a9 60 | lda#$60 |
| $2847 | 85 2a | stazp_bike_throttle; set throttle to $60 (mid) |
| $2849 | 20 2c 2a | jsrclear_track_buffers; clear track display buffers ($0C50 and $0D50, 256 bytes each) |
| $284C | 60 | r_284Crts; x-ref: $2840 |
| $284D | a2 02 | b_284Dldx#$02; animate 3 digit chars at $0D0D-$0D0F (top row) ; x-ref: $2838 |
| $284F | de 0d 0d | b_284FdecSCREEN_RAM_R6C29,x; decrement digit char value ; x-ref: $285F |
| $2852 | bd 0d 0d | ldaSCREEN_RAM_R6C29,x |
| $2855 | c9 51 | cmp#$51; wrapped past $51? (digit cycle point) |
| $2857 | d0 36 | bneb_288F; not wrapped -> scroll update and return |
| $2859 | a9 5b | lda#$5b; wrap char back to $5B (animation cycle) |
| $285B | 9d 0d 0d | staSCREEN_RAM_R6C29,x |
| $285E | ca | dex |
| $285F | 10 ee | bplb_284F |
| $2861 | a9 52 | lda#$52; reset top row digits to $52 when animation completes |
| $2863 | 8d 0d 0d | staSCREEN_RAM_R6C29 |
| $2866 | 8d 0e 0d | staSCREEN_RAM_R6C30 |
| $2869 | 8d 0f 0d | staSCREEN_RAM_R6C31 |
| $286C | a2 02 | ldx#$02 |
| $286E | de 5d 0d | b_286EdecSCREEN_RAM_R8C29,x; decrement digit char value (bottom row) ; x-ref: $287E |
| $2871 | bd 5d 0d | ldaSCREEN_RAM_R8C29,x |
| $2874 | c9 51 | cmp#$51; wrapped past $51? (digit cycle point) |
| $2876 | d0 17 | bneb_288F; not wrapped -> scroll update and return |
| $2878 | a9 5b | lda#$5b; wrap char back to $5B (animation cycle) |
| $287A | 9d 5d 0d | staSCREEN_RAM_R8C29,x |
| $287D | ca | dex |
| $287E | 10 ee | bplb_286E |
| $2880 | a9 52 | lda#$52; reset bottom row digits to $52 when animation completes |
| $2882 | 8d 5d 0d | staSCREEN_RAM_R8C29 |
| $2885 | 8d 5e 0d | staSCREEN_RAM_R8C30 |
| $2888 | 8d 5f 0d | staSCREEN_RAM_R8C31 |
| $288B | 20 18 2a | jsradvance_course_layout; both rows done: inc progress, advance course, load next layout |
| $288E | 60 | rts |
| $288F | 20 b4 29 | b_288Fjsrupdate_scroll_tiles; animation still running: update scroll tile positions ; x-ref: $2857, $2876 |
| $2892 | 60 | rts |
| $2893 | 00 | .byte$00 |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| ; Game mode 5: Debris wait / lap-end transition. |
| ; Waits for all 8 crash_debris_y slots to read $FF (inactive). While waiting, |
| ; returns immediately each tick. Once all debris is clear, advances |
| ; track_progress each tick (aging obstacles via s27FC x2). When progress |
| ; reaches $A0 the lap outcome is resolved: |
| ; - Laps remain (lives_counter > 0): throttle=$60, game_mode=8 (next lap). |
| ; - No laps left (lives_counter = 0): set up course-end screen, game_mode=6. |
| ; Special case: if track_progress == 0 when debris clears, lives_counter is |
| ; decremented first (counts the completed lap before deciding the outcome). |
| ; |
| ; Inputs: crash_debris_y[0..7], track_progress, lives_counter, |
| ; obstacle_life[], obstacle_flags[] |
| ; Outputs: track_progress, lives_counter, game_mode, bike_throttle, |
| ; obstacle_flags[], spawn_cooldown, screen RAM $0D4E, color RAM $094E |
| ; Side Effects: Course-end screen setup (s26CC), next-lap start (s26F8) |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| handle_mode_debris_wait |
| $2894 | a2 07 | ldx#$07; x-ref: $2606 |
| $2896 | b5 48 | b_2896ldazp_crash_debris_y,x; check debris slot X: $FF = inactive ; x-ref: $289D |
| $2898 | c9 ff | cmp#$ff |
| $289A | d0 20 | bner_28BC; slot still active -> wait, exit immediately |
| $289C | ca | dex |
| $289D | 10 f7 | bplb_2896 |
| $289F | a5 36 | ldazp_track_progress; all 8 slots clear; check if this is a fresh lap (progress==0) |
| $28A1 | d0 02 | bneb_28A5; progress != 0 -> skip lap count decrement |
| $28A3 | c6 30 | deczp_lives_counter; progress==0: count this lap as done |
| $28A5 | 20 fc 27 | b_28A5jsrobstacle_life_tick; age obstacle timers (run twice for double speed decay) ; x-ref: $28A1 |
| $28A8 | 20 fc 27 | jsrobstacle_life_tick; second obstacle aging pass |
| $28AB | e6 36 | inczp_track_progress; advance progress toward lap-end threshold ($A0) |
| $28AD | a5 36 | ldazp_track_progress |
| $28AF | c9 a0 | cmp#$a0; reached lap-end threshold? |
| $28B1 | d0 09 | bner_28BC; not yet -> keep counting |
| $28B3 | a5 30 | ldazp_lives_counter; progress=$A0: any laps left? |
| $28B5 | c9 00 | cmp#$00 |
| $28B7 | f0 04 | beqb_28BD; no laps left -> course end |
| $28B9 | 20 f8 26 | jsrenter_mode_next_lap; laps remain: throttle=$60, game_mode=8 (start next lap) |
| $28BC | 60 | r_28BCrts; x-ref: $289A, $28B1 |
| $28BD | 20 cc 26 | b_28BDjsrsetup_course_end_screen; no laps: load course-end screen, game_mode=6, clear obstacles ; x-ref: $28B7 |
| $28C0 | 60 | rts |
| $28C1 | | .byte$00, $00, $00 |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| ; Game mode 6: Course-end results screen - plays a descending pitch sweep |
| ; sound over ~$D0 ticks as track_progress counts from 0 to $F0. |
| ; Each tick: progress is incremented, a sound note is computed from the |
| ; current progress value (lower 5 bits set pitch offset, bits 5-6 set |
| ; octave), combined, offset by $20, then inverted (EOR $FF) so the pitch |
| ; descends as progress increases. Duration=1 tick, volume=$30. |
| ; First ~32 ticks ($00-$20): BMI skips sound (silent lead-in). |
| ; When track_progress reaches $F0: calls reset_basic_runtime_state and |
| ; returns, ending the results screen and handing control back to menu/title. |
| ; |
| ; Inputs: track_progress (set to 0 by s26CC on entry to this mode) |
| ; Outputs: track_progress, snd_pitch, snd_pitch_delta, snd_duration, |
| ; snd_volume, ted_ctrl_staging |
| ; Side Effects: Calls reset_basic_runtime_state when sequence completes |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| handle_mode_results_screen |
| $28C4 | e6 36 | inczp_track_progress; advance results sequence timer ; x-ref: $2609 |
| $28C6 | a5 36 | ldazp_track_progress |
| $28C8 | c9 f0 | cmp#$f0; sequence complete ($F0 ticks)? |
| $28CA | d0 04 | bneb_28D0; not done -> compute sound pitch |
| $28CC | 20 14 26 | jsrreset_basic_runtime_state; done: wipe BASIC ZP state, return to menu |
| $28CF | 60 | rts |
| $28D0 | 38 | b_28D0sec; x-ref: $28CA |
| $28D1 | e9 20 | sbc#$20; offset from $20 baseline |
| $28D3 | 30 1f | bmir_28F4; progress < $21 -> silent lead-in, skip sound |
| $28D5 | 48 | pha |
| $28D6 | 29 1f | and#$1f; lower 5 bits -> pitch offset |
| $28D8 | 0a | asla; double for note spacing |
| $28D9 | 85 f8 | stazp_ted_ctrl_staging |
| $28DB | 68 | pla |
| $28DC | 29 60 | and#$60; bits 5-6 -> octave/range selector |
| $28DE | 18 | clc |
| $28DF | 65 f8 | adczp_ted_ctrl_staging |
| $28E1 | 18 | clc |
| $28E2 | 69 20 | adc#$20 |
| $28E4 | 49 ff | eor#$ff; invert -> descending pitch as progress increases |
| $28E6 | 85 50 | stazp_snd_pitch |
| $28E8 | a9 00 | lda#$00 |
| $28EA | 85 51 | stazp_snd_pitch_delta; no pitch slide between notes |
| $28EC | a9 01 | lda#$01; single-tick note duration |
| $28EE | 85 54 | stazp_snd_duration |
| $28F0 | a9 30 | lda#$30; fixed volume for results jingle |
| $28F2 | 85 55 | stazp_snd_volume |
| $28F4 | 60 | r_28F4rts; x-ref: $28D3 |
| $28F5 | | .byte$00, $00, $00 |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| ; Core bike physics: velocity correction + 16-bit position integration. |
| ; Reads throttle input (via s2E6C -> s2E44), biases velocity rightward (+2), |
| ; clamps positive velocity to $60, then integrates velocity into bike_pos |
| ; four times (effective displacement = 4 * bike_vel per call). |
| ; After integration, checks track boundaries: |
| ; - Within bounds: return cleanly. |
| ; - Out of bounds + track_flags bit 7 set: full crash (s26AC, debris). |
| ; - Out of bounds + track_flags bit 7 clear: soft recovery (s2684, |
| ; zero vel, game_mode=2, pin to left edge). |
| ; |
| ; Inputs: joystick_state (via s2E44), bike_vel, bike_pos_hi/lo, |
| ; bike_throttle, track_right_edge, track_left_edge, track_flags |
| ; Outputs: bike_vel (biased + clamped), bike_pos_hi/lo (integrated), |
| ; bike_throttle (via s2E44) |
| ; Side Effects: May trigger crash (s26AC) or soft recovery (s2684) |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| apply_velocity_and_integrate |
| $28F8 | 20 6c 2e | jsrupdate_throttle_and_load_vel; read throttle input + load bike_vel with CLC ; x-ref: $260C, $2EBE |
| $28FB | 69 02 | adc#$02; bias velocity rightward (+2 correction) |
| $28FD | 85 29 | stazp_bike_vel |
| $28FF | 30 08 | bmib_2909; negative velocity -> skip cap (allow leftward) |
| $2901 | c9 60 | cmp#$60; positive vel > $60? |
| $2903 | 90 04 | bccb_2909 |
| $2905 | a9 60 | lda#$60; clamp to max rightward velocity $60 |
| $2907 | 85 29 | stazp_bike_vel |
| $2909 | a2 03 | b_2909ldx#$03; integrate velocity into position 4 times (X=3..0) ; x-ref: $28FF, $2903 |
| $290B | a5 29 | b_290Bldazp_bike_vel; x-ref: $291F |
| $290D | 10 02 | bplb_2911; positive vel -> skip hi pre-decrement |
| $290F | c6 27 | deczp_bike_pos_x_hi; negative vel: sign-extend by pre-decrementing hi byte |
| $2911 | a5 28 | b_2911ldazp_bike_pos_x_lo; x-ref: $290D |
| $2913 | 18 | clc |
| $2914 | 65 29 | adczp_bike_vel; pos_lo += vel (16-bit add: carry propagates to hi) |
| $2916 | 85 28 | stazp_bike_pos_x_lo |
| $2918 | a5 27 | ldazp_bike_pos_x_hi |
| $291A | 69 00 | adc#$00 |
| $291C | 85 27 | stazp_bike_pos_x_hi |
| $291E | ca | dex |
| $291F | 10 ea | bplb_290B; repeat 4x -> effective displacement = 4 * vel |
| $2921 | a5 39 | ldazp_track_right_edge; bounds check: is bike past right edge? |
| $2923 | c5 27 | cmpzp_bike_pos_x_hi |
| $2925 | 90 06 | bccb_292D; past right -> out of bounds |
| $2927 | a5 37 | ldazp_track_left_edge; bounds check: is bike past left edge? |
| $2929 | c5 27 | cmpzp_bike_pos_x_hi |
| $292B | b0 0d | bcsr_293A; within bounds -> return cleanly |
| $292D | a5 38 | b_292Dldazp_track_flags; x-ref: $2925 |
| $292F | 29 80 | and#$80; bit 7 = crash-enabled for this track segment? |
| $2931 | f0 04 | beqb_2937; crash disabled -> soft recovery |
| $2933 | 20 ac 26 | jsrtrigger_crash; crash enabled: full crash with debris explosion |
| $2936 | 60 | rts |
| $2937 | 20 84 26 | b_2937jsrstop_bike_and_reset; soft recovery: zero vel, game_mode=2, pin to left edge ; x-ref: $2931 |
| $293A | 60 | r_293Arts; x-ref: $292B |
| $293B | | .byte$00 |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| ; Negates the velocity of obstacle slot X (two's-complement bounce). |
| ; Called when an obstacle crosses the upper ($30) or lower ($10) track |
| ; boundary - flips its direction so it bounces back inside the playfield. |
| ; |
| ; Inputs: X = obstacle slot index; obstacle_vel,x = current velocity |
| ; Outputs: obstacle_vel,x = negated velocity (direction reversed) |
| ; Side Effects: None |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| $293C | b5 20 | negate_obstacle_velldazp_obstacle_vel,x; x-ref: $2551 |
| $293E | 49 ff | eor#$ff; one's complement (invert all bits) |
| $2940 | 18 | clc |
| $2941 | 69 01 | adc#$01; +1 -> two's complement negation complete |
| $2943 | 95 20 | stazp_obstacle_vel,x |
| $2945 | 60 | rts |
| $2946 | | .byte$00, $00 |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| ; Game mode 8: Next-lap initialization wait. |
| ; Polls the object record status byte at offset $10 each tick. When bits 6-7 |
| ; are set (signaling screen/scroll readiness), resets the bike to the left |
| ; track edge with neutral throttle ($60), zeroes velocity and position lo, |
| ; initializes the lap-start debris animation from f1CD0, and transitions |
| ; to game_mode=1 (crash debris / lap-start animation). |
| ; Until the readiness bits are set, returns immediately (wait state). |
| ; |
| ; Inputs: (ptr_obj_record_lo)+$10 (object record status), track_left_edge |
| ; Outputs: bike_throttle ($60), bike_pos_hi (left edge), bike_pos_lo (0), |
| ; bike_vel (0), game_mode (-> 1), spawn_cooldown (0), |
| ; crash_debris_x[0..15] (from f1CD0) |
| ; Side Effects: Calls s2BDC (sound/visual trigger), starts lap animation |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| handle_mode_next_lap_init |
| $2948 | a0 10 | ldy#$10; offset $10 into object record = status byte ; x-ref: $260F |
| $294A | b1 24 | lda(zp_ptr_obj_record_lo),y; read status byte from object record |
| $294C | 29 c0 | and#$c0; isolate readiness bits 6-7 |
| $294E | f0 11 | beqr_2961; not ready yet -> wait (return immediately) |
| $2950 | a9 60 | lda#$60; ready: set neutral throttle |
| $2952 | 85 2a | stazp_bike_throttle |
| $2954 | a9 00 | lda#$00 |
| $2956 | 85 28 | stazp_bike_pos_x_lo; zero position lo + velocity |
| $2958 | 85 29 | stazp_bike_vel |
| $295A | a5 37 | ldazp_track_left_edge; pin bike to left track edge |
| $295C | 85 27 | stazp_bike_pos_x_hi |
| $295E | 20 6d 26 | jsrinit_lap_start_anim_no_kill; init debris from f1CD0, game_mode=1, spawn_cooldown=0 |
| $2961 | 60 | r_2961rts; x-ref: $294E |
| $2962 | | .byte$00, $00 |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| ; Initializes the end-of-course results/score screen. |
| ; 1. Copies 24-char score headings from f1CF0 ("bonus for time left") and |
| ; f1D08 ("bikes left bonus") to screen RAM $0CF8/$0D48; fills colour |
| ; RAM $08F8/$0948 with $71 (standard score colour). |
| ; 2. Converts position values $0C07/$0C08/$0C0A into score display chars |
| ; (+$47) and writes to screen cells $0D0D/$0D0E/$0D0F. |
| ; 3. Looks up two per-lap bonus digit chars from f1D38/f1D40[lives_counter] |
| ; and writes to $0D5E/$0D5F. |
| ; 4. Calls s2A4A: awards an extra bike (increments lives_counter, shows |
| ; f1D48 "extra bike awarded" banner at $0D98) if course_index < $10 |
| ; and lives_counter != 5; otherwise shows f1D60 text. |
| ; 5. Clears track_progress. |
| ; |
| ; Inputs: $0C07/$0C08/$0C0A (score values), lives_counter, course_index |
| ; Outputs: Screen/colour RAM score display populated, track_progress=0, |
| ; lives_counter possibly incremented (via s2A4A) |
| ; Side Effects: Calls s2A4A (extra bike award + banner display) |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| $2964 | a2 17 | init_score_screenldx#$17; copy 24-char score headings from f1CF0/f1D08, colour $71 ; x-ref: $26A4 |
| $2966 | bd f0 1c | b_2966ldatime_bonus_text,x; "bonus for time left" heading -> screen RAM $0CF8 ; x-ref: $297D |
| $2969 | 9d f8 0c | staSCREEN_RAM_R6C8,x |
| $296C | bd 08 1d | ldabikes_left_bonus_text,x; "bikes left bonus" heading -> screen RAM $0D48 |
| $296F | 9d 48 0d | staSCREEN_RAM_R8C8,x |
| $2972 | a9 71 | lda#$71; $71 = standard score-screen colour -> colour RAM $08F8 and $0948 |
| $2974 | 9d f8 08 | staCOLOR_RAM_R6C8,x |
| $2977 | a9 71 | lda#$71 |
| $2979 | 9d 48 09 | staCOLOR_RAM_R8C8,x |
| $297C | ca | dex |
| $297D | 10 e7 | bplb_2966 |
| $297F | ea | nop |
| $2980 | ea | nop |
| $2981 | ad 07 0c | ldaSCREEN_RAM_R0C7; convert position values to score chars (+$47) -> $0D0D/$0D0E/$0D0F |
| $2984 | 18 | clc |
| $2985 | 69 47 | adc#$47 |
| $2987 | 8d 0d 0d | staSCREEN_RAM_R6C29 |
| $298A | ad 08 0c | ldaSCREEN_RAM_R0C8 |
| $298D | 18 | clc |
| $298E | 69 47 | adc#$47 |
| $2990 | 8d 0e 0d | staSCREEN_RAM_R6C30 |
| $2993 | ad 0a 0c | ldaSCREEN_RAM_R0C10 |
| $2996 | 18 | clc |
| $2997 | 69 47 | adc#$47 |
| $2999 | 8d 0f 0d | staSCREEN_RAM_R6C31 |
| $299C | a6 30 | ldxzp_lives_counter; per-lap bonus digits from f1D38/f1D40[lives_counter] -> $0D5E/$0D5F |
| $299E | bd 38 1d | ldabonus_value_char1,x |
| $29A1 | 8d 5e 0d | staSCREEN_RAM_R8C30 |
| $29A4 | bd 40 1d | ldabonus_value_char2,x |
| $29A7 | 8d 5f 0d | staSCREEN_RAM_R8C31 |
| $29AA | 20 4a 2a | jsraward_extra_bike; award extra bike + show banner if eligible, fill $0D98 score row |
| $29AD | a9 00 | lda#$00 |
| $29AF | 85 36 | stazp_track_progress |
| $29B1 | 60 | rts |
| $29B2 | | .byte$00, $00 |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| ; Per-frame track scroll tile position updater. |
| ; Looks up the number of increment steps for the current course from |
| ; f1E10[course_index & $0F] (1-5 steps; higher courses scroll faster) and |
| ; calls s29C8 that many times. Each call increments 7 tile position pairs |
| ; ($0C13,x / $0C3B,x for X=6..0), wrapping at $15 back to $0B/$1F. |
| ; Then calls s2BBC to tick the scroll sound effect: if snd_duration==0, |
| ; picks a pitch from (frame_counter & $07)*4 + $A0, sets duration=3, |
| ; volume=$10 (pitch delta $30). |
| ; Called every frame from handle_mode_debris_wait while animation runs. |
| ; |
| ; Inputs: course_index (scroll speed), $0C13,x/$0C3B,x (7 tile pairs), |
| ; snd_duration, frame_counter |
| ; Outputs: $0C13,x/$0C3B,x updated (wrapped at $15->$0B/$1F), |
| ; snd_pitch/snd_duration/snd_volume possibly updated |
| ; Side Effects: Scroll sound tick via s2BBC |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| $29B4 | a5 2f | update_scroll_tilesldazp_course_index; speed = f1E10[course & $0F]: 1-5 steps/frame (faster on later courses) ; x-ref: $288F |
| $29B6 | 29 0f | and#$0f |
| $29B8 | aa | tax |
| $29B9 | bd 10 1e | ldacourse_scroll_steps,x; Y = step count for this course |
| $29BC | a8 | tay |
| $29BD | 20 c8 29 | jsrtick_scroll_tiles; increment tile positions Y times (s29C8 loops X=6..0, wraps at $15->$0B) |
| $29C0 | 20 bc 2b | jsrsfx_scroll_rumble; tick scroll sound effect |
| $29C3 | 60 | rts |
| $29C4 | | .byte$00, $00, $00, $00 |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| ; Core single-step scroll tile engine. Advances 7 tile position pairs by |
| ; one step (called Y times by update_scroll_tiles for variable speed). |
| ; |
| ; Phase 1 - Increment (X=6..0): |
| ; Increments $0C13,x (tile A) and $0C3B,x (tile B) for each of 7 pairs. |
| ; When $0C13,x reaches $15 (wrap point): resets A to $0B, B to $1F, then |
| ; exits the inner DEX loop early (staggered-wrap design: only the wrapping |
| ; slot is reset on that step). DEY re-enters from the top for remaining Y |
| ; steps. |
| ; |
| ; Phase 2 - Best-position update (X=0..6): |
| ; Scans all 7 pairs: if any current position > stored best ($0C20,x / |
| ; $0C48,x) then copies all 7 current pairs to the best tables. If all |
| ; are equal, returns without update. If any is below best, returns. |
| ; Tracks the furthest scroll position reached (high-scroll record). |
| ; |
| ; Inputs: Y = step count; $0C13,x/$0C3B,x (7 current tile pairs); |
| ; $0C20,x/$0C48,x (7 best-position pairs) |
| ; Outputs: $0C13,x/$0C3B,x incremented/wrapped; $0C20,x/$0C48,x updated |
| ; if new positions set a new best |
| ; Side Effects: None |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| $29C8 | a2 06 | tick_scroll_tilesldx#$06; --- Phase 1: increment 7 tile pairs (X=6..0) --- ; x-ref: $29BD, $29E5, $2A14 |
| $29CA | fe 13 0c | b_29CAincSCREEN_RAM_R0C19,x; increment tile A and tile B for pair X ; x-ref: $29E2, $2D81 |
| $29CD | fe 3b 0c | incSCREEN_RAM_R1C19,x |
| $29D0 | bd 13 0c | ldaSCREEN_RAM_R0C19,x |
| $29D3 | c9 15 | cmp#$15; reached wrap point ($15)? |
| $29D5 | d0 0d | bneb_29E4 |
| $29D7 | a9 0b | lda#$0b; wrap: reset A=$0B, B=$1F; exit inner loop (staggered wrap) |
| $29D9 | 9d 13 0c | staSCREEN_RAM_R0C19,x |
| $29DC | a9 1f | lda#$1f |
| $29DE | 9d 3b 0c | staSCREEN_RAM_R1C19,x |
| $29E1 | ca | dex |
| $29E2 | 10 e6 | bplb_29CA |
| $29E4 | 88 | b_29E4dey; decrement Y step counter; loop back if more steps remain ; x-ref: $29D5 |
| $29E5 | d0 e1 | bnetick_scroll_tiles |
| $29E7 | a2 00 | ldx#$00; --- Phase 2: check if new positions beat the stored best --- |
| $29E9 | bd 13 0c | b_29E9ldaSCREEN_RAM_R0C19,x; compare current vs best; below -> no update, above -> copy all ; x-ref: $29F6 |
| $29EC | dd 20 0c | cmpSCREEN_RAM_R0C32,x |
| $29EF | 90 07 | bccr_29F8 |
| $29F1 | d0 06 | bneb_29F9 |
| $29F3 | e8 | inx |
| $29F4 | e0 07 | cpx#$07 |
| $29F6 | d0 f1 | bneb_29E9 |
| $29F8 | 60 | r_29F8rts; x-ref: $29EF |
| $29F9 | a2 06 | b_29F9ldx#$06; new best: copy all 7 current pairs to best tables $0C20/$0C48 ; x-ref: $29F1 |
| $29FB | bd 13 0c | b_29FBldaSCREEN_RAM_R0C19,x; x-ref: $2A08 |
| $29FE | 9d 20 0c | staSCREEN_RAM_R0C32,x |
| $2A01 | bd 3b 0c | ldaSCREEN_RAM_R1C19,x |
| $2A04 | 9d 48 0c | staSCREEN_RAM_R1C32,x |
| $2A07 | ca | dex |
| $2A08 | 10 f1 | bplb_29FB |
| $2A0A | 60 | rts |
| $2A0B | | .byte$00 |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| ; Single-step scroll tile tick, gated on game mode. |
| ; If game_mode != 0 (not normal-ride mode), calls tick_scroll_tiles with |
| ; Y=1 to advance all 7 tile pairs by one step. If game_mode == 0, returns |
| ; immediately without updating tiles. |
| ; |
| ; Inputs: game_mode, $0C13,x/$0C3B,x (7 tile pairs) |
| ; Outputs: $0C13,x/$0C3B,x possibly incremented (if game_mode != 0) |
| ; Side Effects: None |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| tick_scroll_tiles_if_active |
| $2A0C | a5 02 | ldazp_game_mode; skip tile tick if game_mode == 0 (normal-ride mode) ; x-ref: $24EE |
| $2A0E | c9 00 | cmp#GameMode.NORMAL_RIDE |
| $2A10 | f0 05 | beqr_2A17 |
| $2A12 | a0 01 | ldy#$01; Y=1: single-step tick |
| $2A14 | 20 c8 29 | jsrtick_scroll_tiles |
| $2A17 | 60 | r_2A17rts; x-ref: $2A10 |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| ; Advances the game's track progress and loads parameters for the next layout. |
| ; Increments the overall track_progress and the course_index (wrapping at 16). |
| ; Looks up the animation frame count from course_anim_frames and delegates to |
| ; store_course_params to update the scroll and animation state. |
| ; |
| ; Inputs: track_progress, course_index |
| ; Outputs: track_progress, course_index, anim_frame_count, scroll_speed |
| ; Side Effects: None |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| advance_course_layout |
| $2A18 | e6 36 | inczp_track_progress; x-ref: $288B |
| $2A1A | e6 2f | inczp_course_index |
| $2A1C | a5 2f | ldazp_course_index; wrap to 0-15 (16 courses total) |
| $2A1E | 29 0f | and#$0f |
| $2A20 | aa | tax |
| $2A21 | bd 70 1e | ldacourse_anim_frames,x; lookup anim_frame_count for new course |
| $2A24 | 20 a8 2d | jsrstore_course_params; update anim_frame_count and scroll_speed |
| $2A27 | 60 | rts |
| $2A28 | | .byte$00, $00, $00, $00 |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| ; Clears two 256-byte track display buffers by filling them with $00. |
| ; Buffer 1: $0C50-$0D4F. Buffer 2: $0D50-$0E4F. |
| ; Used to wipe the track tile/scroll state before loading a new course. |
| ; |
| ; Inputs: None |
| ; Outputs: $0C50-$0D4F = 0, $0D50-$0E4F = 0 |
| ; Side Effects: None |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| $2A2C | a2 00 | clear_track_buffersldx#$00; zero-fill $0C50-$0D4F and $0D50-$0E4F (256 bytes each) ; x-ref: $2849, $2A3A |
| $2A2E | a9 00 | lda#$00 |
| $2A30 | 9d 50 0c | b_2A30staSCREEN_RAM_R2C0,x; x-ref: $2A37 |
| $2A33 | 9d 50 0d | staSCREEN_RAM_R8C16,x |
| $2A36 | e8 | inx |
| $2A37 | d0 f7 | bneb_2A30 |
| $2A39 | 60 | rts |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| ; Clears track display buffers (via clear_track_buffers), then loads |
| ; per-course animation and scroll parameters from lookup tables: |
| ; anim_frame_count = f1E70[course_index] |
| ; scroll_speed = f1DE0[course_index] |
| ; Called from init_course_state to prepare a new course for play. |
| ; |
| ; Inputs: course_index |
| ; Outputs: $0C50-$0E4F cleared, anim_frame_count, scroll_speed loaded |
| ; Side Effects: None |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| clear_track_and_load_course |
| $2A3A | 20 2c 2a | jsrclear_track_buffers; clear both track display buffers ; x-ref: $2659 |
| $2A3D | a6 2f | ldxzp_course_index; load anim_frame_count and scroll_speed for current course |
| $2A3F | bd 70 1e | ldacourse_anim_frames,x |
| $2A42 | 85 3c | stazp_anim_frame_count |
| $2A44 | bd e0 1d | ldacourse_scroll_speeds,x |
| $2A47 | 85 53 | stazp_scroll_speed |
| $2A49 | 60 | rts |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| ; Awards an extra bike and displays the appropriate score-screen banner. |
| ; Three paths: |
| ; 1. lives_counter == 5 (max bikes): shows f1D60 "five bikes left still" |
| ; 2. course_index >= $10 (past last course): no banner, footer only |
| ; 3. Otherwise: increments lives_counter (extra bike!) and shows f1D48 |
| ; "extra bike awarded" |
| ; All paths converge to fill the course speed footer: $78 at $0D39, |
| ; speed digit (f1E10[course & $0F] + $52) at $0D3A, colour $71. |
| ; Called from init_score_screen. |
| ; |
| ; Inputs: lives_counter (current bikes, max 5), course_index |
| ; Outputs: lives_counter possibly incremented, screen $0D98+ banner text, |
| ; colour $0998+ = $71, $0D39/$0D3A speed footer, $0939/$093A = $71 |
| ; Side Effects: None |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| $2A4A | a5 30 | award_extra_bikeldazp_lives_counter; max bikes (5)? -> show "five bikes left still" banner ; x-ref: $29AA |
| $2A4C | c9 05 | cmp#$05 |
| $2A4E | f0 20 | beqb_2A70 |
| $2A50 | a5 2f | ldazp_course_index; past last course ($10)? -> no extra bike, skip to footer |
| $2A52 | c9 10 | cmp#$10 |
| $2A54 | b0 2a | bcsb_2A80 |
| $2A56 | aa | tax |
| $2A57 | ea | nop |
| $2A58 | ea | nop |
| $2A59 | ea | nop |
| $2A5A | ea | nop |
| $2A5B | ea | nop |
| $2A5C | e6 30 | inczp_lives_counter; award extra bike! show "extra bike awarded" banner |
| $2A5E | a2 17 | ldx#$17 |
| $2A60 | bd 48 1d | b_2A60ldaextra_bike_awarded_text,x; x-ref: $2A6C |
| $2A63 | 9d 98 0d | staSCREEN_RAM_R10C8,x |
| $2A66 | a9 71 | lda#$71 |
| $2A68 | 9d 98 09 | staCOLOR_RAM_R10C8,x |
| $2A6B | ca | dex |
| $2A6C | 10 f2 | bplb_2A60 |
| $2A6E | 30 10 | bmib_2A80 |
| $2A70 | a2 17 | b_2A70ldx#$17; max-bikes path: show "five bikes left still" ; x-ref: $2A4E |
| $2A72 | bd 60 1d | b_2A72ldafive_bikes_left_text,x; x-ref: $2A7E |
| $2A75 | 9d 98 0d | staSCREEN_RAM_R10C8,x |
| $2A78 | a9 71 | lda#$71 |
| $2A7A | 9d 98 09 | staCOLOR_RAM_R10C8,x |
| $2A7D | ca | dex |
| $2A7E | 10 f2 | bplb_2A72 |
| $2A80 | a9 78 | b_2A80lda#$78; --- Footer: course speed label + digit --- ; x-ref: $2A54, $2A6E |
| $2A82 | 8d 39 0d | staSCREEN_RAM_R7C33 |
| $2A85 | a5 2f | ldazp_course_index; speed digit = f1E10[course & $0F] + $52 -> $0D3A |
| $2A87 | 29 0f | and#$0f |
| $2A89 | aa | tax |
| $2A8A | bd 10 1e | ldacourse_scroll_steps,x |
| $2A8D | 18 | clc |
| $2A8E | 69 52 | adc#$52 |
| $2A90 | 8d 3a 0d | staSCREEN_RAM_R7C34 |
| $2A93 | a9 71 | lda#$71 |
| $2A95 | 8d 39 09 | staCOLOR_RAM_R7C33 |
| $2A98 | 8d 3a 09 | staCOLOR_RAM_R7C34 |
| $2A9B | 60 | rts |
| $2A9C | | .byte$00, $00, $00, $00 |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| ; Music sequencer tick - advances the two-voice music playback each frame. |
| ; Each note lasts 6 frames (music_step counts 0-5). The full sequence is |
| ; 192 notes ($C0 entries in f1948) and loops endlessly. |
| ; |
| ; Each byte in f1948[music_pos] encodes two notes packed in nibbles: |
| ; High nibble -> Voice 2 (TED $FF0E/$FF12) via f1A08/f1A18 freq tables |
| ; Low nibble -> Voice 1 (TED $FF0F/$FF10) via f1A28/f1A38 freq tables |
| ; Both tables hold 16-entry frequency lo/hi pairs. |
| ; Control register $FF11 is set to $38 (both voices on, square wave). |
| ; |
| ; Called from the jump/airborne handler - this is the stunt/jump theme. |
| ; |
| ; Inputs: music_step (0-5 sub-step), music_pos (0-$BF sequence position) |
| ; Outputs: TED $FF0E-$FF12 (note frequencies + control), |
| ; music_step/music_pos advanced (loop at $C0) |
| ; Side Effects: Direct writes to Plus/4 TED hardware sound registers |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| $2AA0 | e6 34 | music_sequencer_tickinczp_music_step; advance sub-step (6 frames per note) ; x-ref: $2DB4 |
| $2AA2 | a5 34 | ldazp_music_step |
| $2AA4 | c9 06 | cmp#$06 |
| $2AA6 | d0 10 | bneb_2AB8 |
| $2AA8 | a9 00 | lda#$00 |
| $2AAA | 85 34 | stazp_music_step |
| $2AAC | e6 35 | inczp_music_pos; next note; loop at $C0 (192-note sequence) |
| $2AAE | a5 35 | ldazp_music_pos |
| $2AB0 | c9 c0 | cmp#$c0 |
| $2AB2 | d0 04 | bneb_2AB8 |
| $2AB4 | a9 00 | lda#$00 |
| $2AB6 | 85 35 | stazp_music_pos |
| $2AB8 | a6 35 | b_2AB8ldxzp_music_pos; --- Decode packed note byte from f1948[music_pos] --- ; x-ref: $2AA6, $2AB2 |
| $2ABA | bd 48 19 | ldamusic_packed_notes,x |
| $2ABD | 29 f0 | and#$f0; high nibble -> Voice 2 note index |
| $2ABF | 4a | lsra |
| $2AC0 | 4a | lsra |
| $2AC1 | 4a | lsra |
| $2AC2 | 4a | lsra |
| $2AC3 | a8 | tay |
| $2AC4 | b9 08 1a | ldavoice_2_freq_lo,y; Voice 2 freq lo/hi -> TED $FF0E/$FF12 |
| $2AC7 | 8d 0e ff | sta$ff0e |
| $2ACA | b9 18 1a | ldavoice_2_freq_hi,y |
| $2ACD | 8d 12 ff | sta$ff12 |
| $2AD0 | bd 48 19 | ldamusic_packed_notes,x |
| $2AD3 | 29 0f | and#$0f; low nibble -> Voice 1 note index |
| $2AD5 | a8 | tay |
| $2AD6 | b9 28 1a | ldavoice_1_freq_lo,y; Voice 1 freq lo/hi -> TED $FF0F/$FF10 |
| $2AD9 | 8d 0f ff | sta$ff0f |
| $2ADC | b9 38 1a | ldavoice_1_freq_hi,y |
| $2ADF | 8d 10 ff | sta$ff10 |
| $2AE2 | a9 38 | lda#$38; $38 = both voices on, square wave -> TED control $FF11 |
| $2AE4 | 8d 11 ff | sta$ff11 |
| $2AE7 | 60 | rts |
| $2AE8 | | .byte$00, $00, $00, $00 |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| ; Per-frame sound engine driver for the TED chip. Manages two sound channels: |
| ; |
| ; Voice 1 ($FF0F/$FF10): Pitched SFX notes. Frequency = snd_pitch << 2. |
| ; snd_pitch slides by snd_pitch_delta each frame. Duration-limited by |
| ; snd_duration (decremented each frame; voice silenced when it hits 0). |
| ; |
| ; Voice 2 ($FF0E/$FF12): Continuous engine noise. Frequency directly tracks |
| ; bike_throttle (faster throttle = higher pitch). |
| ; |
| ; Control register ($FF11) is assembled from: |
| ; - snd_volume (or $10 when silent) |
| ; - Bit 4: engine channel enable (cleared when throttle=0 or mode=8) |
| ; - Bits 2-3: alternate each frame (vibrato/distortion effect) |
| ; - Bit 3: set when throttle=0 (idle noise mode) |
| ; |
| ; Special: entire routine is skipped during game_mode=0 (silent init phase). |
| ; |
| ; Inputs: game_mode, snd_duration, snd_pitch, snd_pitch_delta, snd_volume, |
| ; bike_throttle, frame_counter |
| ; Outputs: TED $FF0E-$FF12, snd_duration (dec), snd_pitch (slid), |
| ; ted_ctrl_staging, pitch_hi |
| ; Side Effects: Directly writes TED hardware sound registers |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| $2AEC | a5 02 | sound_engine_tickldazp_game_mode; x-ref: $20EC |
| $2AEE | c9 00 | cmp#GameMode.NORMAL_RIDE; mode 0 = silent (skip all sound) |
| $2AF0 | d0 02 | bneb_2AF4 |
| $2AF2 | 60 | rts |
| $2AF3 | ea | nop |
| $2AF4 | a5 54 | b_2AF4ldazp_snd_duration; duration > 0? (active note playing) ; x-ref: $2AF0 |
| $2AF6 | f0 27 | beqb_2B1F; expired -> silence Voice 1 |
| $2AF8 | c6 54 | deczp_snd_duration |
| $2AFA | a5 50 | ldazp_snd_pitch |
| $2AFC | 18 | clc |
| $2AFD | 65 51 | adczp_snd_pitch_delta; pitch slide: pitch += delta each frame |
| $2AFF | 85 50 | stazp_snd_pitch |
| $2B01 | a5 50 | ldazp_snd_pitch |
| $2B03 | 85 f8 | stazp_ted_ctrl_staging |
| $2B05 | a9 00 | lda#$00 |
| $2B07 | 85 f9 | stazp_pitch_hi |
| $2B09 | 06 f8 | aslzp_ted_ctrl_staging; shift pitch left 2x -> 10-bit TED frequency |
| $2B0B | 26 f9 | rolzp_pitch_hi |
| $2B0D | 06 f8 | aslzp_ted_ctrl_staging |
| $2B0F | 26 f9 | rolzp_pitch_hi |
| $2B11 | a5 f8 | ldazp_ted_ctrl_staging |
| $2B13 | 8d 0f ff | sta$ff0f; TED Voice 1 frequency lo |
| $2B16 | a5 f9 | ldazp_pitch_hi |
| $2B18 | 8d 10 ff | sta$ff10; TED Voice 1 frequency hi (2 bits) |
| $2B1B | a5 55 | ldazp_snd_volume |
| $2B1D | d0 02 | bneb_2B21 |
| $2B1F | a9 10 | b_2B1Flda#$10; $10 = base control (sound off, bit 4 set as default) ; x-ref: $2AF6 |
| $2B21 | 85 f8 | b_2B21stazp_ted_ctrl_staging; x-ref: $2B1D |
| $2B23 | a5 2a | ldazp_bike_throttle |
| $2B25 | f0 06 | beqb_2B2D; throttle=0? -> mute engine channel |
| $2B27 | a5 02 | ldazp_game_mode |
| $2B29 | c9 08 | cmp#GameMode.NEXT_LAP_INIT; mode 8 (next lap init)? -> also mute engine |
| $2B2B | d0 06 | bneb_2B33 |
| $2B2D | a5 f8 | b_2B2Dldazp_ted_ctrl_staging; x-ref: $2B25 |
| $2B2F | 29 ef | and#$ef; clear bit 4: disable engine channel |
| $2B31 | 85 f8 | stazp_ted_ctrl_staging |
| $2B33 | a5 3f | b_2B33ldazp_frame_counter; frame alternation: bits 2-3 toggle each frame (vibrato) ; x-ref: $2B2B |
| $2B35 | 29 01 | and#$01 |
| $2B37 | 0a | asla |
| $2B38 | 0a | asla |
| $2B39 | 18 | clc |
| $2B3A | 69 04 | adc#$04 |
| $2B3C | 05 f8 | orazp_ted_ctrl_staging |
| $2B3E | 85 f8 | stazp_ted_ctrl_staging |
| $2B40 | a9 00 | lda#$00 |
| $2B42 | 8d 12 ff | sta$ff12; TED Voice 2 frequency hi = 0 |
| $2B45 | a5 2a | ldazp_bike_throttle |
| $2B47 | 8d 0e ff | sta$ff0e; Voice 2 freq lo = throttle (engine pitch tracks speed) |
| $2B4A | d0 06 | bneb_2B52 |
| $2B4C | a5 f8 | ldazp_ted_ctrl_staging |
| $2B4E | 09 08 | ora#$08; throttle=0: set bit 3 (noise/distortion for idle) |
| $2B50 | 85 f8 | stazp_ted_ctrl_staging |
| $2B52 | a5 f8 | b_2B52ldazp_ted_ctrl_staging; x-ref: $2B4A |
| $2B54 | 8d 11 ff | sta$ff11; write assembled control byte to TED sound control |
| $2B57 | 60 | rts |
| $2B58 | | .byte$00, $00, $00, $00 |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| ; Idle landing sound + velocity correction trigger. |
| ; Called when the bike lands without the fire button held (no jump). |
| ; Sets bike_vel to A (caller passes $CC), enters game_mode=7 (velocity |
| ; correction), and arms a high-pitched descending sound effect: |
| ; pitch=$E0, delta=$02 (slow slide), duration=15 frames, volume=$30. |
| ; |
| ; Inputs: A = landing velocity ($CC from caller) |
| ; Outputs: bike_vel=A, game_mode=7, snd_pitch=$E0, snd_pitch_delta=$02, |
| ; snd_duration=$0F, snd_volume=$30 |
| ; Side Effects: None (sound applied by sound_engine_tick on next frames) |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| $2B5C | 20 f0 26 | sfx_idle_landingjsrenter_mode_vel_correct; set vel=A, game_mode=7; arm idle landing sound ; x-ref: $27D7 |
| $2B5F | a9 0f | lda#$0f; dur=15, pitch=$E0, delta=$02 (slow descending), vol=$30 |
| $2B61 | 85 54 | stazp_snd_duration |
| $2B63 | a9 e0 | lda#$e0 |
| $2B65 | 85 50 | stazp_snd_pitch |
| $2B67 | a9 02 | lda#$02 |
| $2B69 | 85 51 | stazp_snd_pitch_delta |
| $2B6B | a9 30 | lda#$30 |
| $2B6D | 85 55 | stazp_snd_volume |
| $2B6F | 60 | rts |
| $2B70 | | .byte$00, $00, $00, $00 |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| ; Surface impact sound + velocity correction trigger. |
| ; Called when the bike hits a special surface (ramp/mud, track_flags bit 6). |
| ; Sets bike_vel to A (caller passes $A0), enters game_mode=7 (velocity |
| ; correction), and arms a lower-pitched fast-descending sound effect: |
| ; pitch=$A0, delta=$06 (fast slide), duration=15 frames, volume=$30. |
| ; |
| ; Inputs: A = surface impact velocity ($A0 from caller) |
| ; Outputs: bike_vel=A, game_mode=7, snd_pitch=$A0, snd_pitch_delta=$06, |
| ; snd_duration=$0F, snd_volume=$30 |
| ; Side Effects: None (sound applied by sound_engine_tick on next frames) |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| $2B74 | 20 f0 26 | sfx_surface_impactjsrenter_mode_vel_correct; set vel=A, game_mode=7; arm surface impact sound ; x-ref: $27CB |
| $2B77 | a9 0f | lda#$0f; dur=15, pitch=$A0, delta=$06 (fast descending), vol=$30 |
| $2B79 | 85 54 | stazp_snd_duration |
| $2B7B | a9 a0 | lda#$a0 |
| $2B7D | 85 50 | stazp_snd_pitch |
| $2B7F | a9 06 | lda#$06 |
| $2B81 | 85 51 | stazp_snd_pitch_delta |
| $2B83 | a9 30 | lda#$30 |
| $2B85 | 85 55 | stazp_snd_volume |
| $2B87 | 60 | rts |
| $2B88 | | .byte$00, $00, $00, $00 |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| ; Arms the crash explosion sound effect. |
| ; Sets up the loudest, longest, most dramatic sound in the game: |
| ; max pitch ($FF) sweeping down rapidly (delta=$FC) at high volume ($50) |
| ; for 48 frames ($30). Called from trigger_crash when the bike crashes. |
| ; |
| ; Inputs: None |
| ; Outputs: snd_pitch=$FF, snd_pitch_delta=$FC, snd_duration=$30, snd_volume=$50 |
| ; Side Effects: None (sound played by sound_engine_tick on subsequent frames) |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| $2B8C | a9 ff | sfx_crash_explosionlda#$ff; max pitch, fast sweep-down, long duration, loud - crash boom! ; x-ref: $26C7 |
| $2B8E | 85 50 | stazp_snd_pitch |
| $2B90 | a9 fc | lda#$fc |
| $2B92 | 85 51 | stazp_snd_pitch_delta |
| $2B94 | a9 30 | lda#$30 |
| $2B96 | 85 54 | stazp_snd_duration |
| $2B98 | a9 50 | lda#$50 |
| $2B9A | 85 55 | stazp_snd_volume |
| $2B9C | 60 | rts |
| $2B9D | | .byte$00, $00, $00 |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| ; Finish-line sound effect ticker (non-preemptive). |
| ; Only fires when snd_duration==0 (no sound already playing). Arms a short |
| ; 4-frame blip whose pitch is derived from anim_frame_count + $C0, |
| ; creating a dynamic tone that varies each lap. Called every frame from |
| ; check_finish_line at the end of the bike movement path. |
| ; |
| ; Inputs: snd_duration (guard), anim_frame_count (pitch source) |
| ; Outputs: snd_pitch = anim_frame_count + $C0, snd_pitch_delta = $08, |
| ; snd_duration = $04, snd_volume = $30 (when triggered) |
| ; Side Effects: None (sound rendered by sound_engine_tick) |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| $2BA0 | a5 54 | sfx_finish_lineldazp_snd_duration; guard: skip if a sound is already playing ; x-ref: $2E90 |
| $2BA2 | d0 14 | bner_2BB8 |
| $2BA4 | a9 04 | lda#$04; 4-frame blip; pitch = anim_frame_count + $C0 (dynamic) |
| $2BA6 | 85 54 | stazp_snd_duration |
| $2BA8 | a5 3c | ldazp_anim_frame_count |
| $2BAA | ea | nop |
| $2BAB | 18 | clc |
| $2BAC | 69 c0 | adc#$c0 |
| $2BAE | 85 50 | stazp_snd_pitch |
| $2BB0 | a9 08 | lda#$08; delta=$08 (moderate slide), vol=$30 |
| $2BB2 | 85 51 | stazp_snd_pitch_delta |
| $2BB4 | a9 30 | lda#$30 |
| $2BB6 | 85 55 | stazp_snd_volume |
| $2BB8 | 60 | r_2BB8rts; x-ref: $2BA2 |
| $2BB9 | | .byte$00, $00, $00 |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| ; Scroll rumble sound effect ticker (non-preemptive). |
| ; Only fires when snd_duration==0. Arms a 3-frame pulse whose pitch |
| ; cycles through 8 tones: (frame_counter & $07) * 4 + $A0, ranging |
| ; $A0-$BC. The cycling creates a pulsating warble - the signature |
| ; track scroll / engine rumble sound. Fast descending slide ($10). |
| ; Called every frame from update_scroll_tiles. |
| ; |
| ; Inputs: snd_duration (guard), frame_counter (pitch cycling) |
| ; Outputs: snd_pitch = (frame&7)*4 + $A0, snd_pitch_delta = $10, |
| ; snd_duration = $03, snd_volume = $30 (when triggered) |
| ; Side Effects: None (sound rendered by sound_engine_tick) |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| $2BBC | a5 54 | sfx_scroll_rumbleldazp_snd_duration; guard: skip if a sound is already playing ; x-ref: $29C0 |
| $2BBE | d0 17 | bner_2BD7 |
| $2BC0 | a9 03 | lda#$03; 3-frame pulse; pitch = (frame&7)*4 + $A0 (8-tone warble cycle) |
| $2BC2 | 85 54 | stazp_snd_duration |
| $2BC4 | a5 3f | ldazp_frame_counter |
| $2BC6 | 29 07 | and#$07 |
| $2BC8 | 0a | asla |
| $2BC9 | 0a | asla |
| $2BCA | 18 | clc |
| $2BCB | 69 a0 | adc#$a0 |
| $2BCD | 85 50 | stazp_snd_pitch |
| $2BCF | a9 10 | lda#$10; delta=$10 (fast slide), vol=$30 |
| $2BD1 | 85 51 | stazp_snd_pitch_delta |
| $2BD3 | a9 30 | lda#$30 |
| $2BD5 | 85 55 | stazp_snd_volume |
| $2BD7 | 60 | r_2BD7rts; x-ref: $2BBE |
| $2BD8 | | .byte$00, $00, $00, $00 |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| ; Lap-start sound effect + display counter reset. |
| ; Arms a bright ascending tone at loud volume - the lap-start fanfare. |
| ; Then calls reset_display_counters to prepare the display for the new |
| ; lap animation. Called from init_lap_start_anim_no_kill. |
| ; |
| ; Inputs: None |
| ; Outputs: snd_pitch=$C0, snd_pitch_delta=$04, snd_duration=$0F, |
| ; snd_volume=$50; display counters reset |
| ; Side Effects: Calls reset_display_counters |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| $2BDC | a9 c0 | sfx_lap_startlda#$c0; pitch=$C0 (mid-high), delta=$04 (slow ascending), loud ; x-ref: $266D |
| $2BDE | 85 50 | stazp_snd_pitch |
| $2BE0 | a9 04 | lda#$04 |
| $2BE2 | 85 51 | stazp_snd_pitch_delta |
| $2BE4 | a9 0f | lda#$0f |
| $2BE6 | 85 54 | stazp_snd_duration |
| $2BE8 | a9 50 | lda#$50 |
| $2BEA | 85 55 | stazp_snd_volume |
| $2BEC | 20 0c 2e | jsrreset_display_counters; prepare display for new lap animation |
| $2BEF | 60 | rts |
| $2BF0 | | .byte$00, $00, $00, $00 |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| ; Advances track_progress by one tick and dynamically updates the engine |
| ; pitch sound, creating an accelerating tone as the track scrolls. |
| ; |
| ; Three phases based on track_progress: |
| ; == 0 (start): compute initial pitch from progress, arm sound |
| ; $01-$8F (scrolling): re-arm sound only if snd_pitch < $60; |
| ; otherwise let existing pitch slide naturally |
| ; >= $90 (near end): silent - skip all sound setup, only inc progress |
| ; |
| ; Pitch computation: |
| ; delta = (progress >> 3) | $F0 -> range $F0-$FF (increasingly fast) |
| ; pitch = $F0 - delta -> range $00-$0F (rises as progress increases) |
| ; 1-frame duration = continuous retrigger for smooth gliding tone. |
| ; |
| ; Returns new track_progress in A for caller to check end-of-course. |
| ; Called from handle_mode_track_scroll. |
| ; |
| ; Inputs: track_progress, snd_pitch |
| ; Outputs: track_progress (incremented), A = new progress, |
| ; snd_pitch/delta/duration/volume updated (when applicable) |
| ; Side Effects: None |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| advance_progress_and_engine_sfx |
| $2BF4 | a5 36 | ldazp_track_progress; progress==0? -> compute initial pitch; >=90? -> silent (near end) ; x-ref: $283A |
| $2BF6 | f0 0a | beqb_2C02 |
| $2BF8 | c9 90 | cmp#$90 |
| $2BFA | b0 1e | bcsb_2C1A |
| $2BFC | a5 50 | ldazp_snd_pitch; pitch already >= $60? -> skip recalc, let it slide naturally |
| $2BFE | c9 60 | cmp#$60 |
| $2C00 | b0 10 | bcsb_2C12 |
| $2C02 | a5 36 | b_2C02ldazp_track_progress; delta = (progress>>3)|$F0; pitch = $F0 - delta (rising with progress) ; x-ref: $2BF6 |
| $2C04 | 4a | lsra |
| $2C05 | 4a | lsra |
| $2C06 | 4a | lsra |
| $2C07 | 09 f0 | ora#$f0 |
| $2C09 | 85 51 | stazp_snd_pitch_delta |
| $2C0B | a9 f0 | lda#$f0 |
| $2C0D | 38 | sec |
| $2C0E | e5 51 | sbczp_snd_pitch_delta |
| $2C10 | 85 50 | stazp_snd_pitch |
| $2C12 | a9 01 | b_2C12lda#$01; 1-frame duration = continuous retrigger for smooth tone ; x-ref: $2C00 |
| $2C14 | 85 54 | stazp_snd_duration |
| $2C16 | a9 30 | lda#$30 |
| $2C18 | 85 55 | stazp_snd_volume |
| $2C1A | e6 36 | b_2C1Ainczp_track_progress; always: advance progress, return new value in A ; x-ref: $2BFA |
| $2C1C | a5 36 | ldazp_track_progress |
| $2C1E | 60 | rts |
| $2C1F | | .byte$00 |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| ; Arms the obstacle collision sound and sets the sound-triggered flag. |
| ; Called from the high-speed obstacle physics path when (vel & $1F)==$10 |
| ; and the frame-counter gate passes. Sets bit 4 of obstacle_flags,x |
| ; (marking the slot as sound-triggered) and arms a near-max-pitch |
| ; rapidly-descending sound: pitch=$FC, delta=$FE (-2), dur=12, vol=$50. |
| ; |
| ; Inputs: A = obstacle_flags,x (current flags), X = obstacle slot |
| ; Outputs: obstacle_flags,x with bit 4 set, snd_pitch=$FC, |
| ; snd_pitch_delta=$FE, snd_duration=$0C, snd_volume=$50 |
| ; Side Effects: None (sound rendered by sound_engine_tick) |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| sfx_obstacle_collision_arm |
| $2C20 | 09 10 | ora#$10; set bit 4 (sound-triggered flag) in obstacle_flags,x ; x-ref: $2574 |
| $2C22 | 95 10 | stazp_obstacle_flags,x |
| $2C24 | a9 fc | lda#$fc; pitch=$FC, delta=$FE (-2), dur=12, vol=$50 (near-max descending) |
| $2C26 | 85 50 | stazp_snd_pitch |
| $2C28 | a9 fe | lda#$fe |
| $2C2A | 85 51 | stazp_snd_pitch_delta |
| $2C2C | a9 0c | lda#$0c |
| $2C2E | 85 54 | stazp_snd_duration |
| $2C30 | a9 50 | lda#$50 |
| $2C32 | 85 55 | stazp_snd_volume |
| $2C34 | 60 | rts |
| $2C35 | | .byte$00, $00, $00 |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| ; Bonus collect sound effect. Arms a max-pitch fast-descending chirp when |
| ; the bike hits a safe obstacle (type < 5). Short 8-frame burst. |
| ; Called from the collision handler on the non-crash (bonus) path. |
| ; |
| ; Inputs: None |
| ; Outputs: snd_pitch=$FF, snd_pitch_delta=$F0, snd_duration=$08, snd_volume=$30 |
| ; Side Effects: None (sound rendered by sound_engine_tick) |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| $2C38 | a9 ff | sfx_bonus_collectlda#$ff; pitch=$FF, delta=$F0, dur=8, vol=$30 (short max-pitch chirp) ; x-ref: $2D61 |
| $2C3A | 85 50 | stazp_snd_pitch |
| $2C3C | a9 f0 | lda#$f0 |
| $2C3E | 85 51 | stazp_snd_pitch_delta |
| $2C40 | a9 08 | lda#$08 |
| $2C42 | 85 54 | stazp_snd_duration |
| $2C44 | a9 30 | lda#$30 |
| $2C46 | 85 55 | stazp_snd_volume |
| $2C48 | 60 | rts |
| $2C49 | | .byte$00, $00, $00 |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| ; Obstacle management system: spawner + collision detector. |
| ; Called every frame from the main loop. Two phases: |
| ; |
| ; Phase 1 - Spawning ($2C5A-$2CDF): Only during game_mode 2 or 7. |
| ; Uses PRNG (s27E0) to generate spawn_type (lower nibble). |
| ; Looks up course-specific spawn tables (f1DA0, f1DB0, f1DF0, f1E20) |
| ; to decide if a spawn is allowed. Finds an empty slot (obstacle_flags=$FF) |
| ; and checks spawn_cooldown. If all checks pass, spawns an obstacle with: |
| ; - Types 0-7 (normal): random position and velocity |
| ; - Types 8+ (wide/special): table-driven position, random velocity |
| ; - All spawns get obstacle_life=$28 (40-tick lifetime). |
| ; |
| ; Phase 2 - Collision ($2CE0-$2D43): Checks all 4 obstacle slots. |
| ; Computes vertical screen distance from raster position. |
| ; - Normal obstacles: vertical [$39,$49), horizontal |bike-obs| < 8 |
| ; - Wide obstacles: vertical [$3D,$49), flag bit 4 set, horizontal range check |
| ; On collision: type >= 5 -> crash (s26AC); type < 5 -> bonus (scroll advance). |
| ; |
| ; Inputs: game_mode, course_index, spawn_cooldown, obstacle_flags/life/pos/vel[], |
| ; bike_pos_hi, raster_split_a, rng_state_*, spawn tables f1DA0-f1E20 |
| ; Outputs: obstacle_flags/life/pos_hi/pos_lo/vel[], spawn_cooldown, spawn_type |
| ; Side Effects: May crash (s26AC), add score (s2C38), advance scroll (b29CA) |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| obstacle_spawn_and_collide |
| $2C4C | a5 02 | ldazp_game_mode; x-ref: $20EF |
| $2C4E | c9 02 | cmp#GameMode.ACTIVE_RIDE; only active during active riding (mode 2) |
| $2C50 | f0 08 | beqb_2C5A |
| $2C52 | c9 07 | cmp#GameMode.VELOCITY_INTEGRATE; or velocity correction (mode 7) |
| $2C54 | f0 04 | beqb_2C5A |
| $2C56 | 60 | rts |
| $2C57 | ea | nop |
| $2C58 | ea | nop |
| $2C59 | ea | nop |
| $2C5A | 20 e0 27 | b_2C5Ajsrprng_next; PRNG -> lower nibble = spawn_type ; x-ref: $2C50, $2C54 |
| $2C5D | 29 0f | and#$0f |
| $2C5F | 85 52 | stazp_spawn_type |
| $2C61 | aa | tax |
| $2C62 | a5 2f | ldazp_course_index |
| $2C64 | 29 0f | and#$0f |
| $2C66 | 18 | clc |
| $2C67 | 7d a0 1d | adcspawn_type_offsets,x; Y = course_index + f1DA0[spawn_type] (spawn table offset) |
| $2C6A | a8 | tay |
| $2C6B | b9 20 1e | ldaobstacle_spawn_params,y |
| $2C6E | 3d b0 1d | andspawn_allowed_masks,x; spawn allowed? (table AND mask must be nonzero) |
| $2C71 | f0 18 | beqb_2C8B; zero = spawn blocked for this course/type |
| $2C73 | a5 2f | ldazp_course_index |
| $2C75 | 29 0f | and#$0f |
| $2C77 | aa | tax |
| $2C78 | 20 e0 27 | jsrprng_next; 2nd PRNG roll vs difficulty threshold |
| $2C7B | dd f0 1d | cmpspawn_prob_thresholds,x; roll >= threshold? -> spawn fails (probability gate) |
| $2C7E | b0 0b | bcsb_2C8B |
| $2C80 | a2 03 | ldx#$03 |
| $2C82 | b5 10 | b_2C82ldazp_obstacle_flags,x; find empty obstacle slot ($FF = dead) ; x-ref: $2C89 |
| $2C84 | c9 ff | cmp#$ff |
| $2C86 | f0 06 | beqb_2C8E; found empty slot X -> spawn here |
| $2C88 | ca | dex |
| $2C89 | 10 f7 | bplb_2C82 |
| $2C8B | 18 | b_2C8Bclc; x-ref: $2C71, $2C7E, $2C98 |
| $2C8C | 90 52 | bccb_2CE0 |
| $2C8E | b9 20 1e | b_2C8Eldaobstacle_spawn_params,y; x-ref: $2C86 |
| $2C91 | 29 0f | and#$0f |
| $2C93 | 18 | clc |
| $2C94 | 69 06 | adc#$06 |
| $2C96 | c5 2b | cmpzp_spawn_cooldown; cooldown check: too soon since last spawn? |
| $2C98 | b0 f1 | bcsb_2C8B |
| $2C9A | a5 52 | ldazp_spawn_type |
| $2C9C | 95 10 | stazp_obstacle_flags,x; write spawn_type into slot flags |
| $2C9E | a9 28 | lda#$28; obstacle_life = $28 (40 ticks) |
| $2CA0 | 95 14 | stazp_obstacle_life,x |
| $2CA2 | a9 00 | lda#$00 |
| $2CA4 | 85 2b | stazp_spawn_cooldown |
| $2CA6 | a5 52 | ldazp_spawn_type |
| $2CA8 | c9 08 | cmp#$08; type >= 8? -> wide/special obstacle spawn path |
| $2CAA | b0 1d | bcsb_2CC9 |
| $2CAC | 20 e0 27 | jsrprng_next; normal: random horizontal pos = (PRNG & $1C) + $0C |
| $2CAF | 29 1c | and#$1c |
| $2CB1 | 18 | clc |
| $2CB2 | 69 0c | adc#$0c |
| $2CB4 | 95 18 | stazp_obstacle_pos_hi,x |
| $2CB6 | 20 e0 27 | jsrprng_next; normal: random velocity = (PRNG & $BF) + $20 |
| $2CB9 | 29 bf | and#$bf |
| $2CBB | 18 | clc |
| $2CBC | 69 20 | adc#$20 |
| $2CBE | ea | nop |
| $2CBF | ea | nop |
| $2CC0 | ea | nop |
| $2CC1 | 95 20 | stazp_obstacle_vel,x |
| $2CC3 | a9 00 | lda#$00 |
| $2CC5 | 95 1c | stazp_obstacle_pos_lo,x |
| $2CC7 | f0 17 | beqb_2CE0 |
| $2CC9 | a9 00 | b_2CC9lda#$00; x-ref: $2CAA |
| $2CCB | 95 1c | stazp_obstacle_pos_lo,x |
| $2CCD | 20 e0 27 | jsrprng_next; wide: random velocity from PRNG |
| $2CD0 | 95 20 | stazp_obstacle_vel,x |
| $2CD2 | b9 20 1e | ldaobstacle_spawn_params,y |
| $2CD5 | 29 e0 | and#$e0; wide: pos = (f1E20[Y] & $E0) >> 1 + $10 (table-driven) |
| $2CD7 | 4a | lsra |
| $2CD8 | ea | nop |
| $2CD9 | ea | nop |
| $2CDA | ea | nop |
| $2CDB | 18 | clc |
| $2CDC | 69 10 | adc#$10 |
| $2CDE | 95 18 | stazp_obstacle_pos_hi,x |
| $2CE0 | a2 03 | b_2CE0ldx#$03; --- Phase 2: Collision detection (4 slots) --- ; x-ref: $2C8C, $2CC7 |
| $2CE2 | b5 10 | b_2CE2ldazp_obstacle_flags,x; x-ref: $2D41 |
| $2CE4 | c9 ff | cmp#$ff; slot dead ($FF)? -> skip |
| $2CE6 | f0 58 | beqb_2D40 |
| $2CE8 | b5 14 | ldazp_obstacle_life,x |
| $2CEA | 0a | asla; vert screen dist = life*8 - raster_split / 2 |
| $2CEB | 0a | asla |
| $2CEC | 0a | asla |
| $2CED | 38 | sec |
| $2CEE | e5 04 | sbczp_raster_split_a |
| $2CF0 | 4a | lsra |
| $2CF1 | 85 f7 | stazp_blit_scratch |
| $2CF3 | b5 10 | ldazp_obstacle_flags,x |
| $2CF5 | c9 08 | cmp#$08; type >= 8? -> wide obstacle collision path |
| $2CF7 | b0 1f | bcsb_2D18 |
| $2CF9 | a5 f7 | ldazp_blit_scratch |
| $2CFB | c9 39 | cmp#$39; normal: vertical hit zone lower bound ($39) |
| $2CFD | 90 41 | bccb_2D40 |
| $2CFF | c9 49 | cmp#$49; normal: vertical hit zone upper bound ($49) |
| $2D01 | b0 3d | bcsb_2D40 |
| $2D03 | a5 27 | ldazp_bike_pos_x_hi |
| $2D05 | 38 | sec |
| $2D06 | f5 18 | sbczp_obstacle_pos_hi,x; horizontal distance = |bike_pos_hi - obstacle_pos_hi| |
| $2D08 | 10 05 | bplb_2D0F |
| $2D0A | 49 ff | eor#$ff |
| $2D0C | 18 | clc |
| $2D0D | 69 01 | adc#$01 |
| $2D0F | c9 08 | b_2D0Fcmp#$08; within 8 pixels horizontally? -> HIT! ; x-ref: $2D08 |
| $2D11 | b0 2d | bcsb_2D40 |
| $2D13 | 20 48 2d | jsrhandle_obstacle_collision; COLLISION: handle hit on normal obstacle |
| $2D16 | 60 | rts |
| $2D17 | ea | nop |
| $2D18 | a5 f7 | b_2D18ldazp_blit_scratch; x-ref: $2CF7 |
| $2D1A | c9 3d | cmp#$3d; wide: vertical hit zone lower bound ($3D) |
| $2D1C | 90 22 | bccb_2D40 |
| $2D1E | c9 49 | cmp#$49 |
| $2D20 | b0 1e | bcsb_2D40 |
| $2D22 | b5 10 | ldazp_obstacle_flags,x |
| $2D24 | 29 10 | and#$10; bit 4 = active/visible flag (must be set) |
| $2D26 | f0 18 | beqb_2D40 |
| $2D28 | b5 10 | ldazp_obstacle_flags,x |
| $2D2A | 29 03 | and#$03; wide: horizontal range from (flags & $03)*4 + $0C |
| $2D2C | 0a | asla |
| $2D2D | 0a | asla |
| $2D2E | 18 | clc |
| $2D2F | 69 0c | adc#$0c |
| $2D31 | c5 27 | cmpzp_bike_pos_x_hi |
| $2D33 | b0 0b | bcsb_2D40 |
| $2D35 | a9 3f | lda#$3f |
| $2D37 | c5 27 | cmpzp_bike_pos_x_hi; wide: horizontal range upper limit ($3F) |
| $2D39 | 90 05 | bccb_2D40 |
| $2D3B | 20 48 2d | jsrhandle_obstacle_collision; COLLISION: handle hit on wide obstacle |
| $2D3E | 60 | rts |
| $2D3F | ea | nop |
| $2D40 | ca | b_2D40dex; x-ref: $2CE6, $2CFD, $2D01, $2D11, $2D1C, $2D20, $2D26, $2D33, ... |
| $2D41 | 10 9f | bplb_2CE2 |
| $2D43 | 60 | rts |
| $2D44 | | .byte$00, $00, $00, $00 |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| ; Collision resolution handler. Called when an obstacle hits the bike. |
| ; - Wide obstacles (type >= 8): stop obstacle (vel=0), keep in slot |
| ; - Normal obstacles (type < 8): mark slot dead ($FF) |
| ; - Type >= 5: full crash (s26AC - debris explosion) |
| ; - Type < 5, nonzero: score bonus + scroll advance (s2C38 + b29CA) |
| ; - Type == 0: set anim_frame_count = 5 (visual flash) |
| ; |
| ; Inputs: X = obstacle slot index, obstacle_flags[X] |
| ; Outputs: obstacle_flags[X] (cleared or kept), obstacle_vel[X] (zeroed) |
| ; Side Effects: Crash (s26AC) or bonus scoring (s2C38) + scroll advance |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| handle_obstacle_collision |
| $2D48 | b4 10 | ldyzp_obstacle_flags,x; x-ref: $2D13, $2D3B |
| $2D4A | c0 08 | cpy#$08; type >= 8 (wide)? -> stop obstacle, keep in slot |
| $2D4C | 90 06 | bccb_2D54 |
| $2D4E | a9 00 | lda#$00; wide: zero velocity (obstacle stops) |
| $2D50 | 95 20 | stazp_obstacle_vel,x |
| $2D52 | f0 04 | beqb_2D58 |
| $2D54 | a9 ff | b_2D54lda#$ff; normal: mark slot dead ($FF) ; x-ref: $2D4C |
| $2D56 | 95 10 | stazp_obstacle_flags,x |
| $2D58 | 98 | b_2D58tya; x-ref: $2D52 |
| $2D59 | c9 05 | cmp#$05; type >= 5? -> crash! |
| $2D5B | 90 04 | bccb_2D61 |
| $2D5D | 20 ac 26 | jsrtrigger_crash; dangerous obstacle: full crash + debris |
| $2D60 | 60 | rts |
| $2D61 | 20 38 2c | b_2D61jsrsfx_bonus_collect; safe obstacle: score bonus + scroll advance ; x-ref: $2D5B |
| $2D64 | c0 00 | cpy#$00; type == 0? -> visual flash only |
| $2D66 | f0 21 | beqb_2D89 |
| $2D68 | a5 2f | ldazp_course_index |
| $2D6A | 29 0f | and#$0f |
| $2D6C | aa | tax |
| $2D6D | bd 10 1e | ldacourse_scroll_steps,x |
| $2D70 | 85 f7 | stazp_blit_scratch |
| $2D72 | a9 00 | lda#$00 |
| $2D74 | 18 | b_2D74clc; x-ref: $2D78 |
| $2D75 | 65 f7 | adczp_blit_scratch |
| $2D77 | 88 | dey |
| $2D78 | 10 fa | bplb_2D74 |
| $2D7A | ea | nop |
| $2D7B | 85 f7 | stazp_blit_scratch |
| $2D7D | a0 01 | b_2D7Dldy#$01; x-ref: $2D86 |
| $2D7F | a2 05 | ldx#$05 |
| $2D81 | 20 ca 29 | jsrb_29CA |
| $2D84 | c6 f7 | deczp_blit_scratch |
| $2D86 | d0 f5 | bneb_2D7D |
| $2D88 | 60 | rts |
| $2D89 | a9 05 | b_2D89lda#$05; type 0 hit: set anim flash = 5 frames ; x-ref: $2D66 |
| $2D8B | 85 3c | stazp_anim_frame_count |
| $2D8D | 60 | rts |
| $2D8E | | .byte$00, $00 |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| ; Initializes the two parallel track tile base tables. |
| ; Copies 32 bytes from ROM f1C28 into $0C00-$0C1F (raw base tile indices), |
| ; then stores each value + $14 (20) into $0C28-$0C47 (second-half tile |
| ; mapping for alternating playfield rows). Clears sentinel byte $0C31. |
| ; |
| ; Inputs: None |
| ; Outputs: $0C00-$0C1F = f1C28 base tiles, $0C28-$0C47 = base + $14, |
| ; $0C31 = 0 |
| ; Side Effects: None |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| init_tile_base_tables |
| $2D90 | a2 1f | ldx#$1f; copy 32 base tiles from f1C28 -> $0C00; offset +$14 -> $0C28 ; x-ref: $2E14 |
| $2D92 | bd 28 1c | b_2D92ldatrack_tile_indices,x; x-ref: $2D9F |
| $2D95 | 9d 00 0c | staSCREEN_RAM_R0C0,x |
| $2D98 | 18 | clc |
| $2D99 | 69 14 | adc#$14 |
| $2D9B | 9d 28 0c | staSCREEN_RAM_R1C0,x |
| $2D9E | ca | dex |
| $2D9F | 10 f1 | bplb_2D92 |
| $2DA1 | a9 00 | lda#$00; clear sentinel byte $0C31 |
| $2DA3 | 8d 31 0c | staSCREEN_RAM_R1C9 |
| $2DA6 | 60 | rts |
| $2DA7 | | .byte$00 |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| ; Stores per-course animation and scroll parameters. |
| ; Saves A into anim_frame_count, loads scroll_speed from course_scroll_speeds[X]. |
| ; Called from the course-advance routine (advance_course_layout) after incrementing |
| ; course_index and looking up the new frame count from course_anim_frames. |
| ; |
| ; Inputs: A = anim_frame_count value, X = course_index |
| ; Outputs: anim_frame_count = A, scroll_speed = course_scroll_speeds[X] |
| ; Side Effects: None |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| $2DA8 | 85 3c | store_course_paramsstazp_anim_frame_count; save anim_frame_count and load scroll_speed for this course ; x-ref: $2A24 |
| $2DAA | bd e0 1d | ldacourse_scroll_speeds,x |
| $2DAD | 85 53 | stazp_scroll_speed |
| $2DAF | 60 | rts |
| $2DB0 | | .byte$00, $00, $00, $00 |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| ; Jump movement handler + level select UI. |
| ; Called from handle_mode_normal_ride when fire button is held (mode 0). |
| ; |
| ; 1. Ticks the music sequencer (music_sequencer_tick) each frame. |
| ; 2. If title_row_anim < $64 (100): monitors joystick tilt bits 2+3. |
| ; Both held simultaneously -> inc title_row_anim (charging to unlock). |
| ; Either released -> reset title_row_anim to 0. |
| ; 3. When title_row_anim reaches $64 (100 frames held): enters the |
| ; level-select mode. Copies "level RR" text from f1C98 to screen |
| ; $0DF0 with colour $71. Every 8th frame, reads joystick bits 2/3 |
| ; to dec/inc title_char_idx (course selection, wrapped to 0-15). |
| ; Updates course display digits from f1DC0/f1DD0 lookup tables |
| ; and syncs course_index to the selection. |
| ; |
| ; Inputs: joystick_state (bits 2-3, bit 7), title_row_anim, title_char_idx, |
| ; frame_counter |
| ; Outputs: title_row_anim, title_char_idx, course_index, |
| ; screen $0DF0-$0DF7 (level text), $09F0-$09F7 (colour) |
| ; Side Effects: Music sequencer tick, screen RAM writes |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| handle_jump_and_level_select |
| $2DB4 | 20 a0 2a | jsrmusic_sequencer_tick; tick music each frame while fire is held ; x-ref: $275E |
| $2DB7 | a5 56 | ldazp_title_row_anim; charging counter: needs 100 frames with both tilt bits held |
| $2DB9 | c9 64 | cmp#$64 |
| $2DBB | f0 11 | beqb_2DCE |
| $2DBD | a5 33 | ldazp_joystick_state; both tilt bits (2+3) held? -> charge; else reset to 0 |
| $2DBF | 29 0c | and#$0c |
| $2DC1 | c9 0c | cmp#$0c |
| $2DC3 | d0 04 | bneb_2DC9 |
| $2DC5 | e6 56 | inczp_title_row_anim |
| $2DC7 | d0 04 | bner_2DCD |
| $2DC9 | a9 00 | b_2DC9lda#$00; x-ref: $2DC3 |
| $2DCB | 85 56 | stazp_title_row_anim |
| $2DCD | 60 | r_2DCDrts; x-ref: $2DC7 |
| $2DCE | a2 07 | b_2DCEldx#$07; --- Level select active: copy "level RR" to screen, pick course --- ; x-ref: $2DBB |
| $2DD0 | bd 98 1c | b_2DD0ldalevel_select_text,x; x-ref: $2DDC |
| $2DD3 | 9d f0 0d | staSCREEN_RAM_R12C16,x |
| $2DD6 | a9 71 | lda#$71 |
| $2DD8 | 9d f0 09 | staCOLOR_RAM_R12C16,x |
| $2DDB | ca | dex |
| $2DDC | 10 f2 | bplb_2DD0 |
| $2DDE | a5 3f | ldazp_frame_counter; every 8th frame: joystick left/right adjusts title_char_idx |
| $2DE0 | 29 07 | and#$07 |
| $2DE2 | d0 10 | bneb_2DF4 |
| $2DE4 | a5 33 | ldazp_joystick_state |
| $2DE6 | 29 08 | and#$08 |
| $2DE8 | d0 02 | bneb_2DEC |
| $2DEA | c6 57 | deczp_title_char_idx |
| $2DEC | a5 33 | b_2DECldazp_joystick_state; x-ref: $2DE8 |
| $2DEE | 29 04 | and#$04 |
| $2DF0 | d0 02 | bneb_2DF4 |
| $2DF2 | e6 57 | inczp_title_char_idx |
| $2DF4 | a5 57 | b_2DF4ldazp_title_char_idx; wrap to 0-15; update display digits from f1DC0/f1DD0, sync course_index ; x-ref: $2DE2, $2DF0 |
| $2DF6 | 29 0f | and#$0f |
| $2DF8 | 85 57 | stazp_title_char_idx |
| $2DFA | aa | tax |
| $2DFB | bd c0 1d | ldacourse_digits_units,x |
| $2DFE | 8d f7 0d | staSCREEN_RAM_R12C23 |
| $2E01 | bd d0 1d | ldacourse_digits_tens,x |
| $2E04 | 8d f6 0d | staSCREEN_RAM_R12C22 |
| $2E07 | 86 2f | stxzp_course_index |
| $2E09 | 60 | rts |
| $2E0A | | .byte$00, $00 |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| ; Resets the tile/character animation counters to zero. |
| ; Despite their BASIC-flavoured names, RAM_OLDOV and RAM_TEMPF1 are both |
| ; display-engine state variables: OLDOV is a row animation counter (0-99) |
| ; that drives ROM tile-row selection from $1C98, and TEMPF1 is a 4-bit |
| ; column/character index (inc/dec'd via RAM_FRFTOP bits 2-3) that indexes |
| ; the ROM character table at $1DC0. Clearing both restarts the animation |
| ; from frame zero. Called during level initialisation and object resets. |
| ; |
| ; Inputs: None |
| ; Outputs: None |
| ; Side Effects:($56) <- 0 (row animation counter reset) |
| ; ($57) <- 0 (column/character index reset) |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| reset_display_counters |
| $2E0C | a9 00 | lda#$00; A=0; same value stored to both counters below ; x-ref: $263B, $2BEC |
| $2E0E | 85 56 | stazp_title_row_anim; Row animation counter (0-99); drives ROM tile-row selection at $1C98 |
| $2E10 | 85 57 | stazp_title_char_idx; Column/character index (4-bit); indexes ROM char table at $1DC0 |
| $2E12 | 60 | rts |
| $2E13 | | .byte$00 |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| ; Loads the course layout pointer and initializes track tile base tables. |
| ; First calls init_tile_base_tables to set up $0C00 (raw base tiles from |
| ; f1C28) and $0C28 (offset +$14 for alternating playfield rows). Then |
| ; syncs course_index to title_char_idx and loads the 16-bit course layout |
| ; pointer from f1E50/f1E60[course] into ptr_obj_record_lo/hi. |
| ; Called from init_course_state to prepare a new course for play. |
| ; |
| ; Inputs: title_char_idx (course selection 0-15) |
| ; Outputs: course_index synced, ptr_obj_record_lo/hi = course layout ptr, |
| ; $0C00-$0C1F base tiles, $0C28-$0C47 offset tiles, $0C31=0 |
| ; Side Effects: None |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| $2E14 | 20 90 2d | load_course_layoutjsrinit_tile_base_tables; init tile base tables ($0C00/$0C28 from f1C28) ; x-ref: $2640 |
| $2E17 | a6 57 | ldxzp_title_char_idx; sync course_index; load layout ptr from f1E50/f1E60[course] |
| $2E19 | 86 2f | stxzp_course_index |
| $2E1B | bd 50 1e | ldalevels_ptr_lo,x |
| $2E1E | 85 24 | stazp_ptr_obj_record_lo |
| $2E20 | bd 60 1e | ldalevels_ptr_hi,x |
| $2E23 | 85 25 | stazp_ptr_obj_record_hi |
| $2E25 | 60 | rts |
| $2E26 | | .byte$00, $00 |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| ; Advances the course layout data pointer by one byte, with wrapping. |
| ; Increments the 16-bit pointer ptr_obj_record_lo/hi. If it reaches |
| ; the end-of-data sentinel $3FD8, wraps back to $2F00 (start of course |
| ; data area). Implements a circular course data buffer so the track |
| ; loops endlessly. Called from the per-frame track rendering loop. |
| ; |
| ; Inputs: ptr_obj_record_lo/hi (current position in course data) |
| ; Outputs: ptr_obj_record_lo/hi incremented; wrapped to $2F00 at $3FD8 |
| ; Side Effects: None |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| advance_course_data_ptr |
| $2E28 | e6 24 | inczp_ptr_obj_record_lo; inc 16-bit pointer; wrap $3FD8 -> $2F00 (circular course buffer) ; x-ref: $24F1 |
| $2E2A | d0 02 | bneb_2E2E |
| $2E2C | e6 25 | inczp_ptr_obj_record_hi |
| $2E2E | a5 24 | b_2E2Eldazp_ptr_obj_record_lo; reached end sentinel $3FD8? ; x-ref: $2E2A |
| $2E30 | c9 d8 | cmp#$d8 |
| $2E32 | d0 0e | bner_2E42 |
| $2E34 | a5 25 | ldazp_ptr_obj_record_hi |
| $2E36 | c9 3f | cmp#$3f |
| $2E38 | d0 08 | bner_2E42 |
| $2E3A | a9 00 | lda#<course_data_base; yes: wrap pointer back to $2F00 (course data start) |
| $2E3C | 85 24 | stazp_ptr_obj_record_lo |
| $2E3E | a9 2f | lda#>course_data_base |
| $2E40 | 85 25 | stazp_ptr_obj_record_hi |
| $2E42 | 60 | r_2E42rts; x-ref: $2E32, $2E38 |
| $2E43 | | .byte$00 |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| ; Joystick throttle input handler. |
| ; Reads joystick tilt bits and adjusts bike_throttle: |
| ; Bit 3 (right): accelerate -> throttle += 2, capped at $FA |
| ; Bit 2 (left): decelerate -> throttle -= 2, floored at $62 |
| ; Step size is $02 per frame. Throttle range: $62 (min) to $FA (max). |
| ; |
| ; Inputs: joystick_state (bits 2 and 3), bike_throttle |
| ; Outputs: bike_throttle adjusted within [$62, $FA] |
| ; Side Effects: None |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| $2E44 | a5 33 | update_throttleldazp_joystick_state; bit 3 (right): accelerate -> throttle += 2, cap at $FA ; x-ref: $2E6C |
| $2E46 | 29 08 | and#$08 |
| $2E48 | f0 0d | beqb_2E57 |
| $2E4A | a5 2a | ldazp_bike_throttle |
| $2E4C | c9 fa | cmp#$fa |
| $2E4E | b0 07 | bcsb_2E57 |
| $2E50 | a5 2a | ldazp_bike_throttle |
| $2E52 | 18 | clc |
| $2E53 | 69 02 | adc#$02 |
| $2E55 | 85 2a | stazp_bike_throttle |
| $2E57 | a5 33 | b_2E57ldazp_joystick_state; bit 2 (left): decelerate -> throttle -= 2, floor at $62 ; x-ref: $2E48, $2E4E |
| $2E59 | 29 04 | and#$04 |
| $2E5B | f0 0d | beqr_2E6A |
| $2E5D | a5 2a | ldazp_bike_throttle |
| $2E5F | c9 62 | cmp#$62 |
| $2E61 | 90 07 | bccr_2E6A |
| $2E63 | a5 2a | ldazp_bike_throttle |
| $2E65 | 38 | sec |
| $2E66 | e9 02 | sbc#$02 |
| $2E68 | 85 2a | stazp_bike_throttle |
| $2E6A | 60 | r_2E6Arts; x-ref: $2E5B, $2E61 |
| $2E6B | | .byte$00 |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| ; Convenience wrapper: updates throttle from joystick input, then loads |
| ; bike_vel into A with carry clear — ready for the caller's ADC bias. |
| ; Called from apply_velocity_and_integrate. |
| ; |
| ; Inputs: joystick_state, bike_throttle, bike_vel |
| ; Outputs: bike_throttle adjusted, A = bike_vel, C = 0 |
| ; Side Effects: None |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| update_throttle_and_load_vel |
| $2E6C | 20 44 2e | jsrupdate_throttle; update throttle, then return bike_vel in A with C=0 ; x-ref: $28F8 |
| $2E6F | a5 29 | ldazp_bike_vel |
| $2E71 | 18 | clc |
| $2E72 | 60 | rts |
| $2E73 | | .byte$00 |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| ; Right-boundary check with conditional velocity correction. |
| ; Compares bike_pos_hi against track_right_edge: |
| ; - Below right edge: bike past boundary -> vel=0, mode=7 (soft wall) |
| ; - At/above edge + track_flags bit 7 set: prevent overshoot -> vel=0, mode=7 |
| ; - At/above edge + bit 7 clear: normal, no action |
| ; Provides a "soft wall" that stops the bike without crashing. |
| ; Called from the physics integration path after position update. |
| ; |
| ; Inputs: bike_pos_hi, track_right_edge, track_flags (bit 7) |
| ; Outputs: Possibly bike_vel=0, game_mode=7 (via enter_mode_vel_correct) |
| ; Side Effects: None |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| $2E74 | a5 27 | check_right_boundaryldazp_bike_pos_x_hi; bike past right edge? -> vel=0, mode=7 (soft wall) ; x-ref: $27BB |
| $2E76 | c5 39 | cmpzp_track_right_edge |
| $2E78 | b0 06 | bcsb_2E80 |
| $2E7A | a9 00 | lda#$00 |
| $2E7C | 20 f0 26 | jsrenter_mode_vel_correct |
| $2E7F | 60 | rts |
| $2E80 | a5 38 | b_2E80ldazp_track_flags; at boundary: track_flags bit 7 set? -> also stop (prevent overshoot) ; x-ref: $2E78 |
| $2E82 | 29 80 | and#$80 |
| $2E84 | f0 05 | beqr_2E8B |
| $2E86 | a9 00 | lda#$00 |
| $2E88 | 20 f0 26 | jsrenter_mode_vel_correct |
| $2E8B | 60 | r_2E8Brts; x-ref: $2E84 |
| $2E8C | | .byte$00, $00, $00, $00 |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| ; Finish-line / bike-coincidence detector. |
| ; Called every frame at the end of the bike increment path (both bikes moving). |
| ; |
| ; First arms the finish-line sound effect via s2BA0 (which only triggers if |
| ; no sound is already playing — JMPER=$00). Then checks whether both bike |
| ; screen-position slots have simultaneously reached the left-edge wrap value |
| ; $0B (bike 0 at f0C07, bike 1 at $0C08). If either bike has not yet |
| ; arrived, the routine returns without further action. |
| ; |
| ; When both bikes coincide at $0B: |
| ; - Both position slots are reset to the right-edge start value $14 |
| ; (character table) and $28 (secondary position table), restarting |
| ; the next lap from the beginning of the track. |
| ; - The finish-line sound (already armed above) continues to play. |
| ; |
| ; Inputs: f0C07 (bike 0 screen pos), $0C08 (bike 1 screen pos) |
| ; Outputs: f0C07/$0C08 <- $14, f0C2F/$0C30 <- $28 (on coincidence only) |
| ; Side Effects: Arms sound via s2BA0 (sets JMPER, DSCPNT, a51, SIZE) |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| $2E90 | 20 a0 2b | check_finish_linejsrsfx_finish_line; Arm finish-line sound (no-op if JMPER already non-zero) ; x-ref: $2394 |
| $2E93 | ad 07 0c | ldaSCREEN_RAM_R0C7; Load bike 0 screen position (slot 0 of position table) |
| $2E96 | c9 0b | cmp#$0b; Has bike 0 reached the left edge? |
| $2E98 | d0 17 | bner_2EB1; Bike 0 not at edge — no coincidence, return |
| $2E9A | ad 08 0c | ldaSCREEN_RAM_R0C8; Load bike 1 screen position (slot 1 of position table) |
| $2E9D | c9 0b | cmp#$0b; Has bike 1 also reached the left edge? |
| $2E9F | d0 10 | bner_2EB1; Bike 1 not at edge — no coincidence, return |
| $2EA1 | a9 14 | lda#$14; Both bikes at $0B — reset both to right-edge start ($14) |
| $2EA3 | 8d 07 0c | staSCREEN_RAM_R0C7 |
| $2EA6 | 8d 08 0c | staSCREEN_RAM_R0C8 |
| $2EA9 | a9 28 | lda#$28; Reset both secondary position slots to $28 (right-edge start) |
| $2EAB | 8d 2f 0c | staSCREEN_RAM_R1C7 |
| $2EAE | 8d 30 0c | staSCREEN_RAM_R1C8 |
| $2EB1 | 60 | r_2EB1rts; x-ref: $2E98, $2E9F |
| $2EB2 | | .byte$00, $00, $00, $00, $00, $00 |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| ; Game mode 3: Starting gate phase - enforces the left track boundary and |
| ; decays throttle until the bike comes to a stop. |
| ; If the bike has gone left of the track edge, a rightward correction force |
| ; is applied (j28F8). Obstacles are aged every tick. When throttle reaches |
| ; zero, transitions to game_mode = 4 (course complete / result screen). |
| ; |
| ; Inputs: bike_pos_hi, track_left_edge, bike_throttle, |
| ; obstacle_life[], obstacle_flags[] |
| ; Outputs: bike_pos_hi/lo, bike_vel, bike_throttle, game_mode, |
| ; obstacle_life[], obstacle_flags[], spawn_cooldown |
| ; Side Effects: May trigger crash (s26AC); advances to game_mode 4 via s269C |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| handle_mode_starting_gate |
| $2EB8 | a5 27 | ldazp_bike_pos_x_hi; x-ref: $2600 |
| $2EBA | c5 37 | cmpzp_track_left_edge; has bike gone left of the track edge? |
| $2EBC | b0 03 | bcsb_2EC1; bike >= left edge -> no correction needed |
| $2EBE | 20 f8 28 | jsrapply_velocity_and_integrate; bike past left edge: apply rightward correction + bounds check |
| $2EC1 | 20 18 28 | b_2EC1jsrstarting_gate_throttle_decay; age obstacles + decay throttle (-> game_mode 4 when throttle hits 0) ; x-ref: $2EBC |
| $2EC4 | 60 | rts |
| $2EC5 | | .fill59, $00 |
| ; Start of course layout data area. The 16-bit layout pointer wraps back here when it reaches the $3FD8 end sentinel, making the track circular. |
| $2F00 | | course_data_base.byte$00, $00; x-ref: $2E3A, $2E3E |
| $2F02 | | level_0.fill14, $00; x-ref: $1E50 |
| $2F10 | | .byte$fd, $ff |
| $2F12 | | .fill14, $00 |
| $2F20 | | .byte$fe, $ff |
| $2F22 | | .fill14, $00 |
| $2F30 | | .byte$b1 |
| $2F31 | | .fill9, $31 |
| $2F3A | | .byte$b2 |
| $2F3B | | .fill9, $32 |
| $2F44 | | .byte$b3 |
| $2F45 | | .fill9, $33 |
| $2F4E | | .byte$20, $21, $22, $00, $00, $01, $02, $03 |
| $2F56 | | .byte$01, $02, $03, $01, $02, $03, $01, $02 |
| $2F5E | | .byte$03, $01, $02, $03, $80 |
| $2F63 | | .fill17, $00 |
| $2F74 | | .byte$8d, $0d, $0d, $0d, $0d, $0d, $0d, $0d |
| $2F7C | | .byte$8e, $0e, $0e, $0e, $0e, $0e, $0e, $0e |
| $2F84 | | .byte$96, $17, $18, $19, $16, $17, $18, $19 |
| $2F8C | | .byte$8e |
| $2F8D | | .fill9, $0e |
| $2F96 | | .byte$29, $2a, $2b, $8e, $0e, $0e, $0e, $0e |
| $2F9E | | .byte$0e, $0e, $29, $2a, $2b, $29, $2a, $2b |
| $2FA6 | | .byte$8e, $0e, $0e, $0e, $0e, $0e |
| $2FAC | | .fill8, $0d |
| $2FB4 | | .byte$26, $27, $28, $26, $27, $28, $26, $27 |
| $2FBC | | .byte$28, $8d, $0d, $0d, $80, $00 |
| $2FC2 | | level_1.fill14, $00; x-ref: $1E51 |
| $2FD0 | | .byte$fd, $ff |
| $2FD2 | | .fill14, $00 |
| $2FE0 | | .byte$fe, $ff |
| $2FE2 | | .fill22, $00 |
| $2FF8 | | .byte$36, $39, $80 |
| $2FFB | | .fill13, $00 |
| $3008 | | .byte$36, $39, $80 |
| $300B | | .fill17, $00 |
| $301C | | .byte$ad, $2d, $2d, $2d, $2d, $2d, $2d, $2d |
| $3024 | | .fill8, $2f |
| $302C | | .byte$90, $10, $10, $10, $10, $10, $10, $10 |
| $3034 | | .byte$23, $24, $25, $90 |
| $3038 | | .fill10, $10 |
| $3042 | | .byte$23, $24, $25, $90 |
| $3046 | | .fill10, $10 |
| $3050 | | .byte$23, $24, $25, $90 |
| $3054 | | .fill10, $10 |
| $305E | | .byte$23, $24, $25, $90 |
| $3062 | | .fill22, $10 |
| $3078 | | .byte$0a, $0b, $0c, $90 |
| $307C | | .fill9, $10 |
| $3085 | | .byte$0a, $0b, $0c, $90 |
| $3089 | | .fill9, $10 |
| $3092 | | .byte$0a, $0b, $0c, $90 |
| $3096 | | .fill9, $10 |
| $309F | | .byte$0a, $0b, $0c, $90 |
| $30A3 | | .fill13, $10 |
| $30B0 | | .byte$b4, $34, $33, $33, $32, $32, $b1 |
| $30B7 | | .fill9, $31 |
| $30C0 | | .byte$26, $27, $28, $b1 |
| $30C4 | | .fill8, $31 |
| $30CC | | .byte$26, $27, $28, $26, $27, $28, $b1, $31 |
| $30D4 | | .byte$31, $31, $31, $31, $31, $31, $26, $27 |
| $30DC | | .byte$28, $26, $27, $28, $26, $27, $28, $b1 |
| $30E4 | | .byte$31, $31, $31, $31, $80, $00 |
| $30EA | | level_2.fill14, $00; x-ref: $1E52 |
| $30F8 | | .byte$fd, $ff |
| $30FA | | .fill14, $00 |
| $3108 | | .byte$fe, $ff |
| $310A | | .fill14, $00 |
| $3118 | | .byte$31, $32, $32, $32, $32, $32, $32, $32 |
| $3120 | | .byte$33, $34, $34, $34, $34, $34, $34, $34 |
| $3128 | | .byte$91, $11, $11, $11, $11, $11, $11, $11 |
| $3130 | | .byte$29, $2a, $2b, $91 |
| $3134 | | .fill8, $11 |
| $313C | | .byte$29, $2a, $2b, $91 |
| $3140 | | .fill12, $11 |
| $314C | | .byte$90 |
| $314D | | .fill15, $10 |
| $315C | | .byte$04, $05, $06, $04, $05, $06, $90, $10 |
| $3164 | | .byte$10, $10, $10, $10, $10, $10, $01, $02 |
| $316C | | .byte$03, $01, $02, $03, $01, $02, $03, $90 |
| $3174 | | .byte$10, $10, $10, $10, $23, $24, $25, $00 |
| $317C | | .byte$36, $37, $38, $37, $38, $37, $38, $37 |
| $3184 | | .byte$38, $37, $38, $37, $38, $37, $38, $37 |
| $318C | | .byte$38, $37, $38, $39, $b1, $31, $31, $31 |
| $3194 | | .byte$31, $31, $31, $31, $1a, $1b, $1c, $b1 |
| $319C | | .byte$31, $31, $31, $31, $1a, $1b, $1c, $31 |
| $31A4 | | .byte$31, $36, $39, $31, $1a, $1b, $1c, $b1 |
| $31AC | | .byte$31, $31, $31, $31, $1a, $1b, $1c, $b1 |
| $31B4 | | .byte$31, $31, $31, $31, $1a, $1b, $1c, $31 |
| $31BC | | .byte$31, $36, $39, $31, $1a, $1b, $1c, $b1 |
| $31C4 | | .byte$31, $31, $31, $31, $1a, $1b, $1c, $b1 |
| $31CC | | .byte$31, $31, $31, $31, $1a, $1b, $1c, $31 |
| $31D4 | | .byte$31, $36, $39, $31, $1a, $1b, $1c, $b1 |
| $31DC | | .byte$31, $31, $31, $31, $8d, $0d, $0d, $0d |
| $31E4 | | .byte$0d, $0d, $26, $27, $28, $0d, $26, $27 |
| $31EC | | .byte$28, $0d, $26, $27, $28, $8d |
| $31F2 | | level_3.byte$0d, $0d, $0d, $0d; x-ref: $1E53 |
| $31F6 | | .fill10, $00 |
| $3200 | | .byte$fd, $ff |
| $3202 | | .fill14, $00 |
| $3210 | | .byte$fe, $ff |
| $3212 | | .fill8, $00 |
| $321A | | .byte$ac |
| $321B | | .fill8, $2c |
| $3223 | | .byte$2d, $2d, $2d, $2d, $2d, $2e, $2e, $2e |
| $322B | | .byte$2e, $2e, $2f, $2f, $2f, $2f, $2f, $b0 |
| $3233 | | .byte$30, $30, $30, $30, $30, $00, $07, $08 |
| $323B | | .byte$09, $07, $08, $09, $00, $b0, $30, $30 |
| $3243 | | .byte$30, $30, $30, $30, $00, $07, $08, $09 |
| $324B | | .byte$00, $07, $08, $09, $00, $b0, $30, $30 |
| $3253 | | .byte$30, $30, $30, $30, $30, $00, $01, $02 |
| $325B | | .byte$03, $01, $02, $03, $01, $02, $03, $8d |
| $3263 | | .byte$8d, $0d, $0d, $0d, $0d, $0d, $0d, $0d |
| $326B | | .byte$26, $27, $28, $8e |
| $326F | | .fill8, $0e |
| $3277 | | .byte$29, $2a, $2b, $8f |
| $327B | | .fill9, $0f |
| $3284 | | .byte$20, $21, $22, $00, $04, $05, $06, $04 |
| $328C | | .byte$05, $06, $04, $05, $06, $00, $b5, $35 |
| $3294 | | .byte$35, $35, $35, $35, $b4, $34, $34, $34 |
| $329C | | .byte$b3, $33, $33, $33, $b2, $32, $32, $32 |
| $32A4 | | .byte$b1, $31, $31, $31, $80 |
| $32A9 | | .fill11, $00 |
| $32B4 | | .byte$36, $39, $80 |
| $32B7 | | .fill9, $00 |
| $32C0 | | .byte$36, $39, $80 |
| $32C3 | | .fill9, $00 |
| $32CC | | .byte$36, $39, $80 |
| $32CF | | .fill9, $00 |
| $32D8 | | .byte$36, $39, $80 |
| $32DB | | .fill11, $00 |
| $32E6 | | .byte$31, $31, $1a, $1b, $1c, $00, $36, $37 |
| $32EE | | .byte$38, $37, $38, $37 |
| $32F2 | | level_4.byte$38, $37, $38, $37, $38, $39; x-ref: $1E54 |
| $32F8 | | .fill8, $00 |
| $3300 | | .byte$fd, $ff |
| $3302 | | .fill14, $00 |
| $3310 | | .byte$fe, $ff |
| $3312 | | .fill14, $00 |
| $3320 | | .byte$8d, $0d, $0d, $0d, $0d, $0d, $0d, $0d |
| $3328 | | .byte$8e, $0e, $0e, $0e, $0e, $0e, $0e, $0e |
| $3330 | | .byte$8f, $0f, $0f, $0f, $0f, $0f, $0f, $0f |
| $3338 | | .byte$90, $10, $10, $10, $10, $10, $10, $10 |
| $3340 | | .byte$34, $34, $34, $34, $34, $34, $34, $b4 |
| $3348 | | .byte$23, $24, $25, $34, $04, $05, $06, $b4 |
| $3350 | | .byte$34, $34, $34, $34, $34, $34, $34, $b4 |
| $3358 | | .byte$34, $34, $34, $34, $23, $24, $25, $b4 |
| $3360 | | .byte$34, $34, $34, $34, $34, $34, $34, $b4 |
| $3368 | | .byte$34, $34, $34, $34, $34, $34, $34, $b4 |
| $3370 | | .byte$23, $24, $25, $34, $0a, $0b, $0c, $b4 |
| $3378 | | .byte$34, $34, $34, $34, $34, $34, $34, $b4 |
| $3380 | | .byte$34, $34, $34, $34, $23, $24, $25, $b4 |
| $3388 | | .byte$34, $34, $34, $34, $34, $34, $34, $b4 |
| $3390 | | .byte$34, $34, $34, $34, $34, $34, $34, $b4 |
| $3398 | | .byte$23, $24, $25, $34, $29, $2a, $2b, $b4 |
| $33A0 | | .byte$34, $34, $34, $34, $34, $34, $34, $b4 |
| $33A8 | | .byte$34, $34, $34, $34, $23, $24, $25, $b4 |
| $33B0 | | .byte$34, $34, $34, $34, $34, $34, $34, $b4 |
| $33B8 | | .byte$34, $34, $34, $34, $34, $34, $34, $b4 |
| $33C0 | | .byte$23, $24, $25, $34, $0a, $0b, $0c, $b4 |
| $33C8 | | .byte$34, $34, $34, $34, $34, $34, $34, $b4 |
| $33D0 | | .byte$34, $34, $34, $34, $23, $24, $25, $b4 |
| $33D8 | | .byte$34, $34, $34, $34, $34, $34, $34, $b4 |
| $33E0 | | .byte$23, $24, $25, $34, $04, $05, $06, $b4 |
| $33E8 | | .byte$34, $34, $34, $34, $34, $34, $34, $b4 |
| $33F0 | | .byte$34, $34, $34, $34, $34, $34, $34, $b4 |
| $33F8 | | .byte$90, $10, $10, $10, $10, $10, $10, $10 |
| $3400 | | .byte$8f, $0f, $0f, $0f, $0f, $0f, $0f, $0f |
| $3408 | | .byte$8e, $0e, $0e, $0e, $0e, $0e, $0e, $0e |
| $3410 | | .byte$8d, $0d, $0d, $0d, $0d, $0d, $0d, $0d |
| $3418 | | .byte$80, $00 |
| $341A | | level_5.fill14, $00; x-ref: $1E55 |
| $3428 | | .byte$fd, $ff |
| $342A | | .fill14, $00 |
| $3438 | | .byte$fe, $ff |
| $343A | | .fill14, $00 |
| $3448 | | .byte$36, $39, $80 |
| $344B | | .fill9, $00 |
| $3454 | | .byte$36, $39, $80 |
| $3457 | | .fill9, $00 |
| $3460 | | .byte$36, $39, $80, $00, $00, $00, $00, $00 |
| $3468 | | .byte$00, $00, $80, $00, $31, $31, $1a, $1b |
| $3470 | | .byte$1c, $00, $36, $37, $38, $37, $38, $37 |
| $3478 | | .byte$38, $b9, $00, $31, $31, $1a, $1b, $1c |
| $3480 | | .byte$00, $36, $37, $38, $37, $38, $37, $38 |
| $3488 | | .byte$b9, $00, $31, $31, $1a, $1b, $1c, $00 |
| $3490 | | .byte$36, $37, $38, $37, $38, $37, $38, $39 |
| $3498 | | .byte$80 |
| $3499 | | .fill15, $00 |
| $34A8 | | .byte$36, $39, $00, $31, $1a, $1b, $1c, $00 |
| $34B0 | | .byte$36, $37, $38, $37, $38, $37, $b8, $39 |
| $34B8 | | .byte$00, $32, $1d, $1e, $1f, $00, $36, $37 |
| $34C0 | | .byte$38, $37, $38, $37, $38, $39, $80 |
| $34C7 | | .fill13, $00 |
| $34D4 | | .byte$80, $00, $31, $31, $1a, $1b, $1c, $00 |
| $34DC | | .byte$36, $37, $38, $39, $07, $08, $09, $36 |
| $34E4 | | .byte$37, $38, $b9, $00, $31, $31, $1a, $1b |
| $34EC | | .byte$1c, $00, $07, $08, $09, $07 |
| $34F2 | | level_6.byte$08, $09, $07, $08, $09, $00, $80, $00; x-ref: $1E56 |
| $34FA | | .byte$00, $00, $00, $00, $00, $00, $fd, $ff |
| $3502 | | .fill14, $00 |
| $3510 | | .byte$fe, $ff |
| $3512 | | .fill14, $00 |
| $3520 | | .byte$0d, $0d, $0d, $0d, $0d, $36, $39, $8d |
| $3528 | | .byte$32, $32, $1d, $1e, $1e, $1f, $32, $32 |
| $3530 | | .byte$0f, $0f, $0f, $0f, $0f, $0f, $0f, $8f |
| $3538 | | .byte$34, $34, $23, $24, $24, $25, $34, $34 |
| $3540 | | .byte$0f, $0f, $0f, $0f, $0f, $0f, $0f, $8f |
| $3548 | | .byte$32, $32, $1d, $1e, $1e, $1f, $32, $32 |
| $3550 | | .byte$0d, $0d, $0d, $0d, $0d, $36, $39, $8d |
| $3558 | | .byte$32, $32, $1d, $1e, $1e, $1f, $32, $32 |
| $3560 | | .byte$0f, $0f, $0f, $0f, $0f, $0f, $0f, $8f |
| $3568 | | .byte$34, $34, $23, $24, $24, $25, $34, $34 |
| $3570 | | .byte$0f, $0f, $0f, $0f, $0f, $0f, $0f, $8f |
| $3578 | | .byte$32, $32, $1d, $1e, $1e, $1f, $32, $32 |
| $3580 | | .byte$0d, $0d, $0d, $0d, $0d, $36, $39, $8d |
| $3588 | | .byte$32, $32, $1d, $1e, $1e, $1f, $32, $32 |
| $3590 | | .byte$0f, $0f, $0f, $0f, $0f, $0f, $0f, $8f |
| $3598 | | .byte$34, $34, $23, $24, $24, $25, $34, $34 |
| $35A0 | | .byte$0f, $0f, $0f, $0f, $0f, $0f, $0f, $8f |
| $35A8 | | .byte$32, $32, $1d, $1e, $1e, $1f, $32, $32 |
| $35B0 | | .byte$0d, $0d, $0d, $0d, $0d, $36, $39, $8d |
| $35B8 | | .byte$00, $00 |
| $35BA | | level_7.fill14, $00; x-ref: $1E57 |
| $35C8 | | .byte$fd, $ff |
| $35CA | | .fill14, $00 |
| $35D8 | | .byte$fe, $ff |
| $35DA | | .fill18, $00 |
| $35EC | | .byte$b1, $31, $31, $31, $31, $31, $31, $31 |
| $35F4 | | .byte$b2, $32, $32, $32, $32, $32, $32, $32 |
| $35FC | | .byte$1d, $1e, $1f, $00, $01, $02, $03, $01 |
| $3604 | | .byte$02, $03, $01, $02, $03, $01, $02, $83 |
| $360C | | .byte$00, $20, $21, $21, $22, $00, $01, $02 |
| $3614 | | .byte$03, $01, $02, $03, $01, $02, $03, $01 |
| $361C | | .byte$02, $03, $01, $82, $03, $00, $20, $21 |
| $3624 | | .byte$21, $22, $00, $07, $08, $09, $00, $00 |
| $362C | | .byte$07, $08, $09, $00, $07, $08, $09, $00 |
| $3634 | | .byte$00, $07, $08, $09, $80 |
| $3639 | | .fill15, $00 |
| $3648 | | .byte$36, $39, $80 |
| $364B | | .fill8, $00 |
| $3653 | | .byte$80, $36, $39, $00, $1a, $1b, $1b, $1c |
| $365B | | .byte$00, $36, $39, $36, $37, $38, $37, $38 |
| $3663 | | .byte$37, $38, $39, $80 |
| $3667 | | .fill13, $00 |
| $3674 | | .byte$1a, $1b, $1b, $1c, $00, $00, $36, $39 |
| $367C | | .byte$36, $39, $b6, $39, $00, $00, $1d, $1e |
| $3684 | | .byte$1e, $1f, $00, $00, $36, $39, $36, $39 |
| $368C | | .byte$36, $b9, $00, $00, $20, $21, $21, $22 |
| $3694 | | .byte$00, $00, $01, $02, $03, $01, $02, $03 |
| $369C | | .byte$00, $00, $af |
| $369F | | .fill9, $2f |
| $36A8 | | .byte$31, $0a, $0b, $0c, $31, $00, $07, $08 |
| $36B0 | | .byte$09, $00 |
| $36B2 | | level_8.fill14, $00; x-ref: $1E58 |
| $36C0 | | .byte$fd, $ff |
| $36C2 | | .fill14, $00 |
| $36D0 | | .byte$fe, $ff |
| $36D2 | | .fill14, $00 |
| $36E0 | | .byte$b1, $31, $31, $31, $31, $31, $31, $31 |
| $36E8 | | .byte$b2, $32, $32, $32, $32, $32, $32, $32 |
| $36F0 | | .byte$b3, $33, $33, $33, $33, $33, $33, $33 |
| $36F8 | | .byte$b4, $34, $34, $34, $34, $34, $34, $34 |
| $3700 | | .byte$af, $2f, $2f, $2f, $2f, $2f, $2f, $2f |
| $3708 | | .byte$34, $23, $24, $24, $24, $24, $25, $34 |
| $3710 | | .byte$af, $2f, $2f, $2f, $2f, $2f, $29, $2a |
| $3718 | | .byte$2a, $2b, $2f, $2f, $2f, $2f, $33, $33 |
| $3720 | | .byte$20, $21, $22, $36, $39, $20, $21, $22 |
| $3728 | | .byte$33, $33, $2f, $2f, $2f, $2f, $2f, $2f |
| $3730 | | .byte$af, $2f, $2f, $2f, $2f, $2f, $2f, $2f |
| $3738 | | .byte$31, $0a, $0b, $0c, $0a, $0b, $0c, $31 |
| $3740 | | .byte$af, $2f, $2f, $2f, $2f, $2f, $29, $2a |
| $3748 | | .byte$2a, $2b, $2f, $2f, $2f, $2f, $33, $33 |
| $3750 | | .byte$33, $20, $21, $21, $21, $21, $22, $33 |
| $3758 | | .byte$33, $33, $2f, $2f, $2f, $2f, $2f, $2f |
| $3760 | | .byte$af, $2f, $2f, $2f, $2f, $2f, $2f, $2f |
| $3768 | | .byte$34, $23, $24, $24, $24, $24, $25, $34 |
| $3770 | | .byte$af, $2f, $2f, $2f, $2f, $2f, $29, $2a |
| $3778 | | .byte$2a, $2b, $2f, $2f, $2f, $2f, $33, $33 |
| $3780 | | .byte$20, $21, $22, $36, $39, $20, $21, $22 |
| $3788 | | .byte$33, $33, $2f, $2f, $2f, $2f, $2f, $2f |
| $3790 | | .byte$af, $2f, $2f, $2f, $2f, $2f, $2f, $2f |
| $3798 | | .byte$34, $23, $24, $24, $24, $24, $25, $34 |
| $37A0 | | .byte$af, $2f, $2f, $2f, $2f, $2f, $29, $2a |
| $37A8 | | .byte$2a, $2b, $2f, $2f, $2f, $2f, $2f, $2f |
| $37B0 | | .byte$33, $20, $21, $21, $21, $21, $22, $33 |
| $37B8 | | .byte$af, $2f, $2f, $2f, $2f, $2f, $2f, $2f |
| $37C0 | | .byte$af, $2f, $2f, $2f, $2f, $2f, $2f, $2f |
| $37C8 | | .byte$31, $0a, $0b, $0c, $0a, $0b, $0c, $31 |
| $37D0 | | .byte$af, $2f, $2f, $2f, $2f, $2f, $29, $2a |
| $37D8 | | .byte$2a, $2b, $2f, $2f, $2f, $2f, $33, $33 |
| $37E0 | | .byte$20, $21, $22, $36, $39, $20, $21, $22 |
| $37E8 | | .byte$33, $33, $2f, $2f, $2f, $2f, $2f, $2f |
| $37F0 | | .byte$af, $2f, $2f, $2f, $2f, $2f, $2f, $2f |
| $37F8 | | .byte$34, $23, $24, $24, $24, $24, $25, $34 |
| $3800 | | .byte$af, $2f, $2f, $2f, $2f, $2f, $2f, $2f |
| $3808 | | .byte$ae, $2e, $2e, $2e, $2e, $2e, $2e, $2e |
| $3810 | | .byte$ad, $2d, $2d, $2d, $2d, $2d, $2d, $2d |
| $3818 | | .byte$ac, $2c, $2c, $2c, $2c, $2c, $2c, $2c |
| $3820 | | .byte$80, $00 |
| $3822 | | level_9.fill14, $00; x-ref: $1E59 |
| $3830 | | .byte$fd, $ff |
| $3832 | | .fill14, $00 |
| $3840 | | .byte$fe, $ff |
| $3842 | | .fill14, $00 |
| $3850 | | .byte$1a, $1b, $1c, $00, $01, $02, $03, $80 |
| $3858 | | .fill12, $00 |
| $3864 | | .byte$1a, $1b, $1c, $00, $07, $08, $09, $80 |
| $386C | | .fill12, $00 |
| $3878 | | .byte$1a, $1b, $1c, $00, $01, $02, $03, $80 |
| $3880 | | .fill12, $00 |
| $388C | | .byte$b1, $31, $31, $31, $31, $31, $31, $31 |
| $3894 | | .byte$1a, $1b, $1c, $00, $01, $02, $03, $01 |
| $389C | | .byte$02, $03, $01, $02, $03, $01, $02, $03 |
| $38A4 | | .byte$00, $b2 |
| $38A6 | | .fill8, $32 |
| $38AE | | .byte$b3 |
| $38AF | | .fill9, $33 |
| $38B8 | | .byte$b4 |
| $38B9 | | .fill8, $34 |
| $38C1 | | .byte$23, $24, $25, $00, $04, $05, $06, $04 |
| $38C9 | | .byte$05, $06, $04, $05, $06, $04, $05, $06 |
| $38D1 | | .byte$04, $05, $06, $04, $85, $06, $00, $23 |
| $38D9 | | .byte$24, $24, $25, $00, $0a, $0b, $0c, $0a |
| $38E1 | | .byte$0b, $0c, $0a, $0b, $0c, $0a, $0b, $0c |
| $38E9 | | .byte$0a, $0b, $0c, $0a, $8b, $0c, $00, $23 |
| $38F1 | | .byte$24, $24, $25, $00, $04, $05, $06, $04 |
| $38F9 | | .byte$05, $06, $00, $04, $05, $06, $00, $04 |
| $3901 | | .byte$05, $06, $04, $85, $06, $00, $23, $24 |
| $3909 | | .byte$24, $25, $00, $36, $37, $38, $37, $38 |
| $3911 | | .byte$37, $38, $37, $38, $37, $38, $b7, $38 |
| $3919 | | .byte$39, $00, $1a, $1b, $1b, $1c, $00, $36 |
| $3921 | | .byte$37, $38, $37, $38, $37, $38, $37, $38 |
| $3929 | | .byte$37, $38, $b7, $38, $39, $00, $1a, $1b |
| $3931 | | .byte$1b, $1c, $00, $36, $37, $38, $37, $38 |
| $3939 | | .byte$37, $38, $37, $38, $37, $38, $37, $38 |
| $3941 | | .byte$39 |
| $3942 | | level_10.byte$80; x-ref: $1E5A |
| $3943 | | .fill13, $00 |
| $3950 | | .byte$fd, $ff |
| $3952 | | .fill14, $00 |
| $3960 | | .byte$fe, $ff |
| $3962 | | .fill14, $00 |
| $3970 | | .byte$8d, $0d, $0d, $0d, $0d, $0d, $0d, $0d |
| $3978 | | .byte$8e, $0e, $0e, $0e, $0e, $0e, $0e, $0e |
| $3980 | | .byte$8f, $0f, $0f, $0f, $0f, $0f, $0f, $0f |
| $3988 | | .byte$90, $10, $10, $10, $10, $10, $10, $10 |
| $3990 | | .byte$23, $24, $25, $07, $08, $09, $07, $08 |
| $3998 | | .byte$09, $07, $08, $09, $07, $08, $09, $07 |
| $39A0 | | .byte$08, $09, $07, $08, $09, $80, $00, $00 |
| $39A8 | | .byte$00, $00, $00, $00, $80, $00, $00, $00 |
| $39B0 | | .byte$1a, $1b, $1c, $00, $00, $01, $02, $03 |
| $39B8 | | .byte$00, $00, $00, $00, $80, $00, $00, $00 |
| $39C0 | | .byte$1a, $1b, $1b, $1c, $00, $07, $08, $09 |
| $39C8 | | .byte$00, $00, $00, $00, $80, $00, $00, $00 |
| $39D0 | | .byte$1a, $1b, $1b, $1c, $00, $01, $02, $03 |
| $39D8 | | .byte$80 |
| $39D9 | | .fill14, $00 |
| $39E7 | | .byte$1a, $1b, $1b, $1c, $00, $36, $37, $38 |
| $39EF | | .byte$37, $38, $37, $38, $37, $38, $b7, $38 |
| $39F7 | | .byte$39, $00, $1a, $1b, $1c, $00, $36, $37 |
| $39FF | | .byte$38, $37, $38, $37, $38, $37, $38, $37 |
| $3A07 | | .byte$38, $39, $80 |
| $3A0A | | .fill16, $00 |
| $3A1A | | .byte$1a, $1b, $1b, $1c, $00, $36, $39, $36 |
| $3A22 | | .byte$b7, $38, $39, $00, $1a, $1b, $1c, $00 |
| $3A2A | | .byte$36, $39, $36, $37, $38, $37, $38, $39 |
| $3A32 | | level_11.byte$80; x-ref: $1E5B |
| $3A33 | | .fill13, $00 |
| $3A40 | | .byte$fd, $ff |
| $3A42 | | .fill14, $00 |
| $3A50 | | .byte$fe, $ff |
| $3A52 | | .fill14, $00 |
| $3A60 | | .fill8, $0e |
| $3A68 | | .fill8, $10 |
| $3A70 | | .byte$0d, $0a, $0b, $0c, $0d, $0f, $0f, $0f |
| $3A78 | | .byte$23, $24, $24, $24, $25, $81, $02, $03 |
| $3A80 | | .byte$23, $24, $24, $25, $36, $b7, $38, $39 |
| $3A88 | | .byte$23, $24, $25, $87, $08, $09, $23, $24 |
| $3A90 | | .byte$24, $24, $24, $24, $25, $a9, $2a, $2b |
| $3A98 | | .byte$23, $24, $24, $25, $36, $b7, $38, $39 |
| $3AA0 | | .byte$23, $24, $24, $25, $8f, $0f, $0f, $23 |
| $3AA8 | | .byte$24, $24, $24, $24, $25, $a9, $2a, $2b |
| $3AB0 | | .byte$23, $24, $24, $25, $36, $b7, $38, $39 |
| $3AB8 | | .byte$23 |
| $3AB9 | | .fill11, $24 |
| $3AC4 | | .byte$25, $81, $02, $03, $23, $24, $24, $25 |
| $3ACC | | .byte$36, $b7, $38, $39, $23, $24, $24, $25 |
| $3AD4 | | .byte$29, $aa, $2b, $23, $24, $25, $07, $08 |
| $3ADC | | .byte$09, $8f, $0f, $0f, $23, $24, $24, $25 |
| $3AE4 | | .byte$36, $b7, $38, $39, $23, $24, $24, $25 |
| $3AEC | | .byte$81, $02, $03, $23, $24, $24, $24, $24 |
| $3AF4 | | .byte$25, $8f, $0f, $0f, $23, $24, $24, $25 |
| $3AFC | | .byte$36, $b7, $38, $39, $23, $24, $24, $25 |
| $3B04 | | .byte$29, $2a, $2b, $0f, $0f, $0f, $0f, $0f |
| $3B0C | | .byte$0f, $0f, $23, $24, $24, $25, $00, $04 |
| $3B14 | | .byte$05, $06, $04, $05, $06, $04, $05, $06 |
| $3B1C | | .byte$04, $05, $06, $0d, $00, $00 |
| $3B22 | | level_12.fill14, $00; x-ref: $1E5C |
| $3B30 | | .byte$fd, $ff |
| $3B32 | | .fill14, $00 |
| $3B40 | | .byte$fe, $ff |
| $3B42 | | .fill14, $00 |
| $3B50 | | .byte$2c, $2c, $2c, $2c, $2c, $ac, $2c, $2c |
| $3B58 | | .byte$2d, $2d, $2d, $2d, $2d, $ad, $2d, $2d |
| $3B60 | | .byte$2e, $2e, $2e, $2e, $2e, $2e, $ae, $2e |
| $3B68 | | .byte$2f, $2f, $2f, $2e, $2d, $ae, $2f, $2f |
| $3B70 | | .byte$2f, $2f, $2f, $2e, $2d, $ae, $2f, $2f |
| $3B78 | | .byte$2f, $2f, $2f, $2f, $af, $2f, $30, $30 |
| $3B80 | | .byte$30, $30, $30, $b0, $2f, $2f, $2e, $2e |
| $3B88 | | .byte$2e, $2e, $2e, $ae, $2f, $30, $30, $30 |
| $3B90 | | .byte$30, $30, $30, $2f, $2e, $2d, $2d, $ae |
| $3B98 | | .byte$2f, $30, $30, $30, $30, $2f, $2e, $2d |
| $3BA0 | | .byte$2c, $2c, $2d, $ae, $2f, $30, $30, $30 |
| $3BA8 | | .byte$30, $30, $2f, $2e, $2d, $ae, $2f, $30 |
| $3BB0 | | .byte$30, $b0, $30, $2f, $2e, $2e, $2e, $2e |
| $3BB8 | | .byte$ae, $2e, $2f, $2e, $2e, $ae, $2e, $2d |
| $3BC0 | | .byte$2e, $2e, $2e, $2e, $2e, $ae, $2f, $30 |
| $3BC8 | | .byte$30, $30, $30, $b0, $30, $2f, $2e, $2e |
| $3BD0 | | .byte$2e, $2e, $2e, $ae, $2f, $30, $30, $30 |
| $3BD8 | | .byte$30, $30, $b0, $2f, $30, $30, $30, $30 |
| $3BE0 | | .byte$2f, $ae, $2f, $30, $30, $30, $b0, $30 |
| $3BE8 | | .byte$2f, $2f, $2f, $2f, $2f, $2e, $2e, $2e |
| $3BF0 | | .byte$ad, $2e, $2d, $2c, $2c, $ac, $2c, $2c |
| $3BF8 | | .byte$2e, $2e, $2e, $2e, $ae, $2e, $30, $30 |
| $3C00 | | .byte$30, $30, $30, $30, $30, $2f, $30, $30 |
| $3C08 | | .byte$30, $30, $af, $2e, $30, $30, $30, $30 |
| $3C10 | | .byte$2f, $2e, $2d, $2c, $2d, $2e, $2d, $2e |
| $3C18 | | .byte$2f, $2f, $2f, $2e, $2d, $ae, $2f, $30 |
| $3C20 | | .byte$30, $30, $b0, $30, $2f, $2f, $2f, $2f |
| $3C28 | | .byte$2e, $2f, $2e, $2d, $2e, $2f, $2f, $2f |
| $3C30 | | .byte$2f, $2e, $af, $2f, $2f, $2e, $2e, $ae |
| $3C38 | | .byte$2e, $2e, $2d, $2d, $2d, $2d, $ad, $2d |
| $3C40 | | .byte$2c, $2d, $2d, $2d, $2d, $ad, $2d, $2d |
| $3C48 | | .fill8, $2c |
| $3C50 | | .byte$80, $00 |
| $3C52 | | level_13.fill14, $00; x-ref: $1E5D |
| $3C60 | | .byte$fd, $ff |
| $3C62 | | .fill14, $00 |
| $3C70 | | .byte$fe, $ff |
| $3C72 | | .fill14, $00 |
| $3C80 | | .byte$1a, $1b, $1b, $1c, $00, $00, $36, $37 |
| $3C88 | | .byte$38, $37, $38, $37, $38, $b7, $38, $39 |
| $3C90 | | .byte$00, $1a, $1b, $1c, $00, $36, $37, $38 |
| $3C98 | | .byte$37, $38, $37, $38, $b7, $38, $39, $00 |
| $3CA0 | | .byte$1a, $1b, $1c, $00, $36, $37, $38, $37 |
| $3CA8 | | .byte$38, $37, $38, $37, $38, $b7, $38, $39 |
| $3CB0 | | .byte$00, $1a, $1b, $1c, $00, $36, $37, $38 |
| $3CB8 | | .byte$37, $38, $37, $38, $39 |
| $3CBD | | .fill11, $00 |
| $3CC8 | | .byte$12, $13, $14, $15, $b1, $31, $16, $17 |
| $3CD0 | | .byte$18, $19, $b1, $31, $12, $13, $14, $15 |
| $3CD8 | | .byte$b1, $31, $16, $17, $18, $19, $31, $31 |
| $3CE0 | | .byte$80, $00, $00, $00, $00, $00, $00, $00 |
| $3CE8 | | .fill10, $0d |
| $3CF2 | | .byte$1d, $1e, $1e, $1e, $1f, $0d, $0d, $36 |
| $3CFA | | .byte$37, $38, $37, $38, $37, $38, $39, $36 |
| $3D02 | | .byte$37, $38, $39, $36, $37, $38, $39, $80 |
| $3D0A | | .fill10, $00 |
| $3D14 | | .byte$80, $00, $00, $00, $1a, $1b, $1b, $1c |
| $3D1C | | .byte$00, $36, $37, $38, $37, $38, $37, $38 |
| $3D24 | | .byte$37, $b8, $39, $00, $1d, $1e, $1e, $1f |
| $3D2C | | .byte$00, $36, $39, $36, $37, $38, $39, $36 |
| $3D34 | | .byte$37, $38, $37, $38, $39, $80 |
| $3D3A | | .fill10, $00 |
| $3D44 | | .byte$80, $00, $00, $00, $1a, $1b, $1c, $00 |
| $3D4C | | .byte$04, $05, $06, $00, $00, $00, $00, $00 |
| $3D54 | | .byte$80, $00, $00, $00, $1a, $1b, $1c, $00 |
| $3D5C | | .byte$0a, $0b, $0c, $00, $00, $00, $00, $00 |
| $3D64 | | .byte$80, $00, $00, $00, $1a, $1b |
| $3D6A | | level_14.byte$1c, $00, $04, $05, $06; x-ref: $1E5E |
| $3D6F | | .fill9, $00 |
| $3D78 | | .byte$fd, $ff |
| $3D7A | | .fill14, $00 |
| $3D88 | | .byte$fe, $ff |
| $3D8A | | .fill14, $00 |
| $3D98 | | .byte$8d, $0d, $0d, $0d, $0d, $0d, $0d, $0d |
| $3DA0 | | .byte$8e, $0e, $0e, $0e, $0e, $0e, $0e, $0e |
| $3DA8 | | .byte$8f, $0f, $0f, $0f, $0f, $0f, $0f, $0f |
| $3DB0 | | .byte$90, $10, $10, $10, $10, $10, $10, $10 |
| $3DB8 | | .byte$91, $11, $11, $11, $11, $11, $11, $11 |
| $3DC0 | | .byte$23 |
| $3DC1 | | .fill138, $a4 |
| $3E4B | | .byte$24, $24, $24, $24, $25, $91, $11, $11 |
| $3E53 | | .byte$11, $11, $11, $11, $11, $90, $10, $10 |
| $3E5B | | .byte$10, $10, $10, $10, $10, $8f, $0f, $0f |
| $3E63 | | .byte$0f, $0f, $0f, $0f, $0f, $8e, $0e, $0e |
| $3E6B | | .byte$0e, $0e, $0e, $0e, $0e, $8d, $0d, $0d |
| $3E73 | | .byte$0d, $0d, $0d, $0d, $0d, $80, $00 |
| $3E7A | | level_15.fill14, $00; x-ref: $1E5F |
| $3E88 | | .byte$fd, $ff |
| $3E8A | | .fill14, $00 |
| $3E98 | | .byte$fe, $ff |
| $3E9A | | .fill11, $00 |
| $3EA5 | | .byte$80, $00, $00, $32, $32, $32, $32, $32 |
| $3EAD | | .byte$b2, $32, $32, $33, $33, $33, $33, $34 |
| $3EB5 | | .byte$34, $34, $b3, $34, $34, $33, $33, $33 |
| $3EBD | | .byte$33, $32, $33, $34, $35, $35, $34, $35 |
| $3EC5 | | .byte$b4, $33, $32, $33, $33, $33, $33, $33 |
| $3ECD | | .byte$b2, $33, $34, $34, $34, $b4, $34, $35 |
| $3ED5 | | .byte$35, $35, $34, $33, $32, $b1, $32, $33 |
| $3EDD | | .byte$33, $33, $33, $20, $21, $22, $00, $04 |
| $3EE5 | | .byte$05, $06, $04, $05, $06, $04, $05, $06 |
| $3EED | | .byte$04, $05, $06, $80 |
| $3EF1 | | .fill15, $00 |
| $3F00 | | .byte$b1, $31, $31, $31, $31, $31, $31, $31 |
| $3F08 | | .byte$1a, $1b, $1c, $31, $31, $31, $36, $39 |
| $3F10 | | .byte$b1, $31, $31, $31, $1a, $1b, $1c, $31 |
| $3F18 | | .byte$36, $37, $38, $39, $b1, $31, $31, $31 |
| $3F20 | | .byte$1a, $1b, $1c, $31, $31, $36, $37, $38 |
| $3F28 | | .byte$39, $31, $31, $31, $1a, $1b, $1c, $31 |
| $3F30 | | .byte$36, $37, $38, $37, $38, $39, $b1, $31 |
| $3F38 | | .byte$1a, $1b, $1c, $b1 |
| $3F3C | | .fill8, $31 |
| $3F44 | | .byte$1a, $1b, $1c, $31, $31, $36, $39, $b1 |
| $3F4C | | .byte$31, $31, $31, $31, $1a, $1b, $1c, $31 |
| $3F54 | | .byte$31, $31, $31, $31, $80 |
| $3F59 | | .fill15, $00 |
| $3F68 | | .byte$36, $39, $80 |
| $3F6B | | .fill13, $00 |
| $3F78 | | .byte$36, $b9, $00, $1a, $1b, $1b, $1c, $00 |
| $3F80 | | .byte$36, $37, $38, $37, $38, $37, $38, $39 |
| $3F88 | | .byte$80, $00, $00, $00, $00, $00, $00, $00 |
| $3F90 | | .byte$8d, $0d, $0d, $0d, $0d, $0d, $0d, $0d |
| $3F98 | | .byte$1d, $1e, $1e, $1f, $00, $36, $37, $38 |
| $3FA0 | | .byte$37, $38, $37, $38, $37, $38, $37, $38 |
| $3FA8 | | .byte$37, $38, $39, $80 |
| $3FAC | | .fill12, $00 |
| $3FB8 | | .byte$1d, $1e, $1e, $1f, $00, $07, $08, $09 |
| $3FC0 | | .byte$01, $02, $03, $07, $08, $09, $01, $02 |
| $3FC8 | | .byte$03, $07, $08, $09, $80 |
| $3FCD | | .fill11, $00 |
| $3FD8 | | padding.fill16, $00 |
| $3FE8 | | .byte$fd, $ff |
| $3FEA | | .fill14, $00 |
| $3FF8 | | .byte$fe, $ff, $00, $00, $00, $00, $e1, $06 |