| ;=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| ; |
| ; Auto-generated by Regenerator 2000 v0.9.17 |
| ; https://github.com/ricardoquesada/regenerator2000 |
| ; |
| ; Exported from: c128_hero_is_back.regen2000proj |
| ; |
| ; Assemble with 64tass: |
| ; 64tass -o c128_hero_is_back.prg c128_hero_is_back.asm |
| ; |
| ;=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
|
| ; EXTERNAL LABELS |
| ; zpf_ = Zero Page Field |
| ; zpa_ = Zero Page Absolute Address |
| ; zpp_ = Zero Page Pointer |
| ; f_ = Field |
| ; a_ = Absolute Address |
| ; p_ = Pointer |
| ; L_ = Other / User-defined |
|
| zp_work0 = $02 ; x-ref: $1CB5, $1CE8, $1F37, $1FDF, $2031, ... |
| zp_work1 = $03 ; x-ref: $1CBA, $1CE2, $1F3B, $1FE3, $2035, ... |
| zp_work2 = $04 ; x-ref: $1F4F, $1FF7, $4A1E, $4A2C, $4A2E, ... |
| zp_work3 = $05 ; x-ref: $1F5A, $2002, $4A22, $4A32, $4A3C, ... |
| zp_ptr_aux1_lo = $06 ; x-ref: $4B78, $4BAC, $4BF2, $4BF7, $4D3A, ... |
| zp_ptr_aux1_hi = $07 ; x-ref: $4B7C, $4BF9, $4BFD, $4D3F, $69F4, ... |
| zp_ptr_aux2_lo = $08 ; x-ref: $4B80, $4BB9, $4BC7, $4BFF, $4C04, ... |
| zp_ptr_aux2_hi = $09 ; x-ref: $4B84, $4C06, $4C0A, $69FC, $6A3B, ... |
| zp_ptr_aux3_lo = $0a ; x-ref: $4B88, $4BCC, $4C0C, $4C11 |
| zp_ptr_aux3_hi = $0b ; x-ref: $4B8C, $4C13, $4C17 |
| zp_ptr_aux4_lo = $0c ; x-ref: $4B90, $4BB7, $4C19, $4C1E |
| zp_ptr_aux4_hi = $0d ; x-ref: $4B94, $4C20, $4C24 |
| zp_temp_pixel_y = $1b ; x-ref: $7258, $727F, $72B3, $72F5, $7361, ... |
| zp_ptr_map_lo = $1c ; x-ref: $722E, $7237, $7251, $7270, $72A4, ... |
| zp_ptr_map_hi = $1d ; x-ref: $4A26, $4A5A, $4A5C, $4AE8, $7233, ... |
| zp_temp_x = $1e ; x-ref: $4A4F, $4A54, $4A78, $4A88, $4A8A, ... |
| zp_temp_y = $1f ; x-ref: $4AA2, $4AAD, $4ABE, $4AC0, $4AC7, ... |
| zpf_sort_order = $20 ; x-ref: $53F5, $5411, $541D, $542B, $5444, ... |
| zpf_sort_order_1 = $21 ; x-ref: $540C, $541B, $541F, $5426, $547E |
| zp_sort_order_2 = $22 ; x-ref: $54B8 |
| zp_sort_order_3 = $23 ; x-ref: $54F2 |
| zp_sort_order_4 = $24 ; x-ref: $552C |
| zp_sort_order_5 = $25 ; x-ref: $5566 |
| zp_sort_order_6 = $26 ; x-ref: $55A0 |
| zp_sort_order_7 = $27 ; x-ref: $55DA |
| zp_spr_y_pos = $0033 ; x-ref: $4C2D, $53F9, $540E, $5413, $5428, ... |
| zp_mux_y_bomb = $34 ; x-ref: $81B1, $81F4 |
| zp_mux_y_fire = $35 ; x-ref: $792E, $7954 |
| zp_mux_y_explode = $36 ; x-ref: $7076, $708E |
| zp_mux_y_entities = $37 ; x-ref: $7793, $77B2 |
| zp_screen_dirty = $0045 ; x-ref: $4C38, $4C6A, $781C, $7AEE, $8397 |
| zp_spr_x_lo = $46 ; x-ref: $544B, $5485, $54BF, $54F9, $5533, ... |
| zp_mux_x_lo_bomb = $47 ; x-ref: $81D6, $81E3 |
| zp_mux_x_lo_fire = $48 ; x-ref: $7946 |
| zp_mux_x_lo_explode = $49 ; x-ref: $707F |
| zp_mux_x_lo_entities = $4a ; x-ref: $77A3 |
| zp_mux_x_lo_hazard = $58 ; x-ref: $780D, $7ADF, $8388 |
| zp_spr_x_hi = $59 ; x-ref: $545A, $5494, $54CE, $5508, $5542, ... |
| zp_mux_x_hi_bomb = $5a ; x-ref: $81DC, $81E7 |
| zp_mux_x_hi_fire = $5b ; x-ref: $794D |
| zp_mux_x_hi_explode = $5c ; x-ref: $7086 |
| zp_mux_x_hi_entities = $5d ; x-ref: $77AA |
| zp_mux_x_hi_hazard = $6b ; x-ref: $7814, $7AE6, $838F |
| zp_spr_frame = $6c ; x-ref: $5450, $548A, $54C4, $54FE, $5538, ... |
| zp_mux_frame_bomb = $6d ; x-ref: $820F, $8218 |
| zp_mux_frame_fire = $6e ; x-ref: $7967 |
| zp_mux_frame_explode = $6f ; x-ref: $7093 |
| zp_mux_frame_entities = $70 ; x-ref: $77B7 |
| zp_mux_frame_hazard = $7e ; x-ref: $7820, $7AF3, $839B |
| zp_spr_color = $007f ; x-ref: $4C79, $50AC, $5455, $548F, $54C9, ... |
| zp_spr_color_p2 = $0080 ; x-ref: $4C7E, $50AF |
| zp_dynamite_timer = $81 ; x-ref: $7844 |
| zp_screen_color = $82 ; x-ref: $6F16 |
| zp_mux_color_entities = $83 ; x-ref: $77BC |
| zp_spr_color_extra = $0091 ; x-ref: $50B2, $7824, $7AF7, $839F |
| zp_spr_expand_x = $92 ; x-ref: $53FD, $5466, $54A0, $54DA, $5514, ... |
| zp_mux_flip_fire = $94 ; x-ref: $7972 |
| zp_spr_priority = $a5 ; x-ref: $53FF, $5472, $54AC, $54E6, $5520, ... |
| zp_dynamite_active = $a7 ; x-ref: $7848 |
| zp_current_device = $ba ; x-ref: $20C8 |
| zp_init_flag = $d8 ; x-ref: $20D7 |
| zp_math_temp = $ed ; x-ref: $21A5, $21A9, $21AC, $21B2, $21B5, ... |
| zp_ptr_text_lo = $f5 ; x-ref: $3777, $3785, $37A4, $37B4, $37CE, ... |
| zp_ptr_text_hi = $f6 ; x-ref: $3789, $37A8, $37B8, $37D2, $60A1 |
| zp_ptr_screen_lo = $f7 ; x-ref: $378B, $3790, $37C3, $60A5 |
| zp_ptr_screen_hi = $f8 ; x-ref: $3792, $3796, $60A9 |
| zp_ptr_src_lo = $00fb ; x-ref: $1C59, $1C69, $1C86, $1C94, $1CAB, ... |
| zp_ptr_src_hi = $00fc ; x-ref: $1C5E, $1C6F, $1C89, $1C9A, $1CB0, ... |
| zp_ptr_dst_lo = $fd ; x-ref: $1CBE, $1CD2, $1CDA, $2083, $36B6, ... |
| zp_ptr_dst_hi = $fe ; x-ref: $1CC2, $1CDE, $2085, $36BC, $36D3, ... |
| zp_temp = $ff ; x-ref: $1C63, $1C65, $1C75, $1C8C, $1C8E, ... |
| IRQ_VECTOR_LO = $0314 ; x-ref: $2150, $2179, $217F, $2196 |
| IRQ_VECTOR_HI = $0315 ; x-ref: $2153, $2182, $219B |
| SCREEN_RAM = $0400 ; x-ref: $3648, $4B3E, $4C93, $8C17 |
| SCREEN_RAM_R1C0 = $0428 ; x-ref: $8C18 |
| SCREEN_RAM_R1C8 = $0430 ; x-ref: $69EE, $69F2 |
| SCREEN_RAM_R1C15 = $0437 ; x-ref: $6D70, $6D74 |
| SCREEN_RAM_R2C0 = $0450 ; x-ref: $8C19 |
| SCREEN_RAM_R3C0 = $0478 ; x-ref: $8C1A |
| SCREEN_RAM_R3C8 = $0480 ; x-ref: $6D85, $6D89 |
| SCREEN_RAM_R4C0 = $04a0 ; x-ref: $8C1B |
| SCREEN_RAM_R4C10 = $04aa ; x-ref: $4B41, $4C9F |
| SCREEN_RAM_R5C0 = $04c8 ; x-ref: $8C1C |
| SCREEN_RAM_R6C0 = $04f0 ; x-ref: $8C1D |
| SCREEN_RAM_R6C4 = $04f4 ; x-ref: $6613, $6617 |
| SCREEN_RAM_R6C10 = $04fa ; x-ref: $364B |
| SCREEN_RAM_R7C0 = $0518 ; x-ref: $8C1E |
| SCREEN_RAM_R7C6 = $051e ; x-ref: $5ED6, $5EDA |
| SCREEN_RAM_R7C32 = $0538 ; x-ref: $6977, $697B |
| SCREEN_RAM_R8C0 = $0540 ; x-ref: $8C1F |
| SCREEN_RAM_R8C6 = $0546 ; x-ref: $5EEB, $5EEF |
| SCREEN_RAM_R8C20 = $0554 ; x-ref: $4B44, $4CAB |
| SCREEN_RAM_R9C0 = $0568 ; x-ref: $8C20 |
| SCREEN_RAM_R10C0 = $0590 ; x-ref: $8C21 |
| SCREEN_RAM_R11C0 = $05b8 ; x-ref: $8C22 |
| SCREEN_RAM_R11C11 = $05c3 ; x-ref: $698C, $6990 |
| SCREEN_RAM_R12C0 = $05e0 ; x-ref: $8C23 |
| SCREEN_RAM_R12C6 = $05e6 ; x-ref: $5F00, $5F04 |
| SCREEN_RAM_R12C10 = $05ea ; x-ref: $6EC1, $6EC5 |
| SCREEN_RAM_R12C13 = $05ed ; x-ref: $6680, $6684, $6EEB, $6EEF |
| SCREEN_RAM_R12C20 = $05f4 ; x-ref: $364E |
| SCREEN_RAM_R12C30 = $05fe ; x-ref: $4B47, $4CB7 |
| SCREEN_RAM_R13C0 = $0608 ; x-ref: $8C24 |
| SCREEN_RAM_R13C5 = $060d ; x-ref: $6B64 |
| SCREEN_RAM_R13C6 = $060e ; x-ref: $5F15, $5F19 |
| SCREEN_RAM_R14C0 = $0630 ; x-ref: $8C25 |
| SCREEN_RAM_R15C0 = $0658 ; x-ref: $8C26 |
| SCREEN_RAM_R16C0 = $0680 ; x-ref: $7A4B, $7A55, $7A5F, $7A69, $8C27 |
| SCREEN_RAM_R17C23 = $06bf ; x-ref: $6B7A |
| SCREEN_RAM_R18C1 = $06d1 ; x-ref: $62BF, $62C3 |
| SCREEN_RAM_R18C7 = $06d7 ; x-ref: $829C, $82A4 |
| SCREEN_RAM_R18C9 = $06d9 ; x-ref: $6628, $662C |
| SCREEN_RAM_R18C30 = $06ee ; x-ref: $3651 |
| SCREEN_RAM_R19C4 = $06fc ; x-ref: $520D, $5227 |
| SCREEN_RAM_R19C5 = $06fd ; x-ref: $5210, $522C |
| SCREEN_RAM_R19C25 = $0711 ; x-ref: $6352, $6368 |
| SCREEN_RAM_R20C5 = $0725 ; x-ref: $5213, $5231 |
| SCREEN_RAM_R20C25 = $0739 ; x-ref: $6357, $636B |
| SCREEN_RAM_R22C4 = $0774 ; x-ref: $62E7, $62EB |
| SCREEN_RAM_R22C12 = $077c ; x-ref: $636F, $6373 |
| SCREEN_RAM_R23C21 = $07ad ; x-ref: $69BA, $69BE |
| SCREEN_RAM_R24C1 = $07c1 ; x-ref: $630C, $6310 |
| SCREEN_RAM_R24C16 = $07d0 ; x-ref: $6321, $6325 |
| SCREEN_RAM_R24C35 = $07e3 ; x-ref: $6336, $633A |
| SPRITE_PTR_0 = $07f8 ; x-ref: $5452, $565A, $64DB, $66C9, $6BB2, ... |
| SPRITE_PTR_1 = $07f9 ; x-ref: $548C, $56EC, $6BB6, $6C98 |
| SPRITE_PTR_2 = $07fa ; x-ref: $54C6, $577E, $6BBA, $6C9C |
| SPRITE_PTR_3 = $07fb ; x-ref: $5500, $5810, $6BBE, $6CA0 |
| SPRITE_PTR_4 = $07fc ; x-ref: $553A, $58A2, $6BC2, $6CA4 |
| SPRITE_PTR_5 = $07fd ; x-ref: $5574, $5934, $6CA8 |
| SPRITE_PTR_6 = $07fe ; x-ref: $55AE, $59C6 |
| SPRITE_PTR_7 = $07ff ; x-ref: $55E8, $5A58 |
| game_flags = $0a04 ; x-ref: $20D9, $20DE |
| cave_data_buffer = $1300 ; x-ref: $1CBC, $1CC0 |
| VIC_RAM_CONFIG = $d506 ; C128: RAM Configuration Register (RCR) ; x-ref: $1CC6, $1CF3 |
| COLOR_RAM = $d800 ; x-ref: $3655, $4C99 |
| COLOR_RAM_R1C0 = $d828 ; x-ref: $5071, $507D |
| COLOR_RAM_R1C8 = $d830 ; x-ref: $69F6, $69FA |
| COLOR_RAM_R4C10 = $d8aa ; x-ref: $4CA5 |
| COLOR_RAM_R5C0 = $d8c8 ; x-ref: $6048 |
| COLOR_RAM_R6C0 = $d8f0 ; x-ref: $5080, $508C |
| COLOR_RAM_R6C10 = $d8fa ; x-ref: $3658 |
| COLOR_RAM_R8C20 = $d954 ; x-ref: $4CB1 |
| COLOR_RAM_R11C0 = $d9b8 ; x-ref: $508F, $509B, $6A45, $6A49 |
| COLOR_RAM_R12C20 = $d9f4 ; x-ref: $365B |
| COLOR_RAM_R12C30 = $d9fe ; x-ref: $4CBD |
| COLOR_RAM_R13C0 = $da08 ; x-ref: $6052 |
| COLOR_RAM_R17C0 = $daa8 ; x-ref: $605C |
| COLOR_RAM_R18C30 = $daee ; x-ref: $365E |
| COLOR_RAM_R20C5 = $db25 ; x-ref: $62D6 |
| COLOR_RAM_R22C24 = $db88 ; x-ref: $62FE |
| COLOR_RAM_R24C1 = $dbc1 ; x-ref: $6345 |
| room_data_ptrs_lo = $e000 ; $E000 Reset Code ; x-ref: $4B23 |
| room_data_ptrs_hi = $e001 ; x-ref: $4B28 |
| color_attr_row = $e318 ; x-ref: $4CE9 |
| color_attr_remapped = $e340 ; x-ref: $4CF7 |
| screen_buf_q1 = $e368 ; x-ref: $4C90 |
| screen_buf_q2 = $e412 ; x-ref: $4C9C |
| screen_buf_q3 = $e4bc ; x-ref: $4CA8 |
| screen_buf_q4 = $e566 ; x-ref: $4CB4 |
| color_buf_q1 = $e610 ; x-ref: $4C96, $4E32, $4E53 |
| color_buf_0x28 = $e638 ; x-ref: $4E68 |
| color_buf_q2 = $e6ba ; x-ref: $4CA2 |
| color_buf_0x100 = $e710 ; x-ref: $4E38 |
| color_buf_mid_clear = $e738 ; x-ref: $4E6B |
| color_buf_q3 = $e764 ; x-ref: $4CAE |
| color_buf_0x1b8 = $e7c8 ; x-ref: $4E45 |
| color_buf_q4 = $e80e ; x-ref: $4CBA |
| color_buf_0x228 = $e838 ; x-ref: $4E71 |
| color_buf_last_row = $e890 ; x-ref: $4E59 |
| KERNAL_IRQ_DEFAULT = $ea31 ; x-ref: $2194, $2199 |
| screen_slot_table = $ef78 ; x-ref: $49F0, $4E1A, $505E |
| MMU_CONFIG = $ff00 ; C128: MMU Configuration Register ; x-ref: $1CCB, $1CEE, $20E3, $2160, $21A0, ... |
| KERNAL_SETBNK = $ff68 ; $FF68 (jmp) setbnk ; x-ref: $1C54, $52E0, $5307 |
| KERNAL_READSS = $ffb7 ; $FFB7 (jmp) readss Read I/O Status Word ; x-ref: $20B3 |
| KERNAL_SETLFS = $ffba ; $FFBA (jmp) setlfs Set Logical File Parameters ; x-ref: $20D0 |
| KERNAL_SETNAM = $ffbd ; $FFBD (jmp) setnam Set Filename ; x-ref: $206A, $207B, $208C, $20A3 |
| KERNAL_OPENi = $ffc0 ; $FFC0 (ind) iopen Open Vector [efbd] ; x-ref: $2094, $20AB |
| KERNAL_CLOSEi = $ffc3 ; $FFC3 (ind) iclose Close Vector [f188] ; x-ref: $2099, $20C0 |
| KERNAL_CHKINi = $ffc6 ; $FFC6 (ind) ichkin Set Input [f106] ; x-ref: $20B0 |
| KERNAL_CLRCHi = $ffcc ; $FFCC (ind) iclrch Restore I/O Vector [f226] ; x-ref: $209C, $20C3 |
| KERNAL_BASINi = $ffcf ; $FFCF (ind) ibasin Input Vector, chrin [ef06] ; x-ref: $20B8 |
| KERNAL_LOADSP = $ffd5 ; $FFD5 (jmp) loadsp Load RAM From Device ; x-ref: $2078 |
| KERNAL_SAVESP = $ffd8 ; $FFD8 (jmp) savesp Save RAM To Device ; x-ref: $2089 |
|
| ; ENUMS |
| ; Enum: GameState |
| GameState = { |
| GAMEPLAY: $00, |
| INTRO: $01, |
| CURTAIN_ANIMATION: $02, |
| MAIN_MENU: $03, |
| GAME_OVER: $04, |
| CREDITS: $05, |
| GAME_COMPLETE: $06 |
| } |
| ; Enum: MenuOptions |
| MenuOptions = { |
| START: $00, |
| DYNAMITE: $01, |
| BEST_HEROES: $02, |
| PLAY_LEVELS: $03, |
| CREDITS: $04 |
| } |
| ; Enum: VicIIColors |
| VicIIColors = { |
| BLACK: $00, |
| WHITE: $01, |
| RED: $02, |
| CYAN: $03, |
| PURPLE: $04, |
| GREEN: $05, |
| BLUE: $06, |
| YELLOW: $07, |
| ORANGE: $08, |
| BROWN: $09, |
| LIGHT_RED: $0a, |
| DARK_GREY: $0b, |
| GREY: $0c, |
| LIGHT_GREEN: $0d, |
| LIGHT_BLUE: $0e, |
| LIGHT_GREY: $0f |
| } |
|
| $1C01 | | .worda_1C0B; 10 SYS 7181 |
| $1C03 | | .word$000a |
| $1C05 | | .byte$9e, $37, $31, $38, $31 |
| a_1C0B =*+$01 ; x-ref: $1C01 |
| $1C0A | | .word$0000; End of BASIC |
| $1C0C | | .byte$00 |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| ; Main game loop. Runs initialization per frame, waits for the raster beam |
| ; to reach line $FB (bottom of visible screen), then dispatches the current |
| ; game state handler. Loops forever. |
| ; |
| ; Inputs: None |
| ; Outputs: None |
| ; Side Effects: Drives the entire game; calls frame setup, raster sync, |
| ; and game-state dispatch each iteration. |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| $1C0D | 20 d5 20 | startjsrinit_game; frame setup (MMU bank, disable CIAs, etc.) |
| main_loop_raster_wait |
| $1C10 | a9 fb | lda#$fb; target raster line = $FB (251) ; x-ref: $1C1A |
| $1C12 | cd 12 d0 | b_1C12cmp$d012; wait until raster beam reaches line $FB ; x-ref: $1C15 Raster Position |
| $1C15 | d0 fb | bneb_1C12; not there yet, keep polling |
| $1C17 | 20 f5 20 | jsrgame_state_dispatch; game state dispatch (input, logic, rendering) |
| $1C1A | 4c 10 1c | jmpmain_loop_raster_wait; loop forever |
| ; Table of 20 word-sized entries (lo/hi interleaved). Each pair holds the RAM bank 1 start address where CAVEnn was loaded. Indexed by cave_index * 2. |
| $1C1D | | cave_addr_table.byte$00; x-ref: $1C6C, $1CA8 |
| ; High byte counterpart of cave_addr_table (same table, offset +1). |
| $1C1E | | cave_addr_table_hi.byte$00; x-ref: $1C72, $1CAD |
| ; End address lo for cave data. Actually cave_addr_table+2, i.e. the next cave's start address serves as the current cave's end. |
| $1C1F | | cave_end_table.byte$00; x-ref: $1CB2 |
| ; End address hi for cave data (cave_addr_table+3). 37 bytes of fill complete the 40-byte table (20 entries x 2 bytes). |
| $1C20 | | cave_end_table_hi.fill37, $00; x-ref: $1CB7 |
| ; Low byte of the final end address after all 20 cave files are loaded into bank 1 RAM. |
| $1C45 | | cave_data_end_lo.byte$00; x-ref: $1C97 |
| ; High byte of the final end address. Followed by the "CAVE" filename template string. |
| $1C46 | | cave_data_end_hi.byte$00; x-ref: $1C9D |
| | .encode |
| | .enc"none" |
| $1C47 | | .text"CAVE" |
| | .endencode |
| ; Tens digit ASCII char in the "CAVExx" filename string. Written by convert_byte_to_two_ascii_digits. |
| $1C4B | | cave_filename_tens.byte$58; x-ref: $1D04 |
| ; Units digit ASCII char in the "CAVExx" filename string. Written by convert_byte_to_two_ascii_digits. |
| $1C4C | | cave_filename_units.byte$58; x-ref: $1D01 |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| ; Loads all 20 cave data files (CAVE01–CAVE20) from disk into RAM bank 1, |
| ; starting at $2000. Records each file's load address in the cave_load_addrs |
| ; table at $1C1D for later lookup. Saves/restores zero page around the |
| ; operation. |
| ; |
| ; Inputs: None |
| ; Outputs: f_1C1D table filled with 20 address entries, a_1C45/a_1C46 = end addr |
| ; Side Effects: Disk I/O; loads 20 files into bank 1 RAM; zero page temporarily modified |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| $1C4D | 20 c4 5b | load_all_cave_datajsrrestore_zero_page; Save zero page to buffer ; x-ref: $6693 |
| $1C50 | a9 01 | lda#$01; Load from bank 0 |
| $1C52 | a2 00 | ldx#$00; Save to bank 1 |
| $1C54 | 20 68 ff | jsrKERNAL_SETBNK; Set I/O banks for LOAD; $FF68 (jmp) setbnk |
| $1C57 | a9 00 | lda#<cave_data_load_addr; Load address = $2000 (lo) |
| $1C59 | 8d fb 00 | sta@w zp_ptr_src_lo |
| $1C5C | a9 20 | lda#>cave_data_load_addr; Load address = $2000 (hi) |
| $1C5E | 8d fc 00 | sta@w zp_ptr_src_hi |
| $1C61 | a9 00 | lda#$00; Cave index = 0 |
| $1C63 | 85 ff | stazp_temp |
| $1C65 | a5 ff | b_1C65ldazp_temp; --- Loop: load each cave file --- ; x-ref: $1C92 |
| $1C67 | 0a | asla; Index * 2 for word table |
| $1C68 | aa | tax |
| $1C69 | ad fb 00 | lda@w zp_ptr_src_lo; Store load addr lo in table |
| $1C6C | 9d 1d 1c | stacave_addr_table,x |
| $1C6F | ad fc 00 | lda@w zp_ptr_src_hi; Store load addr hi in table |
| $1C72 | 9d 1e 1c | stacave_addr_table_hi,x |
| $1C75 | a5 ff | ldazp_temp; Cave number (0-based) |
| $1C77 | 18 | clc |
| $1C78 | 69 01 | adc#$01; Convert to 1-based for filename |
| $1C7A | 20 f7 1c | jsrconvert_byte_to_two_ascii_digits; Convert to 2-digit decimal -> "CAVExx" |
| $1C7D | a9 06 | lda#$06; Filename length = 6 ("CAVExx") |
| $1C7F | a2 47 | ldx#$47; Filename addr = $1C47 |
| $1C81 | a0 1c | ldy#$1c |
| $1C83 | 20 6a 20 | jsrload_file_to_addr; SETNAM + LOAD file from disk |
| $1C86 | 8e fb 00 | stx@w zp_ptr_src_lo; Update load addr with end-of-file (lo) |
| $1C89 | 8c fc 00 | sty@w zp_ptr_src_hi; Update load addr with end-of-file (hi) |
| $1C8C | e6 ff | inczp_temp; Next cave index |
| $1C8E | a5 ff | ldazp_temp |
| $1C90 | c9 14 | cmp#$14; All 20 caves loaded? |
| $1C92 | d0 d1 | bneb_1C65 |
| $1C94 | ad fb 00 | lda@w zp_ptr_src_lo; Store final end address (lo) |
| $1C97 | 8d 45 1c | stacave_data_end_lo |
| $1C9A | ad fc 00 | lda@w zp_ptr_src_hi; Store final end address (hi) |
| $1C9D | 8d 46 1c | stacave_data_end_hi |
| $1CA0 | 4c b7 5b | jmpsave_zero_page; Restore zero page and return |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| ; Copies cave/level data from banked RAM into the working buffer at $1300. |
| ; Uses the current cave index (a_60D9) to look up source address and end |
| ; address from tables at f_1C1D-f_1C20, then performs a byte-by-byte copy |
| ; with C128 bank switching (RAM bank via $D506, MMU config via $FF00). |
| ; |
| ; Inputs: a_60D9 = cave index (0-based) |
| ; Outputs: Cave data copied to $1300+ |
| ; Side Effects: Temporarily switches C128 RAM bank configuration |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| $1CA3 | ad d9 60 | load_cave_dataldacurrent_level; A = cave index ; x-ref: $6152 |
| $1CA6 | 0a | asla; index * 2 for word-sized table entries |
| $1CA7 | aa | tax |
| $1CA8 | bd 1d 1c | ldacave_addr_table,x; src addr lo from table |
| $1CAB | 85 fb | stazp_ptr_src_lo; store in ZP ptr $FB |
| $1CAD | bd 1e 1c | ldacave_addr_table_hi,x; src addr hi from table |
| $1CB0 | 85 fc | stazp_ptr_src_hi; store in ZP ptr $FC |
| $1CB2 | bd 1f 1c | ldacave_end_table,x; end addr lo |
| $1CB5 | 85 02 | stazp_work0; store in ZP $02 |
| $1CB7 | bd 20 1c | ldacave_end_table_hi,x; end addr hi |
| $1CBA | 85 03 | stazp_work1; store in ZP $03 |
| $1CBC | a9 00 | lda#<cave_data_buffer; dest addr lo = $00 |
| $1CBE | 85 fd | stazp_ptr_dst_lo; store in ZP ptr $FD |
| $1CC0 | a9 13 | lda#>cave_data_buffer; dest addr hi = $13 (dest=$1300) |
| $1CC2 | 85 fe | stazp_ptr_dst_hi; store in ZP ptr $FE |
| $1CC4 | a9 06 | lda#$06; select RAM bank for source data |
| $1CC6 | 8d 06 d5 | staVIC_RAM_CONFIG; Select RAM bank 6 for banked read; C128: RAM Configuration Register (RCR) |
| $1CC9 | a9 4e | lda#$4e; MMU: map banked RAM for reading |
| $1CCB | 8d 00 ff | staMMU_CONFIG; C128: MMU Configuration Register |
| $1CCE | a0 00 | ldy#$00 |
| $1CD0 | b1 fb | b_1CD0lda(zp_ptr_src_lo),y; read byte from banked source ; x-ref: $1CE4, $1CEA |
| $1CD2 | 91 fd | sta(zp_ptr_dst_lo),y; write byte to dest buffer |
| $1CD4 | e6 fb | inczp_ptr_src_lo; advance source ptr lo |
| $1CD6 | d0 02 | bneb_1CDA |
| $1CD8 | e6 fc | inczp_ptr_src_hi; advance source ptr hi on carry |
| $1CDA | e6 fd | b_1CDAinczp_ptr_dst_lo; advance dest ptr lo ; x-ref: $1CD6 |
| $1CDC | d0 02 | bneb_1CE0 |
| $1CDE | e6 fe | inczp_ptr_dst_hi; advance dest ptr hi on carry |
| $1CE0 | a5 fc | b_1CE0ldazp_ptr_src_hi; check if src hi == end hi ; x-ref: $1CDC |
| $1CE2 | c5 03 | cmpzp_work1 |
| $1CE4 | d0 ea | bneb_1CD0; not done yet, keep copying |
| $1CE6 | a5 fb | ldazp_ptr_src_lo; check if src lo == end lo |
| $1CE8 | c5 02 | cmpzp_work0 |
| $1CEA | d0 e4 | bneb_1CD0; not done yet, keep copying |
| $1CEC | a9 0e | lda#$0e; MMU: restore normal config |
| $1CEE | 8d 00 ff | staMMU_CONFIG; C128: MMU Configuration Register |
| $1CF1 | a9 04 | lda#$04; restore normal RAM config |
| $1CF3 | 8d 06 d5 | staVIC_RAM_CONFIG; Restore normal RAM config after bank copy; C128: RAM Configuration Register (RCR) |
| $1CF6 | 60 | rts |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| ; Converts a byte value (0-99) in A to two ASCII digit characters. |
| ; The tens digit is stored at a_1C4B and the units digit at a_1C4C, |
| ; which are the digit positions in the "CAVEXX" display string. |
| ; |
| ; Inputs: A = value to convert (0-99) |
| ; Outputs: a_1C4B = tens digit ASCII char, a_1C4C = units digit ASCII char |
| ; Side Effects: X is modified |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| convert_byte_to_two_ascii_digits |
| $1CF7 | a2 2f | ldx#$2f; X = '0'-1 (ASCII $30 - 1) ; x-ref: $1C7A |
| $1CF9 | 38 | sec; Prepare for repeated subtraction |
| $1CFA | e8 | b_1CFAinx; Increment tens digit char ; x-ref: $1CFD |
| $1CFB | e9 0a | sbc#$0a; Subtract 10 from value |
| $1CFD | b0 fb | bcsb_1CFA; Loop while value >= 10 |
| $1CFF | 69 3a | adc#$3a; Adjust remainder to ASCII units digit (+$30+$0A) |
| $1D01 | 8d 4c 1c | stacave_filename_units; Store units digit character |
| $1D04 | 8e 4b 1c | stxcave_filename_tens; Store tens digit character |
| $1D07 | 60 | rts |
| ; Transition active flag: $00 = inactive (skip update), nonzero = active, $FF = finished/aborted. |
| $1D08 | | transition_active.byte$00; x-ref: $1D44, $1E01, $1E11, $802A |
| ; Current pattern byte from the sequence table. Used as joystick override during state 0 transitions. |
| $1D09 | | transition_pattern.byte$00; x-ref: $1D77, $1DAD, $1DF5 |
| ; 16-bit transition countdown timer (low byte). Decremented each frame; when both bytes reach zero, the next sequence step triggers. |
| $1D0A | | transition_timer_lo.byte$00; x-ref: $1D80, $1D88, $1D8B, $1D9D, $1DC4, ... |
| ; 16-bit transition countdown timer (high byte). |
| $1D0B | | transition_timer_hi.byte$00; x-ref: $1D85, $1D8E, $1DA2, $1DC9, $1DDC, ... |
| ; Index into the transition sequence table (transition_seq_table). Advances by 2 for each (pattern, duration) pair. |
| $1D0C | | transition_seq_idx.byte$00; x-ref: $1DA7, $1DEA, $1DEF |
| ; Duration counter for the current sequence step. Decremented each frame; when zero, advances to next (pattern, duration) pair. |
| $1D0D | | transition_duration.byte$00; x-ref: $1DB3, $1DE5, $1DFB |
| ; Sequence table of (pattern, duration) byte pairs used during state 3 (cave init) transitions. Indexed by transition_seq_idx. |
| $1D0E | | transition_seq_table.byte$e7; x-ref: $1DAA, $1DF2 |
| ; Duration byte counterpart of transition_seq_table (same table, offset +1). Each pair: [pattern, duration]. |
| transition_seq_table_dur |
| $1D0F | | .byte$64, $e9, $1e, $e7, $9b, $e9, $1e, $e7; x-ref: $1DB0, $1DF8 |
| $1D17 | | .byte$e6, $eb, $2d, $ef, $0f, $eb, $32, $ff |
| $1D1F | | .byte$ff, $eb, $6e, $e5, $1e, $eb, $b4, $e7 |
| $1D27 | | .byte$ff, $e7, $b4, $e9, $1e, $e7, $3c, $ef |
| $1D2F | | .byte$19, $e7, $32, $e6, $3c, $e7, $78, $eb |
| $1D37 | | .byte$4b, $ef, $19, $eb, $9b, $ff, $ff, $e7 |
| $1D3F | | .byte$c8, $e7, $73, $eb, $ff |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| ; Manages timed transition sequences during game state changes (death, level |
| ; complete, etc.). Uses a 16-bit countdown timer (a_1D0A/a_1D0B) and a |
| ; sequence table at a_1D0E containing (pattern, duration) pairs. Each frame, |
| ; decrements the timer; when it expires, reloads with state-dependent values |
| ; and dispatches to the appropriate visual effect handler. |
| ; |
| ; Inputs: a_1D08 (active flag), a_20D3 (game state), a_3E80 (joystick) |
| ; Outputs: a_1D0A/a_1D0B (timer), a_1D09 (current pattern), a_1D0C (index) |
| ; Side Effects: Dispatches to state-specific effect routines; may reset SID |
| ; voices; advances sequence table pointer |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| update_transition_sequence |
| $1D44 | ad 08 1d | ldatransition_active; Check if transition is active ; x-ref: $2104 |
| $1D47 | d0 01 | bneb_1D4A; Exit if no active transition |
| $1D49 | 60 | rts |
| $1D4A | 20 89 3f | b_1D4Ajsrreset_keyboard_state; Reset sprite/collision flags ; x-ref: $1D47 |
| $1D4D | ad d3 20 | ldagame_state; Check game state for transition dispatch |
| $1D50 | c9 03 | cmp#GameState.MAIN_MENU; State 3 = special transition |
| $1D52 | d0 0c | bneb_1D60 |
| $1D54 | ad 80 3e | ldajoystick_state; Read joystick/input register |
| $1D57 | 29 1f | and#$1f; Check all direction + fire bits |
| $1D59 | c9 1f | cmp#$1f |
| $1D5B | f0 23 | beqb_1D80; All pressed? Skip to timer |
| $1D5D | 4c ff 1d | jmpabort_transition; Abort: mark transition finished |
| $1D60 | ad 80 3e | b_1D60ldajoystick_state; Read joystick/input register ; x-ref: $1D52 |
| $1D63 | 29 10 | and#$10; Check fire button (bit 4) |
| $1D65 | d0 06 | bneb_1D6D; Fire pressed: skip ahead |
| $1D67 | 20 55 1e | jsrsilence_all_channels; Reset SID voice state |
| $1D6A | 4c 5e 69 | jmpshow_main_menu; Jump to default handler |
| $1D6D | ad d3 20 | b_1D6Dldagame_state; Check game state again ; x-ref: $1D65 |
| $1D70 | c9 00 | cmp#GameState.GAMEPLAY |
| $1D72 | d0 0c | bneb_1D80; State 0: advance sequence |
| $1D74 | 20 e5 1d | jsradvance_sequence_step |
| $1D77 | ad 09 1d | ldatransition_pattern; Load current pattern from table |
| $1D7A | 8d 80 3e | stajoystick_state; Store as joystick override |
| $1D7D | 20 55 1e | jsrsilence_all_channels; Reset SID voice state |
| $1D80 | ad 0a 1d | b_1D80ldatransition_timer_lo; Check timer high byte ; x-ref: $1D5B, $1D72 |
| $1D83 | d0 03 | bneb_1D88; If nonzero, skip low-byte dec |
| $1D85 | ce 0b 1d | dectransition_timer_hi; Decrement timer high byte |
| $1D88 | ce 0a 1d | b_1D88dectransition_timer_lo; Decrement timer low byte ; x-ref: $1D83 |
| $1D8B | ad 0a 1d | ldatransition_timer_lo; Load timer low byte |
| $1D8E | 0d 0b 1d | oratransition_timer_hi; OR with high byte |
| $1D91 | f0 01 | beqb_1D94; Timer expired? Handle it |
| $1D93 | 60 | rts; Timer still running, return |
| $1D94 | ad d3 20 | b_1D94ldagame_state; Timer expired — dispatch by state ; x-ref: $1D91 |
| $1D97 | c9 03 | cmp#GameState.MAIN_MENU; State 3? |
| $1D99 | d0 23 | bneb_1DBE; No, check other states |
| $1D9B | a9 40 | lda#$40; Reload timer = $0B40 (2880 frames) |
| $1D9D | 8d 0a 1d | statransition_timer_lo |
| $1DA0 | a9 0b | lda#$0b |
| $1DA2 | 8d 0b 1d | statransition_timer_hi |
| $1DA5 | a9 00 | lda#$00; Reset sequence index to 0 |
| $1DA7 | 8d 0c 1d | statransition_seq_idx |
| $1DAA | ad 0e 1d | ldatransition_seq_table; Load initial pattern from table |
| $1DAD | 8d 09 1d | statransition_pattern |
| $1DB0 | ad 0f 1d | ldatransition_seq_table_dur; Load initial duration from table |
| $1DB3 | 8d 0d 1d | statransition_duration |
| $1DB6 | a9 00 | lda#$00; Clear state variable |
| $1DB8 | 8d d8 60 | stadifficulty_mode |
| $1DBB | 4c ff 60 | jmpinit_cave_level; Jump to state 3 init handler |
| $1DBE | c9 00 | b_1DBEcmp#GameState.GAMEPLAY; State 0? ; x-ref: $1D99 |
| $1DC0 | d0 0f | bneb_1DD1 |
| $1DC2 | a9 e0 | lda#$e0; Reload timer = $01E0 (480 frames) |
| $1DC4 | 8d 0a 1d | statransition_timer_lo |
| $1DC7 | a9 01 | lda#$01 |
| $1DC9 | 8d 0b 1d | statransition_timer_hi |
| $1DCC | a9 ff | lda#$ff; Load $FF (flag value) |
| $1DCE | 4c 3e 6d | jmpinit_high_score_screen; Jump to state 0 effect handler |
| $1DD1 | c9 04 | b_1DD1cmp#$04; State 4? ; x-ref: $1DC0 |
| $1DD3 | d0 0d | bneb_1DE2 |
| $1DD5 | a9 2c | lda#$2c; Reload timer = $012C (300 frames) |
| $1DD7 | 8d 0a 1d | statransition_timer_lo |
| $1DDA | a9 01 | lda#$01 |
| $1DDC | 8d 0b 1d | statransition_timer_hi |
| $1DDF | 4c c3 5e | jmpshow_credits_screen; Jump to state 4 effect handler |
| $1DE2 | 4c 5e 69 | b_1DE2jmpshow_main_menu; Fallback: jump to default handler ; x-ref: $1DD3 |
| ; Advances to the next (pattern, duration) pair in the sequence table |
| ; at a_1D0E, indexed by a_1D0C. Called each frame during state 0. |
| advance_sequence_step |
| $1DE5 | ce 0d 1d | dectransition_duration; Decrement duration counter ; x-ref: $1D74 |
| $1DE8 | d0 14 | bner_1DFE; Duration not expired, return |
| $1DEA | ae 0c 1d | ldxtransition_seq_idx; Load sequence table index |
| $1DED | e8 | inx; Advance by 2 (next pair) |
| $1DEE | e8 | inx |
| $1DEF | 8e 0c 1d | stxtransition_seq_idx; Store updated index |
| $1DF2 | bd 0e 1d | ldatransition_seq_table,x; Load next pattern byte |
| $1DF5 | 8d 09 1d | statransition_pattern; Store as current pattern |
| $1DF8 | bd 0f 1d | ldatransition_seq_table_dur,x; Load next duration byte |
| $1DFB | 8d 0d 1d | statransition_duration; Store as current duration counter |
| $1DFE | 60 | r_1DFErts; x-ref: $1DE8 |
| ; Aborts the current transition by marking it finished and reloading |
| ; the timer with $021C (540 frames). |
| $1DFF | a9 ff | abort_transitionlda#$ff; Mark transition as finished ($FF) ; x-ref: $1D5D, $69CF |
| $1E01 | 8d 08 1d | statransition_active; Store finish flag |
| $1E04 | a9 1c | lda#$1c; Reload timer = $021C (540 frames) |
| $1E06 | 8d 0a 1d | statransition_timer_lo |
| $1E09 | a9 02 | lda#$02 |
| $1E0B | 8d 0b 1d | statransition_timer_hi |
| $1E0E | 60 | rts |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| ; Disables sound playback by clearing the sound-active flag. |
| ; Called during game state transitions (death, level change, menu) to |
| ; silence the SID before entering a new state. |
| ; |
| ; Inputs: None |
| ; Outputs: a_1D08 = $00 (sound disabled) |
| ; Side Effects: Sound playback stops on the next tick (s_1D44 returns early) |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| $1E0F | a9 00 | stop_soundlda#$00; Clear flag: disable sound ; x-ref: $6A7D, $6AA2, $6AAE, $6ABE |
| $1E11 | 8d 08 1d | statransition_active; sound_active_flag = 0 (off) |
| $1E14 | 60 | rts |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| ; Initializes the SID chip for music playback. Silences all three voices by |
| ; clearing their control registers and pulse widths, sets all frequency |
| ; high-bytes to $FF, and sets the master volume to maximum ($0F) with no |
| ; filter enabled. |
| ; |
| ; Inputs: None |
| ; Outputs: None |
| ; Side Effects: Resets SID registers $D401-$D418; silences all audio, sets |
| ; volume to max. |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| $1E15 | a9 00 | sid_initlda#$00; Clear value for control/pulse registers ; x-ref: $1E52, $20EF, $60CC |
| $1E17 | 8d 04 d4 | sta$d404; Silence voice 1 (gate off, no waveform); Voice 1: Control Register |
| $1E1A | 8d 0b d4 | sta$d40b; Silence voice 2; Voice 2: Control Register |
| $1E1D | 8d 12 d4 | sta$d412; Silence voice 3; Voice 3: Control Register |
| $1E20 | 8d 02 d4 | sta$d402; Reset voice 1 pulse width; Voice 1: Pulse Waveform Width - Low-Byte |
| $1E23 | 8d 09 d4 | sta$d409; Reset voice 2 pulse width; Voice 2: Pulse Waveform Width - Low-Byte |
| $1E26 | 8d 10 d4 | sta$d410; Reset voice 3 pulse width; Voice 3: Pulse Waveform Width - Low-Byte |
| $1E29 | a9 ff | lda#$ff; Max frequency high-byte value |
| $1E2B | 8d 01 d4 | sta$d401; Voice 1 freq hi = $FF; Voice 1: Frequency Control - High-Byte |
| $1E2E | 8d 08 d4 | sta$d408; Voice 2 freq hi = $FF; Voice 2: Frequency Control - High-Byte |
| $1E31 | 8d 0f d4 | sta$d40f; Voice 3 freq hi = $FF; Voice 3: Frequency Control - High-Byte |
| $1E34 | a9 0f | lda#$0f; Max volume, no filter |
| $1E36 | 8d 18 d4 | sta$d418; Set master volume to 15; Select Filter Mode and Volume |
| $1E39 | 60 | rts |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| ; Update all 8 sound effect channels. Each channel has an independent state |
| ; machine that controls SID voice parameters (frequency, waveform, ADSR). |
| ; Channels 1-2 use Voice 3, channel 3 uses Voice 2, channels 4-8 use Voice 1. |
| ; Called once per frame from the main game loop. |
| ; |
| ; Inputs: None (reads SFX state variables a_88EC..a_8BCF) |
| ; Outputs: None |
| ; Side Effects: Writes to SID registers $D400-$D414 (all three voices) |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| $1E3A | 20 ee 88 | update_all_sfxjsrtick_sfx_hit; Tick SFX channel 1: hit/destroy noise (Voice 3) ; x-ref: $60B6, $64D0 |
| $1E3D | 20 42 89 | jsrtick_sfx_explosion; Tick SFX channel 2 (Voice 3) |
| $1E40 | 20 92 89 | jsrtick_sfx_fire; Tick SFX channel 3 (Voice 2) |
| $1E43 | 20 25 8a | jsrtick_sfx_ch4_voice1; Tick SFX channel 4 (Voice 1) |
| $1E46 | 20 9f 8a | jsrtick_sfx_ch5_voice1; Tick SFX channel 5 (Voice 1) |
| $1E49 | 20 f2 8a | jsrtick_sfx6_voice1; Tick SFX channel 6 (Voice 1) |
| $1E4C | 20 78 8b | jsrtick_sfx7_voice1; Tick SFX channel 7 (Voice 1) |
| $1E4F | 4c d1 8b | jmptick_sfx_ch8; Tick SFX channel 8 (Voice 3), tail call |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| ; Stops all music and sound effects by resetting the SID chip hardware |
| ; registers and clearing all 8 music channel enable flags. |
| ; |
| ; Inputs: None |
| ; Outputs: None |
| ; Side Effects: SID chip voices silenced, all channel flags cleared |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| $1E52 | 20 15 1e | stop_all_musicjsrsid_init; Reset SID chip registers ; x-ref: $618E |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| ; Silences all 8 sound channels by clearing each channel's enable flag. |
| ; Called during state transitions and when fire is released on title screen. |
| ; |
| ; Inputs: None |
| ; Outputs: None |
| ; Side Effects: Clears enable byte for all 8 sound channels |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| $1E55 | a9 00 | silence_all_channelslda#$00; Clear accumulator (disable value) ; x-ref: $1D67, $1D7D |
| $1E57 | 8d ec 88 | stasfx_hit_state; Silence channel 1 |
| $1E5A | 8d 40 89 | stasfx_explosion_state; Silence channel 2 |
| $1E5D | 8d 88 89 | stasfx_fire_phase; Silence channel 3 |
| $1E60 | 8d 1a 8a | stasfx_ch4_state; Silence channel 4 |
| $1E63 | 8d 9d 8a | stasfx_ch5_state; Silence channel 5 |
| $1E66 | 8d f0 8a | stasfx6_enable; Silence channel 6 |
| $1E69 | 8d 76 8b | stasfx7_enable; Silence channel 7 |
| $1E6C | 8d cf 8b | stasfx_ch8_state; Silence channel 8 |
| $1E6F | 60 | rts |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| ; Hero collision detection dispatcher. |
| ; Checks if the hero collides with walls, laser beams, enemies, or the raft. |
| ; Skips all checks if hero is invulnerable (a_7B11 != 0). |
| ; Dispatches based on game state (a_7AFA): state 0 = normal play, |
| ; state 4 = dynamite placed (checks dynamite vs enemies instead). |
| ; |
| ; Inputs: a_7AFA (game state), a_7B11 (hero invulnerability flag) |
| ; Outputs: None (dispatches to sub-routines) |
| ; Side Effects: May trigger hero death (j_5056), enemy death (j_75F5/j_8185), |
| ; or raft collision (j_8185) |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| check_hero_collisions |
| $1E70 | ad 11 7b | ldahero_invulnerable; hero invulnerable? skip all collision checks ; x-ref: $61EC |
| $1E73 | f0 01 | beqhero_collision_dispatch |
| $1E75 | 60 | rts |
| hero_collision_dispatch |
| $1E76 | ad fa 7a | ldahero_state; check game state ; x-ref: $1E73 |
| $1E79 | c9 04 | cmp#$04 |
| $1E7B | d0 03 | bneb_1E80; state 4 = dynamite placed, check dynamite collisions |
| $1E7D | 4c 0d 20 | jmpcheck_dynamite_vs_enemies |
| $1E80 | ad fa 7a | b_1E80ldahero_state; state 0 = normal play ; x-ref: $1E7B |
| $1E83 | d0 14 | bner_1E99 |
| $1E85 | 20 9a 1e | jsrcheck_hazard_collision; check hero vs wall/obstacle |
| $1E88 | 20 d6 1e | jsrcheck_creature2_collision; check hero vs laser beam |
| $1E8B | 20 bd 1f | jsrcheck_player_enemy_collision; check hero vs enemies (laser hitbox) |
| $1E8E | 20 21 1f | jsrcheck_enemy_collision; check hero vs enemies (normal hitbox) |
| $1E91 | ad fa 7a | ldahero_state |
| $1E94 | d0 03 | bner_1E99 |
| $1E96 | 4c 65 1f | jmpcheck_raft_collision; check hero vs raft/vehicle |
| $1E99 | 60 | r_1E99rts; x-ref: $1E83, $1E94 |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| ; Check hero collision with wall/obstacle. |
| ; Compares hero Y position (a_7AFD) against obstacle Y (a_77C5) and hero X |
| ; position (a_7AFB/a_7AFC) against obstacle X (a_77C3/a_77C4). |
| ; If within bounding box, triggers hero death via j_5056. |
| ; |
| ; Inputs: a_77C2 (obstacle active flag), a_3FA4 (hero death flag), |
| ; hero pos (a_7AFB-a_7AFD), obstacle pos (a_77C3-a_77C5) |
| ; Outputs: None |
| ; Side Effects: May trigger hero death (j_5056) |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| check_hazard_collision |
| $1E9A | ad c2 77 | ldahazard_active; obstacle active? ; x-ref: $1E85 |
| $1E9D | f0 36 | beqr_1ED5; No hazard -> skip |
| $1E9F | ad a4 3f | ldascreen_slot_status; hero already dead? |
| $1EA2 | d0 31 | bner_1ED5; Death already triggered -> skip |
| $1EA4 | ad fd 7a | ldahero_y_pos; delta_y = hero_y - obstacle_y |
| $1EA7 | 38 | sec |
| $1EA8 | ed c5 77 | sbchazard_y; delta_y = player_y - hazard_y |
| $1EAB | c9 0d | cmp#$0d; delta_y >= 13? too far below |
| $1EAD | 10 26 | bplr_1ED5 |
| $1EAF | c9 f4 | cmp#$f4; delta_y < -12? too far above |
| $1EB1 | 30 22 | bmir_1ED5 |
| $1EB3 | ad fb 7a | ldahero_x_lo; delta_x_lo = hero_x_lo - obstacle_x_lo |
| $1EB6 | 38 | sec |
| $1EB7 | ed c3 77 | sbchazard_x_lo; delta_x lo = player_x_lo - hazard_x_lo |
| $1EBA | a8 | tay; Y = delta_x lo |
| $1EBB | ad fc 7a | ldahero_x_hi; delta_x_hi = hero_x_hi - obstacle_x_hi |
| $1EBE | ed c4 77 | sbchazard_x_hi; A = delta_x hi = player_x_hi - hazard_x_hi |
| $1EC1 | d0 07 | bneb_1ECA; Hi byte nonzero? Check negative case |
| $1EC3 | c0 0a | cpy#$0a; delta_x_lo < 10? collision! |
| $1EC5 | b0 0e | bcsr_1ED5 |
| $1EC7 | 4c 56 50 | jmpj_5056; kill hero |
| $1ECA | c9 ff | b_1ECAcmp#$ff; Hi byte == $FF? (negative delta) ; x-ref: $1EC1 |
| $1ECC | d0 07 | bner_1ED5 |
| $1ECE | c0 f6 | cpy#$f6; delta_x lo < $F6 (-10)? Too far left |
| $1ED0 | 90 03 | bccr_1ED5 |
| $1ED2 | 4c 56 50 | jmpj_5056; Collision! Trigger death |
| $1ED5 | 60 | r_1ED5rts; No collision ; x-ref: $1E9D, $1EA2, $1EAD, $1EB1, $1EC5, ... |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| ; Checks collision between the player and the secondary creature (a_7827). |
| ; Compares player position (a_7AFB/C/D) against creature position (a_77C3/C4/C5) |
| ; with a vertical proximity range of [5, 11) pixels and a direction-dependent |
| ; horizontal range of ~50 pixels in the player's facing direction. |
| ; On hit, jumps to j_5056 to trigger player death. |
| ; |
| ; Inputs: a_7827 (creature2 active flag), a_77C2 (enemy active), |
| ; a_3FA4 (player death flag), a_7AFB/C (player X 16-bit), |
| ; a_7AFD (player Y), a_77C3/C4 (enemy X 16-bit), |
| ; a_77C5 (enemy Y), a_7B01 (player facing direction) |
| ; Outputs: None (exits early if no collision) |
| ; Side Effects: Sets a_3FA4=$FF and triggers death screen flash via j_5056 |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| check_creature2_collision |
| $1ED6 | ad 27 78 | ldafire_active; creature2 active? ; x-ref: $1E88 |
| $1ED9 | f0 45 | beqr_1F20; no creature2, skip |
| $1EDB | ad c2 77 | ldahazard_active; enemy active? |
| $1EDE | f0 40 | beqr_1F20; no enemy, skip |
| $1EE0 | ad a4 3f | ldascreen_slot_status; already dead? |
| $1EE3 | d0 3b | bner_1F20; already dead, skip |
| $1EE5 | ad fd 7a | ldahero_y_pos; delta_y = player_y - enemy_y |
| $1EE8 | 38 | sec |
| $1EE9 | ed c5 77 | sbchazard_y |
| $1EEC | c9 0b | cmp#$0b; delta_y >= 11? too far below |
| $1EEE | 10 30 | bplr_1F20 |
| $1EF0 | c9 05 | cmp#$05; delta_y < 5? too far above |
| $1EF2 | 30 2c | bmir_1F20 |
| $1EF4 | ad fb 7a | ldahero_x_lo; delta_x lo = player_x_lo - enemy_x_lo |
| $1EF7 | 38 | sec |
| $1EF8 | ed c3 77 | sbchazard_x_lo |
| $1EFB | a8 | tay; Y = delta_x lo |
| $1EFC | ad fc 7a | ldahero_x_hi; delta_x hi = player_x_hi - enemy_x_hi |
| $1EFF | ed c4 77 | sbchazard_x_hi |
| $1F02 | aa | tax; X = delta_x hi |
| $1F03 | ad 01 7b | ldahero_scroll_dir; player facing direction |
| $1F06 | c9 01 | cmp#$01; facing right? |
| $1F08 | d0 0b | bneb_1F15; no, check left-facing range |
| $1F0A | e0 00 | cpx#$00; hi byte must be 0 (positive delta) |
| $1F0C | d0 12 | bner_1F20; hi != 0, out of range |
| $1F0E | c0 33 | cpy#$33; lo < $33 (51 px)? within range |
| $1F10 | b0 0e | bcsr_1F20; lo >= $33, out of range |
| $1F12 | 4c 56 50 | jmpj_5056; collision! trigger player death |
| $1F15 | e0 ff | b_1F15cpx#$ff; hi byte must be $FF (negative delta) ; x-ref: $1F08 |
| $1F17 | d0 07 | bner_1F20; hi != $FF, out of range |
| $1F19 | c0 ce | cpy#$ce; lo >= $CE (-50 px)? within range |
| $1F1B | 90 03 | bccr_1F20; lo < $CE, out of range |
| $1F1D | 4c 56 50 | jmpj_5056; collision! trigger player death |
| $1F20 | 60 | r_1F20rts; x-ref: $1ED9, $1EDE, $1EE3, $1EEE, $1EF2, ... |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| ; Check hero collision with enemies (normal hitbox). |
| ; Iterates the enemy table (f_7096) from index a_71E0-1 down to 0. |
| ; Skips dead enemies (f_7096,x != 0). Calls s_761B to set hitbox |
| ; dimensions based on enemy type. If hero is within bounding box, |
| ; triggers enemy-hit-hero via j_8185. |
| ; |
| ; Inputs: a_71E0 (enemy count), enemy tables (f_7096, f_70C3, etc.) |
| ; Outputs: None |
| ; Side Effects: May trigger enemy hit via j_8185 |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| check_enemy_collision |
| $1F21 | ae e0 71 | ldxtile_count; enemy_count ; x-ref: $1E8E |
| $1F24 | d0 01 | bneb_1F27; no enemies? return |
| $1F26 | 60 | rts |
| $1F27 | ca | b_1F27dex; adjust to 0-based index ; x-ref: $1F24 |
| $1F28 | bd 96 70 | b_1F28ldaentity_status,x; enemy dead/inactive? skip ; x-ref: $1F62 |
| $1F2B | d0 34 | bneb_1F61 |
| $1F2D | 20 1b 76 | jsrget_enemy_hitbox; set hitbox params for enemy type |
| $1F30 | ad fd 7a | ldahero_y_pos; delta_y = hero_y - enemy_y |
| $1F33 | 38 | sec |
| $1F34 | fd f0 70 | sbcentity_y,x; A = player_Y - enemy_Y |
| $1F37 | c5 02 | cmpzp_work0; delta >= upper Y bound? skip |
| $1F39 | 10 26 | bplb_1F61 |
| $1F3B | c5 03 | cmpzp_work1; delta < lower Y bound? skip |
| $1F3D | 30 22 | bmib_1F61 |
| $1F3F | ad fb 7a | ldahero_x_lo; delta_x_lo = hero_x_lo - enemy_x_lo |
| $1F42 | 38 | sec |
| $1F43 | fd c3 70 | sbcentity_x_lo,x; 16-bit: player_X - enemy_X |
| $1F46 | a8 | tay; Y = horiz delta lo byte |
| $1F47 | ad fc 7a | ldahero_x_hi; player X hi |
| $1F4A | fd d2 70 | sbcentity_x_hi,x; A = horiz delta hi byte |
| $1F4D | d0 07 | bneb_1F56; hi=0? positive delta path |
| $1F4F | c4 04 | cpyzp_work2; lo >= upper X bound? skip |
| $1F51 | b0 0e | bcsb_1F61 |
| $1F53 | 4c 85 81 | jmpj_8185; hero hit by enemy! |
| $1F56 | c9 ff | b_1F56cmp#$ff; hi=$FF? negative delta path ; x-ref: $1F4D |
| $1F58 | d0 07 | bneb_1F61 |
| $1F5A | c4 05 | cpyzp_work3; lo < lower X bound? skip |
| $1F5C | 90 03 | bccb_1F61 |
| $1F5E | 4c 85 81 | jmpj_8185; hero hit by enemy (neg delta)! |
| $1F61 | ca | b_1F61dex; next enemy ; x-ref: $1F2B, $1F39, $1F3D, $1F51, $1F58, ... |
| $1F62 | 10 c4 | bplb_1F28; loop until all checked |
| $1F64 | 60 | rts |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| ; Check hero collision with raft/vehicle (a_83A2). |
| ; Compares hero position against raft position (a_83A3-a_83A5). |
| ; Uses raft width (a_83A8) to calculate dynamic horizontal hitbox. |
| ; If within range, triggers raft collision via j_8185. |
| ; |
| ; Inputs: a_83A2 (raft active flag), raft pos (a_83A3-a_83A5), |
| ; a_83A8 (raft width), hero pos (a_7AFB-a_7AFD) |
| ; Outputs: None |
| ; Side Effects: May trigger raft collision via j_8185 |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| $1F65 | ad a2 83 | check_raft_collisionldaraft_active; raft/vehicle active? ; x-ref: $1E96 |
| $1F68 | f0 52 | beqr_1FBC |
| $1F6A | ad fd 7a | ldahero_y_pos; delta_y = hero_y - raft_y |
| $1F6D | 38 | sec |
| $1F6E | ed a5 83 | sbcraft_pixel_x |
| $1F71 | c9 21 | cmp#$21; delta_y >= $21? too far below |
| $1F73 | 10 47 | bplr_1FBC |
| $1F75 | c9 e2 | cmp#$e2; delta_y < $E2? too far above |
| $1F77 | 30 43 | bmir_1FBC |
| $1F79 | ad fb 7a | ldahero_x_lo; delta_x = hero_x - raft_x |
| $1F7C | 38 | sec |
| $1F7D | ed a3 83 | sbcraft_pixel_y_lo |
| $1F80 | a8 | tay |
| $1F81 | ad fc 7a | ldahero_x_hi |
| $1F84 | ed a4 83 | sbcraft_pixel_y_hi |
| $1F87 | d0 28 | bneb_1FB1 |
| $1F89 | ad a8 83 | ldaraft_anim_frame; left_edge = raft_width * 8 |
| $1F8C | 0a | asla |
| $1F8D | 0a | asla |
| $1F8E | 0a | asla |
| $1F8F | 85 ff | stazp_temp |
| $1F91 | c4 ff | cpyzp_temp |
| $1F93 | b0 03 | bcsb_1F98 |
| $1F95 | 4c 85 81 | jmpj_8185; raft collision (from left)! |
| $1F98 | c0 38 | b_1F98cpy#$38; x-ref: $1F93 |
| $1F9A | b0 20 | bcsr_1FBC |
| $1F9C | a9 04 | lda#$04 |
| $1F9E | 38 | sec |
| $1F9F | ed a8 83 | sbcraft_anim_frame |
| $1FA2 | 0a | asla |
| $1FA3 | 0a | asla |
| $1FA4 | 0a | asla |
| $1FA5 | 18 | clc |
| $1FA6 | 69 11 | adc#$11 |
| $1FA8 | 85 ff | stazp_temp |
| $1FAA | c4 ff | cpyzp_temp |
| $1FAC | 90 0e | bccr_1FBC |
| $1FAE | 4c 85 81 | jmpj_8185; raft collision (from right)! |
| $1FB1 | c9 ff | b_1FB1cmp#$ff; x-ref: $1F87 |
| $1FB3 | d0 07 | bner_1FBC |
| $1FB5 | c0 f9 | cpy#$f9 |
| $1FB7 | 90 03 | bccr_1FBC |
| $1FB9 | 4c 85 81 | jmpj_8185; raft collision (negative delta)! |
| $1FBC | 60 | r_1FBCrts; x-ref: $1F68, $1F73, $1F77, $1F9A, $1FAC, ... |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| ; Check hero collision with enemies (laser-active hitbox). |
| ; Similar to check_enemy_collision_normal but uses s_76BD to calculate |
| ; hitbox params based on enemy type and laser state. |
| ; Skips enemies of type 4 and dead enemies. If hero is within bounding |
| ; box, triggers laser-hit-enemy via j_75F5. |
| ; |
| ; Inputs: a_7827 (laser active), a_71E0 (enemy count), |
| ; enemy tables, hero position |
| ; Outputs: None |
| ; Side Effects: May trigger enemy death via j_75F5 |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| check_player_enemy_collision |
| $1FBD | ad 27 78 | ldafire_active; laser active? ; x-ref: $1E8B |
| $1FC0 | f0 05 | beqr_1FC7; No enemies → return |
| $1FC2 | ae e0 71 | ldxtile_count; enemy_count |
| $1FC5 | d0 01 | bneb_1FC8; No enemies → return |
| $1FC7 | 60 | r_1FC7rts; x-ref: $1FC0 |
| $1FC8 | ca | b_1FC8dex; Start from last enemy index ; x-ref: $1FC5 |
| $1FC9 | bd a5 70 | b_1FC9ldaentity_type,x; enemy type 4? skip (immune) ; x-ref: $200A |
| $1FCC | c9 04 | cmp#$04; Type 4 = dead/exploding, skip |
| $1FCE | f0 39 | beqb_2009 |
| $1FD0 | bd 96 70 | ldaentity_status,x; enemy dead? skip |
| $1FD3 | d0 34 | bneb_2009 |
| $1FD5 | 20 bd 76 | jsrget_laser_hitbox_params; set laser hitbox params for enemy type |
| $1FD8 | ad fd 7a | ldahero_y_pos; delta_y = hero_y - enemy_y |
| $1FDB | 38 | sec |
| $1FDC | fd f0 70 | sbcentity_y,x; Subtract enemy Y position |
| $1FDF | c5 02 | cmpzp_work0; Y delta >= upper bound? Skip |
| $1FE1 | 10 26 | bplb_2009 |
| $1FE3 | c5 03 | cmpzp_work1; Y delta < lower bound? Skip |
| $1FE5 | 30 22 | bmib_2009 |
| $1FE7 | ad fb 7a | ldahero_x_lo; delta_x = hero_x - enemy_x |
| $1FEA | 38 | sec |
| $1FEB | fd c3 70 | sbcentity_x_lo,x; Subtract enemy X low |
| $1FEE | a8 | tay; Y = X delta low byte |
| $1FEF | ad fc 7a | ldahero_x_hi; Player X high byte |
| $1FF2 | fd d2 70 | sbcentity_x_hi,x; Subtract enemy X high → A = X delta high |
| $1FF5 | d0 07 | bneb_1FFE; High byte = 0 → same page |
| $1FF7 | c4 04 | cpyzp_work2; X delta low >= right bound? Skip |
| $1FF9 | b0 0e | bcsb_2009 |
| $1FFB | 4c f5 75 | jmpj_75F5; laser kills enemy! |
| $1FFE | c9 ff | b_1FFEcmp#$ff; High byte = $FF → player is left of enemy ; x-ref: $1FF5 |
| ; Also used as cave_data_load_addr: initial RAM destination ($2000) for loading |
| ; cave files from disk. After each file loads, this pointer advances past the |
| ; loaded data. See $1C57-$1C5E. |
| $2000 | d0 07 | cave_data_load_addrbneb_2009; High byte ≠ $FF → delta out of range, skip ; x-ref: $1C57, $1C5C |
| $2002 | c4 05 | cpyzp_work3; X delta low < left bound? Skip |
| $2004 | 90 03 | bccb_2009 |
| $2006 | 4c f5 75 | jmpj_75F5; Laser kills enemy (negative X delta in range)! |
| $2009 | ca | b_2009dex; next enemy ; x-ref: $1FCE, $1FD3, $1FE1, $1FE5, $1FF9, ... |
| $200A | 10 bd | bplb_1FC9; Loop until all checked |
| $200C | 60 | rts |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| ; Check dynamite explosion vs enemies. |
| ; When game state is 4 (dynamite placed), iterate all enemies and check |
| ; if they are within the blast radius. Uses wider bounding box for |
| ; type-4 enemies ($18/$E9) vs normal ($14/$ED). Marks hit enemies in |
| ; f_71D1,x table. |
| ; |
| ; Inputs: a_71E0 (enemy count), enemy tables, hero position |
| ; Outputs: f_71D1,x (enemy hit flags) |
| ; Side Effects: May mark enemies as hit by dynamite |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| check_dynamite_vs_enemies |
| $200D | ae e0 71 | ldxtile_count; enemy_count ; x-ref: $1E7D |
| $2010 | d0 01 | bneb_2013 |
| $2012 | 60 | rts |
| $2013 | ca | b_2013dex; x-ref: $2010 |
| $2014 | bd 96 70 | b_2014ldaentity_status,x; enemy dead? skip ; x-ref: $2067 |
| $2017 | d0 4d | bneb_2066 |
| $2019 | ad fd 7a | ldahero_y_pos; delta_y = hero_y - enemy_y |
| $201C | 38 | sec |
| $201D | fd f0 70 | sbcentity_y,x |
| $2020 | c9 18 | cmp#$18; delta_y >= $18? too far below |
| $2022 | 10 42 | bplb_2066 |
| $2024 | c9 e9 | cmp#$e9 |
| $2026 | 30 3e | bmib_2066 |
| $2028 | bd a5 70 | ldaentity_type,x; enemy type 4? use wider hitbox |
| $202B | c9 04 | cmp#$04 |
| $202D | f0 0b | beqb_203A |
| $202F | a9 14 | lda#$14; normal blast radius: $14 wide |
| $2031 | 85 02 | stazp_work0 |
| $2033 | a9 ed | lda#$ed |
| $2035 | 85 03 | stazp_work1 |
| $2037 | 4c 42 20 | jmpj_2042 |
| $203A | a9 18 | b_203Alda#$18; type-4 blast radius: $18 wide ; x-ref: $202D |
| $203C | 85 02 | stazp_work0 |
| $203E | a9 e9 | lda#$e9 |
| $2040 | 85 03 | stazp_work1 |
| $2042 | ad fb 7a | j_2042ldahero_x_lo; delta_x = hero_x - enemy_x ; x-ref: $2037 |
| $2045 | 38 | sec |
| $2046 | fd c3 70 | sbcentity_x_lo,x |
| $2049 | a8 | tay |
| $204A | ad fc 7a | ldahero_x_hi |
| $204D | fd d2 70 | sbcentity_x_hi,x |
| $2050 | d0 07 | bneb_2059 |
| $2052 | c4 02 | cpyzp_work0 |
| $2054 | b0 10 | bcsb_2066 |
| $2056 | 4c 61 20 | jmpj_2061 |
| $2059 | c9 ff | b_2059cmp#$ff; x-ref: $2050 |
| $205B | d0 09 | bneb_2066 |
| $205D | c4 03 | cpyzp_work1 |
| $205F | 90 05 | bccb_2066 |
| $2061 | a9 ff | j_2061lda#$ff; mark enemy as hit by dynamite ; x-ref: $2056 |
| $2063 | 9d d1 71 | staentity_hit_flag,x |
| $2066 | ca | b_2066dex; next enemy ; x-ref: $2017, $2022, $2026, $2054, $205B, ... |
| $2067 | 10 ab | bplb_2014 |
| $2069 | 60 | rts |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| ; Loads a file from disk into memory at the address stored in $FB/$FC. |
| ; The caller must pre-load A=filename length, X/Y=filename address before calling. |
| ; Uses secondary address 0 (load to specified address, not file header address). |
| ; |
| ; Inputs: A = filename length, X = filename addr lo, Y = filename addr hi, |
| ; $FB/$FC = destination address (lo/hi) |
| ; Outputs: X/Y = end-of-load address (lo/hi), A = error code (0=ok) |
| ; Side Effects: Performs disk I/O; loads file data into RAM |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| $206A | 20 bd ff | load_file_to_addrjsrKERNAL_SETNAM; Set filename (A=len, X/Y=name addr) ; x-ref: $1C83, $52F1 $FFBD (jmp) setnam Set Filename |
| $206D | a0 00 | ldy#$00; Secondary addr 0 = load to X/Y addr |
| $206F | 20 c6 20 | jsrsetup_file_params; Set logical file #1, device, SA=0 |
| $2072 | a6 fb | ldxzp_ptr_src_lo; Load addr lo from $FB |
| $2074 | a4 fc | ldyzp_ptr_src_hi; Load addr hi from $FC |
| $2076 | a9 00 | lda#$00; A=0: LOAD (not VERIFY) |
| $2078 | 4c d5 ff | jmpKERNAL_LOADSP; Tail-call KERNAL LOAD; $FFD5 (jmp) loadsp Load RAM From Device |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| ; Saves a memory region to a storage device (disk). |
| ; Caller must pre-set the filename in A/X/Y before calling. |
| ; Uses ZP $FB-$FC as start address and ZP $FD-$FE as end address+1. |
| ; |
| ; Inputs: A = filename length, X/Y = pointer to filename string, |
| ; $FB-$FC = start address of memory region, |
| ; $FD-$FE = end address+1 of memory region |
| ; Outputs: Carry set on error, A = KERNAL error code |
| ; Side Effects: Saves memory block to disk via KERNAL SAVE |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| save_memory_to_device |
| $207B | 20 bd ff | jsrKERNAL_SETNAM; Set filename from caller's A/X/Y ; x-ref: $5320 $FFBD (jmp) setnam Set Filename |
| $207E | a0 ff | ldy#$ff; Secondary address $FF = SAVE mode |
| $2080 | 20 c6 20 | jsrsetup_file_params; Set logical file #1, device (default 8) |
| $2083 | a6 fd | ldxzp_ptr_dst_lo; X = end address low byte |
| $2085 | a4 fe | ldyzp_ptr_dst_hi; Y = end address high byte |
| $2087 | a9 fb | lda#$fb; A = ZP ptr to start addr ($FB-$FC) |
| $2089 | 4c d8 ff | jmpKERNAL_SAVESP; Tail call: perform the SAVE; $FFD8 (jmp) savesp Save RAM To Device |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| ; Sends a command string to the disk drive via the command channel. |
| ; The caller sets A=length, X/Y=pointer to command string before calling |
| ; KERNAL_SETNAM, then this routine opens the command channel (SA#15), |
| ; which implicitly sends the command, and immediately closes it. |
| ; |
| ; Inputs: Filename must be set via KERNAL_SETNAM before entry (A=len, X/Y=ptr) |
| ; Outputs: None |
| ; Side Effects: Sends a command to the disk drive (e.g., scratch, rename) |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| $208C | 20 bd ff | send_disk_commandjsrKERNAL_SETNAM; x-ref: $5300 $FFBD (jmp) setnam Set Filename |
| $208F | a0 0f | ldy#$0f; SA=15: disk command channel |
| $2091 | 20 c6 20 | jsrsetup_file_params; Set LF#1, device, SA=15 |
| $2094 | 20 c0 ff | jsrKERNAL_OPENi; Open command channel (sends the command); $FFC0 (ind) iopen Open Vector [efbd] |
| $2097 | a9 01 | lda#$01; LF#1 |
| $2099 | 20 c3 ff | jsrKERNAL_CLOSEi; Close the command channel; $FFC3 (ind) iclose Close Vector [f188] |
| $209C | 4c cc ff | jmpKERNAL_CLRCHi; Restore default I/O and return; $FFCC (ind) iclrch Restore I/O Vector [f226] |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| ; Reads and discards the disk drive error/status channel. |
| ; Opens the command channel (secondary address 15), reads all status |
| ; bytes until the I/O status indicates completion, then closes the channel. |
| ; Commonly called after disk operations to clear any pending drive errors. |
| ; |
| ; Inputs: zpa_BA (current device number) |
| ; Outputs: None (status bytes are read and discarded) |
| ; Side Effects: Opens and closes logical file #1 on the disk drive |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| read_disk_status_channel |
| $209F | a9 00 | lda#$00; filename length = 0 (no filename needed for status channel) ; x-ref: $6696 |
| $20A1 | aa | tax |
| $20A2 | a8 | tay |
| $20A3 | 20 bd ff | jsrKERNAL_SETNAM; set empty filename; $FFBD (jmp) setnam Set Filename |
| $20A6 | a0 0f | ldy#$0f; secondary address 15 = command/status channel |
| $20A8 | 20 c6 20 | jsrsetup_file_params; set logical file params (file #1, device, SA #15) |
| $20AB | 20 c0 ff | jsrKERNAL_OPENi; open the command channel; $FFC0 (ind) iopen Open Vector [efbd] |
| $20AE | a2 01 | ldx#$01; channel #1 |
| $20B0 | 20 c6 ff | jsrKERNAL_CHKINi; set channel 1 as input source; $FFC6 (ind) ichkin Set Input [f106] |
| $20B3 | 20 b7 ff | read_status_loopjsrKERNAL_READSS; check I/O status ; x-ref: $20BB $FFB7 (jmp) readss Read I/O Status Word |
| $20B6 | d0 06 | bnestatus_read_done; non-zero = error or end-of-input, stop reading |
| $20B8 | 20 cf ff | jsrKERNAL_BASINi; read and discard one status byte; $FFCF (ind) ibasin Input Vector, chrin [ef06] |
| $20BB | 4c b3 20 | jmpread_status_loop |
| $20BE | a9 01 | status_read_donelda#$01; logical file #1 ; x-ref: $20B6 |
| $20C0 | 20 c3 ff | jsrKERNAL_CLOSEi; close the command channel; $FFC3 (ind) iclose Close Vector [f188] |
| $20C3 | 4c cc ff | jmpKERNAL_CLRCHi; restore default I/O channels; $FFCC (ind) iclrch Restore I/O Vector [f226] |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| ; Sets up logical file parameters for KERNAL I/O operations. |
| ; Uses logical file #1, reads the current device number from $BA, |
| ; and ensures it is at least 8 (disk drive). The secondary address |
| ; is expected to be pre-loaded in Y by the caller. |
| ; |
| ; Inputs: Y = secondary address (set by caller before JSR) |
| ; Outputs: A = 1 (logical file #), X = device # (>= 8), Y unchanged |
| ; Side Effects: Calls KERNAL SETLFS ($FFBA) to apply file parameters |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| $20C6 | a9 01 | setup_file_paramslda#$01; Logical file number = 1 ; x-ref: $206F, $2080, $2091, $20A8 |
| $20C8 | a6 ba | ldxzp_current_device; Current device number (KERNAL $BA) |
| $20CA | e0 08 | cpx#$08; Is it >= 8 (disk drive)? |
| $20CC | b0 02 | bcsb_20D0; Yes, keep the device number |
| $20CE | a2 08 | ldx#$08; No, default to device 8 |
| $20D0 | 4c ba ff | b_20D0jmpKERNAL_SETLFS; Set logical file params (A=file#, X=dev#, Y=sec addr) ; x-ref: $20CC $FFBA (jmp) setlfs Set Logical File Parameters |
| ; Game state machine variable. |
| ; 0=playing cave, 1=title/intro, 2=high score entry, 3=main menu, |
| ; 4=best heroes, 5=credits, 6=game complete |
| $20D3 | | game_state.byte$00; x-ref: $1D4D, $1D6D, $1D94, $20FE, $2107, ... |
| ; Snapshot of game_state taken before transition check. |
| ; Used to detect mid-frame state changes and abort the current frame. |
| $20D4 | | prev_game_state.byte$00; x-ref: $2101, $210A |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| ; Initializes the game hardware and state. Configures the C128 MMU bank, |
| ; saves the zero-page working area, disables CIA interrupts, installs |
| ; a custom NMI handler, resets the SID sound chip, and then jumps to |
| ; the first game-state setup (state 1). |
| ; |
| ; Inputs: None |
| ; Outputs: None |
| ; Side Effects: MMU bank set to $0E (I/O visible, RAM0); CIA1/CIA2 |
| ; interrupts disabled; NMI vector redirected; SID silenced; |
| ; zero-page $03–$FA saved to buffer; game state set to 1. |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| $20D5 | a9 ff | init_gamelda#$ff; sentinel: mark game as initializing ; x-ref: $1C0D |
| $20D7 | 85 d8 | stazp_init_flag; store init flag in zero-page |
| $20D9 | ad 04 0a | ldagame_flags; Read game flags for init |
| $20DC | 29 fe | and#$fe |
| $20DE | 8d 04 0a | stagame_flags; Clear bit 0 of game flags |
| $20E1 | a9 0e | lda#$0e; MMU bank $0E: I/O + KERNAL visible, RAM0 |
| $20E3 | 8d 00 ff | staMMU_CONFIG; Set MMU: I/O + KERNAL visible, RAM0; C128: MMU Configuration Register |
| $20E6 | 20 b7 5b | jsrsave_zero_page; save zero-page $03-$FA to buffer |
| $20E9 | 20 3d 21 | jsrdisable_cia_interrupts; disable CIA1 & CIA2 interrupts |
| $20EC | 20 ab 5b | jsrdisable_nmi; set NMI vector to custom handler |
| $20EF | 20 15 1e | jsrsid_init; silence all SID voices |
| $20F2 | 4c f3 65 | jmpinit_intro_screen; enter game state 1 (title/intro setup) |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| ; Main game-state dispatcher. Called once per frame from the main loop after |
| ; the raster beam reaches line $FB. Reads joystick input, scans the keyboard |
| ; matrix, filters keyboard ghosting, then snapshots the current game state |
| ; (a_20D3) and runs the screen transition sequencer. If the transition changed |
| ; the state, returns immediately (to let the new state take effect next frame). |
| ; Otherwise, dispatches to the handler for the current state: |
| ; |
| ; State 0 → j_6182 (title/intro screen) |
| ; State 1 → j_663B (menu/option select) |
| ; State 2 → j_66DE (game setup / level init) |
| ; State 3 → j_6A6A (gameplay) |
| ; State 4 → j_6E96 (game over / results) |
| ; State 5 → j_5F28 (high-score entry) |
| ; Default → j_60B6 (fallback / SFX update) |
| ; |
| ; Inputs: a_20D3 (current game state) |
| ; Outputs: None (dispatches to appropriate handler) |
| ; Side Effects: Joystick and keyboard state updated; transition sequencer runs |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| $20F5 | 20 82 3e | game_state_dispatchjsrread_joystick; poll joystick port ; x-ref: $1C17 |
| $20F8 | 20 18 3f | jsrscan_keyboard_matrix; scan keyboard matrix for key states |
| $20FB | 20 96 3e | jsrfilter_joystick_from_keyboard; filter phantom joystick bits from keyboard ghosting |
| $20FE | ad d3 20 | ldagame_state; Snapshot current game_state |
| $2101 | 8d d4 20 | staprev_game_state; Save as prev_game_state for comparison |
| $2104 | 20 44 1d | jsrupdate_transition_sequence; run screen transition sequencer (may change state) |
| $2107 | ad d3 20 | ldagame_state; Re-read game_state (may have changed) |
| $210A | cd d4 20 | cmpprev_game_state; Compare with pre-transition snapshot |
| $210D | f0 01 | beqb_2110; if state unchanged, proceed to dispatch |
| $210F | 60 | rts; state changed mid-frame — abort, let new state run next frame |
| $2110 | c9 00 | b_2110cmp#GameState.GAMEPLAY; state == 0? → title/intro screen ; x-ref: $210D |
| $2112 | d0 03 | bneb_2117 |
| $2114 | 4c 82 61 | jmpgame_engine_loop |
| $2117 | c9 01 | b_2117cmp#GameState.INTRO; state == 1? → menu/option select ; x-ref: $2112 |
| $2119 | d0 03 | bneb_211E |
| $211B | 4c 3b 66 | jmpwait_for_intro_fire_click |
| $211E | c9 02 | b_211Ecmp#GameState.CURTAIN_ANIMATION; state == 2? → game setup / level init ; x-ref: $2119 |
| $2120 | d0 03 | bneb_2125 |
| $2122 | 4c de 66 | jmpupdate_title_curtain_animation |
| $2125 | c9 03 | b_2125cmp#GameState.MAIN_MENU; state == 3? → gameplay ; x-ref: $2120 |
| $2127 | d0 03 | bneb_212C |
| $2129 | 4c 6a 6a | jmpupdate_main_menu_selection |
| $212C | c9 04 | b_212Ccmp#GameState.GAME_OVER; state == 4? → game over / results ; x-ref: $2127 |
| $212E | d0 03 | bneb_2133 |
| $2130 | 4c 96 6e | jmpupdate_high_score_screen |
| $2133 | c9 05 | b_2133cmp#GameState.CREDITS; state == 5? → high-score entry ; x-ref: $212E |
| $2135 | d0 03 | bneb_213A |
| $2137 | 4c 28 5f | jmpwait_for_credits_fire_click |
| $213A | 4c b6 60 | b_213Ajmpupdate_typewriter_or_skip; default: fallback handler (update SFX, check fire) ; x-ref: $2135 |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| ; Disables all CIA1 and CIA2 interrupt sources and acknowledges any pending |
| ; interrupts. Writes $7F to the ICR to clear all enable bits, then reads |
| ; the ICR to clear the interrupt-pending flags. |
| ; |
| ; Inputs: None |
| ; Outputs: A = value of CIA2 ICR (pending flags at time of read) |
| ; Side Effects: All CIA1 and CIA2 interrupts are disabled and acknowledged |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| disable_cia_interrupts |
| $213D | a9 7f | lda#$7f; $7F = %01111111, clears all CIA interrupt enable bits ; x-ref: $20E9 |
| $213F | 8d 0d dc | sta$dc0d; Disable all CIA1 interrupts (timer A/B, TOD, serial, flag); CIA1: CIA Interrupt Control Register |
| $2142 | 8d 0d dd | sta$dd0d; Disable all CIA2 interrupts; CIA2: CIA Interrupt Control Register |
| $2145 | ad 0d dc | lda$dc0d; Acknowledge/clear any pending CIA1 interrupts; CIA1: CIA Interrupt Control Register |
| $2148 | ad 0d dd | lda$dd0d; Acknowledge/clear any pending CIA2 interrupts; CIA2: CIA Interrupt Control Register |
| $214B | 60 | rts |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| ; Configures a raster IRQ on a specified scanline with a custom handler. |
| ; The raster line is passed in A, and the handler address in X (lo) / Y (hi). |
| ; Sets the C128 MMU to $3E (RAM+I/O) and points the hardware IRQ vector |
| ; at $FFFE/$FFFF to the local IRQ stub at $2174, which dispatches through |
| ; the stored handler pointer at $0314/$0315. |
| ; |
| ; Inputs: A = raster line number, X = handler address lo, Y = handler address hi |
| ; Outputs: None |
| ; Side Effects: Configures VIC-II raster IRQ, sets hardware IRQ vector, sets MMU |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| $214C | 78 | setup_raster_irqsei; Disable interrupts during setup ; x-ref: $6163, $69DB |
| $214D | 8d 12 d0 | sta$d012; Set raster line to trigger IRQ (from A); Raster Position |
| $2150 | 8e 14 03 | stxIRQ_VECTOR_LO; Store custom IRQ handler lo byte |
| $2153 | 8c 15 03 | styIRQ_VECTOR_HI; Store custom IRQ handler hi byte |
| $2156 | ad 11 d0 | lda$d011; Read VIC Control Register 1; VIC Control Register 1 |
| $2159 | 29 7f | and#$7f; Clear bit 7 (raster compare bit 8) |
| $215B | 8d 11 d0 | sta$d011; Restrict to raster lines 0-255; VIC Control Register 1 |
| $215E | a9 3e | lda#$3e; MMU config $3E: RAM+I/O visible |
| $2160 | 8d 00 ff | staMMU_CONFIG; Set MMU: RAM+I/O visible for IRQ; C128: MMU Configuration Register |
| $2163 | a9 74 | lda#$74; Point HW IRQ vector lo to $2174 (IRQ stub) |
| $2165 | 8d fe ff | sta$fffe; IRQ |
| $2168 | a9 21 | lda#$21; Point HW IRQ vector hi to $21 (IRQ stub) |
| $216A | 8d ff ff | sta$ffff; IRQ |
| $216D | a9 01 | lda#$01; Enable raster interrupt |
| $216F | 8d 1a d0 | sta$d01a; VIC Interrupt Mask Register (IMR) |
| $2172 | 58 | cli; Re-enable interrupts |
| $2173 | 60 | rts |
| $2174 | 48 | pha |
| $2175 | 8a | txa |
| $2176 | 48 | pha |
| $2177 | 98 | tya |
| $2178 | 48 | pha |
| $2179 | 6c 14 03 | jmp(IRQ_VECTOR_LO); Dispatch through custom IRQ handler vector |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| ; Raster IRQ epilogue / chain dispatcher. |
| ; Sets the next raster line and IRQ handler, acknowledges the interrupt, |
| ; restores registers from the stack, and returns via RTI. |
| ; |
| ; Inputs: A = next raster line, X = lo byte of next IRQ handler, Y = hi byte |
| ; Outputs: None (returns via RTI) |
| ; Side Effects: $D012 (raster line), $0314/$0315 (IRQ vector), $D019 (IRQ ack) |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| $217C | 8d 12 d0 | irq_chain_nextsta$d012; Set next raster trigger line ; x-ref: $563A, $56CC, $575E, $57F0, $5882, ...; Raster Position |
| $217F | 8e 14 03 | stxIRQ_VECTOR_LO; Set next IRQ handler (lo) |
| $2182 | 8c 15 03 | styIRQ_VECTOR_HI; Set next IRQ handler (hi) |
| $2185 | ee 19 d0 | inc$d019; Acknowledge VIC interrupt; VIC Interrupt Request Register (IRR) |
| $2188 | 68 | pla; Restore Y |
| $2189 | a8 | tay |
| $218A | 68 | pla; Restore X |
| $218B | aa | tax |
| $218C | 68 | pla; Restore A |
| $218D | 40 | rti; Return from interrupt |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| ; Disables raster IRQs and restores the KERNAL default IRQ vector ($EA31). |
| ; Also restores the C128 MMU configuration to make KERNAL ROM and I/O visible. |
| ; |
| ; Inputs: None |
| ; Outputs: None |
| ; Side Effects: Disables VIC interrupts ($D01A), restores IRQ vector to $EA31, |
| ; sets MMU config ($FF00) to $0E (KERNAL+I/O) |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| $218E | 78 | irq_raster_disablesei; Disable interrupts during setup ; x-ref: $3694 |
| $218F | a9 00 | lda#$00 |
| $2191 | 8d 1a d0 | sta$d01a; Disable all VIC interrupt sources; VIC Interrupt Mask Register (IMR) |
| $2194 | a9 31 | lda#<KERNAL_IRQ_DEFAULT; Restore IRQ vector lo = $31 |
| $2196 | 8d 14 03 | staIRQ_VECTOR_LO; Restore default KERNAL IRQ ($EA31) |
| $2199 | a9 ea | lda#>KERNAL_IRQ_DEFAULT; Restore IRQ vector hi = $EA ($EA31 = KERNAL IRQ) |
| $219B | 8d 15 03 | staIRQ_VECTOR_HI; Restore default KERNAL IRQ ($EA31) |
| $219E | a9 0e | lda#$0e; MMU: KERNAL ROM + I/O visible |
| $21A0 | 8d 00 ff | staMMU_CONFIG; Restore MMU: KERNAL+I/O visible; C128: MMU Configuration Register |
| $21A3 | 58 | cli; Re-enable interrupts |
| $21A4 | 60 | rts |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| ; Multiplies the accumulator by 5. |
| ; Uses shift-and-add: A*4 + A = A*5. |
| ; |
| ; Inputs: A = value to multiply |
| ; Outputs: A = A * 5 (result undefined if overflow occurs) |
| ; Side Effects: Clobbers zpa_ED (scratch), carry flag undefined |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| $21A5 | 85 ed | multiply_by_5stazp_math_temp; Save original A in scratch ; x-ref: $6B71, $7A43 |
| $21A7 | 0a | asla; A = A * 2 |
| $21A8 | 0a | asla; A = A * 4 |
| $21A9 | 65 ed | adczp_math_temp; A = A*4 + original = A*5 |
| $21AB | 60 | rts |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| ; Multiplies the accumulator by 7 using shift-and-subtract. |
| ; Computes A = A * 8 - A = A * 7. Uses zpa_ED as a temporary. |
| ; |
| ; Inputs: A = value to multiply |
| ; Outputs: A = A * 7 (carry flag undefined) |
| ; Side Effects: zpa_ED is overwritten |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| $21AC | 85 ed | multiply_by_7stazp_math_temp; Save original A ; x-ref: $8157, $8168 |
| $21AE | 0a | asla |
| $21AF | 0a | asla |
| $21B0 | 0a | asla; A = original * 8 |
| $21B1 | 38 | sec |
| $21B2 | e5 ed | sbczp_math_temp; A = A*8 - A = A*7 |
| $21B4 | 60 | rts |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| ; Multiplies the accumulator by 30 using shift-and-subtract. |
| ; Computes A = A * 32 - A * 2 = A * 30. |
| ; Used to index into 30-byte record tables. |
| ; |
| ; Inputs: A = value to multiply |
| ; Outputs: A = A * 30 (low byte, carry undefined) |
| ; Side Effects: zpa_ED used as temp storage |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| $21B5 | 85 ed | multiply_by_30stazp_math_temp; save original value (N) ; x-ref: $6B5B |
| $21B7 | 0a | asla; A = N * 2 |
| $21B8 | 0a | asla; A = N * 4 |
| $21B9 | 0a | asla; A = N * 8 |
| $21BA | 0a | asla; A = N * 16 |
| $21BB | 0a | asla; A = N * 32 |
| $21BC | 38 | sec; prepare for subtraction |
| $21BD | e5 ed | sbczp_math_temp; A = N*32 - N = N*31 |
| $21BF | e5 ed | sbczp_math_temp; A = N*31 - N = N*30 |
| $21C1 | 60 | rts; return A = N * 30 |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| ; Divides the unsigned value in A by 5 using fixed-point |
| ; multiplication by the reciprocal (1/5 ≈ 0.001100110011... binary). |
| ; Uses successive shift-and-add to approximate A * 51/256. |
| ; |
| ; Inputs: A = unsigned dividend (0-255) |
| ; Outputs: A = quotient (A / 5, truncated) |
| ; Side Effects: zpa_ED used as temporary storage |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| $21C2 | 4a | divide_by_5lsra; A = input >> 1 ; x-ref: $7C6E |
| $21C3 | 85 ed | stazp_math_temp; temp = input/2 |
| $21C5 | 4a | lsra; A = input/4 |
| $21C6 | 65 ed | adczp_math_temp; A = input/4 + input/2 = 3*input/4 |
| $21C8 | 6a | rora; A = 3*input/8 (with carry) |
| $21C9 | 4a | lsra; A = 3*input/16 |
| $21CA | 4a | lsra; A = 3*input/32 |
| $21CB | 65 ed | adczp_math_temp; A += input/2 (refine approximation) |
| $21CD | 6a | rora; rotate for next bit of 1/5 |
| $21CE | 65 ed | adczp_math_temp; A += input/2 (final refinement) |
| $21D0 | 6a | rora; final shifts to complete A/5 |
| $21D1 | 4a | lsra |
| $21D2 | 4a | lsra |
| $21D3 | 60 | rts; return A = input / 5 |
| $21D4 | | .fill171, $00 |
| ; -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= |
| ; Gameplay Sprites |
| $227F | | .byte$05, $01, $41, $00, $00, $11, $00, $00 |
| $2287 | | .byte$11, $00, $01, $51, $00, $01, $41, $00 |
| $228F | | .byte$00, $a2, $80, $02, $aa, $80, $02, $8a |
| $2297 | | .byte$80, $02, $8a, $80, $02, $a2, $00, $02 |
| $229F | | .byte$02, $00, $00, $fc, $00, $00, $f0, $00 |
| $22A7 | | .byte$00, $f0, $00, $00, $f0, $00, $00, $f0 |
| $22AF | | .byte$00, $00, $f0, $00, $00, $f0, $00, $00 |
| $22B7 | | .byte$f0, $00, $00, $f0, $00, $03, $f0, $00 |
| $22BF | | .byte$06, $01, $41, $00, $00, $11, $00, $00 |
| $22C7 | | .byte$11, $00, $01, $51, $00, $01, $41, $00 |
| $22CF | | .byte$00, $a2, $80, $02, $aa, $80, $02, $8a |
| $22D7 | | .byte$80, $02, $8a, $80, $02, $a2, $00, $02 |
| $22DF | | .byte$02, $00, $00, $fc, $00, $00, $3c, $00 |
| $22E7 | | .byte$00, $fc, $00, $00, $fc, $00, $00, $cc |
| $22EF | | .byte$00, $00, $cf, $c0, $00, $c0, $c0, $0f |
| $22F7 | | .byte$00, $c0, $03, $00, $00, $00, $00, $00 |
| $22FF | | .byte$06, $01, $41, $00, $00, $11, $00, $00 |
| $2307 | | .byte$11, $00, $01, $51, $00, $01, $41, $00 |
| $230F | | .byte$00, $a2, $80, $02, $aa, $80, $02, $8a |
| $2317 | | .byte$80, $02, $8a, $80, $00, $8a, $00, $02 |
| $231F | | .byte$0a, $00, $00, $fc, $00, $00, $3c, $00 |
| $2327 | | .byte$00, $fc, $00, $03, $f0, $00, $03, $30 |
| $232F | | .byte$00, $03, $ff, $00, $00, $33, $00, $00 |
| $2337 | | .byte$33, $00, $00, $30, $00, $00, $f0, $00 |
| $233F | | .byte$06, $01, $41, $00, $00, $11, $00, $00 |
| $2347 | | .byte$11, $00, $01, $51, $00, $01, $41, $00 |
| $234F | | .byte$00, $a2, $80, $02, $aa, $80, $02, $8a |
| $2357 | | .byte$80, $02, $8a, $80, $00, $8a, $00, $02 |
| $235F | | .byte$0a, $00, $00, $fc, $00, $00, $fc, $00 |
| $2367 | | .byte$03, $fc, $00, $03, $cc, $00, $03, $0f |
| $236F | | .byte$00, $00, $cf, $00, $00, $c3, $00, $03 |
| $2377 | | .byte$03, $00, $00, $03, $00, $00, $0c, $00 |
| $237F | | .byte$06, $01, $41, $00, $00, $11, $00, $00 |
| $2387 | | .byte$11, $00, $01, $51, $00, $01, $41, $00 |
| $238F | | .byte$00, $a2, $80, $02, $aa, $80, $02, $8a |
| $2397 | | .byte$80, $02, $8a, $80, $00, $8a, $00, $02 |
| $239F | | .byte$0a, $00, $00, $fc, $00, $00, $fc, $00 |
| $23A7 | | .byte$03, $ff, $00, $03, $cf, $00, $03, $03 |
| $23AF | | .byte$c0, $03, $03, $c0, $0f, $00, $f0, $00 |
| $23B7 | | .byte$00, $30, $00, $00, $30, $00, $00, $00 |
| $23BF | | .byte$06, $01, $41, $00, $00, $11, $00, $00 |
| $23C7 | | .byte$11, $00, $01, $51, $00, $01, $41, $00 |
| $23CF | | .byte$00, $a2, $80, $02, $aa, $80, $02, $8a |
| $23D7 | | .byte$80, $02, $8a, $80, $02, $a2, $00, $02 |
| $23DF | | .byte$02, $00, $00, $fc, $00, $03, $fc, $00 |
| $23E7 | | .byte$03, $3c, $f0, $03, $0f, $c0, $0f, $0f |
| $23EF | | .fill16, $00 |
| $23FF | | .byte$06, $01, $41, $00, $00, $11, $00, $00 |
| $2407 | | .byte$11, $00, $01, $51, $00, $01, $41, $00 |
| $240F | | .byte$00, $a2, $80, $02, $aa, $80, $02, $8a |
| $2417 | | .byte$80, $02, $8a, $80, $00, $8a, $00, $02 |
| $241F | | .byte$0a, $00, $00, $fc, $00, $00, $f0, $00 |
| $2427 | | .byte$00, $f0, $00, $00, $30, $00, $00, $30 |
| $242F | | .byte$00, $00, $3c, $00, $00, $3c, $00, $00 |
| $2437 | | .byte$0c, $00, $00, $0c, $00, $00, $0c, $00 |
| $243F | | .byte$06, $00, $41, $40, $00, $44, $00, $00 |
| $2447 | | .byte$44, $00, $00, $45, $40, $00, $41, $40 |
| $244F | | .byte$02, $8a, $00, $02, $aa, $80, $02, $a2 |
| $2457 | | .byte$80, $02, $a2, $80, $00, $8a, $80, $00 |
| $245F | | .byte$80, $80, $00, $3f, $00, $00, $0f, $00 |
| $2467 | | .byte$00, $0f, $00, $00, $0f, $00, $00, $0f |
| $246F | | .byte$00, $00, $0f, $00, $00, $0f, $00, $00 |
| $2477 | | .byte$0f, $00, $00, $0f, $00, $00, $0f, $c0 |
| $247F | | .byte$06, $00, $41, $40, $00, $44, $00, $00 |
| $2487 | | .byte$44, $00, $00, $45, $40, $00, $41, $40 |
| $248F | | .byte$02, $8a, $00, $02, $aa, $80, $02, $a2 |
| $2497 | | .byte$80, $02, $a2, $80, $00, $8a, $80, $00 |
| $249F | | .byte$80, $80, $00, $3f, $00, $00, $3c, $00 |
| $24A7 | | .byte$00, $3f, $00, $00, $3f, $00, $00, $33 |
| $24AF | | .byte$00, $03, $f3, $00, $03, $03, $00, $03 |
| $24B7 | | .byte$00, $f0, $00, $00, $c0, $00, $00, $00 |
| $24BF | | .byte$06, $00, $41, $40, $00, $44, $00, $00 |
| $24C7 | | .byte$44, $00, $00, $45, $40, $00, $41, $40 |
| $24CF | | .byte$02, $8a, $00, $02, $aa, $80, $02, $a2 |
| $24D7 | | .byte$80, $02, $a2, $80, $00, $a2, $00, $00 |
| $24DF | | .byte$a0, $80, $00, $3f, $00, $00, $3c, $00 |
| $24E7 | | .byte$00, $3f, $00, $00, $0f, $c0, $00, $0c |
| $24EF | | .byte$c0, $00, $ff, $c0, $00, $cc, $00, $00 |
| $24F7 | | .byte$cc, $00, $00, $0c, $00, $00, $0f, $00 |
| $24FF | | .byte$06, $00, $41, $40, $00, $44, $00, $00 |
| $2507 | | .byte$44, $00, $00, $45, $40, $00, $41, $40 |
| $250F | | .byte$02, $8a, $00, $02, $aa, $80, $02, $a2 |
| $2517 | | .byte$80, $02, $a2, $80, $00, $a2, $00, $00 |
| $251F | | .byte$a0, $80, $00, $3f, $00, $00, $3f, $00 |
| $2527 | | .byte$00, $3f, $c0, $00, $33, $c0, $00, $f0 |
| $252F | | .byte$c0, $00, $f3, $00, $00, $c3, $00, $00 |
| $2537 | | .byte$c0, $c0, $00, $c0, $00, $00, $30, $00 |
| $253F | | .byte$06, $00, $41, $40, $00, $44, $00, $00 |
| $2547 | | .byte$44, $00, $00, $45, $40, $00, $41, $40 |
| $254F | | .byte$02, $8a, $00, $02, $aa, $80, $02, $a2 |
| $2557 | | .byte$80, $02, $a2, $80, $00, $a2, $00, $00 |
| $255F | | .byte$a0, $80, $00, $3f, $00, $00, $3f, $00 |
| $2567 | | .byte$00, $ff, $c0, $00, $f3, $c0, $03, $c0 |
| $256F | | .byte$c0, $03, $c0, $c0, $0f, $00, $f0, $0c |
| $2577 | | .byte$00, $00, $0c, $00, $00, $00, $00, $00 |
| $257F | | .byte$06, $00, $41, $40, $00, $44, $00, $00 |
| $2587 | | .byte$44, $00, $00, $45, $40, $00, $41, $40 |
| $258F | | .byte$02, $8a, $00, $02, $aa, $80, $02, $a2 |
| $2597 | | .byte$80, $02, $a2, $80, $00, $8a, $80, $00 |
| $259F | | .byte$80, $80, $00, $3f, $00, $00, $3f, $c0 |
| $25A7 | | .byte$0f, $3c, $c0, $03, $f0, $c0, $00, $f0 |
| $25AF | | .byte$f0 |
| $25B0 | | .fill15, $00 |
| $25BF | | .byte$06, $00, $41, $40, $00, $44, $00, $00 |
| $25C7 | | .byte$44, $00, $00, $45, $40, $00, $41, $40 |
| $25CF | | .byte$02, $8a, $00, $02, $aa, $80, $02, $a2 |
| $25D7 | | .byte$80, $02, $a2, $80, $00, $a2, $00, $00 |
| $25DF | | .byte$a0, $80, $00, $3f, $00, $00, $0f, $00 |
| $25E7 | | .byte$00, $0f, $00, $00, $0c, $00, $00, $0c |
| $25EF | | .byte$00, $00, $3c, $00, $00, $3c, $00, $00 |
| $25F7 | | .byte$30, $00, $00, $30, $00, $00, $30, $00 |
| $25FF | | .byte$06, $00, $51, $40, $01, $04, $40, $01 |
| $2607 | | .byte$04, $40, $01, $54, $40, $00, $50, $40 |
| $260F | | .byte$00, $a2, $80, $02, $08, $80, $02, $aa |
| $2617 | | .byte$00, $08, $a2, $00, $08, $a2, $80, $08 |
| $261F | | .byte$a8, $80, $0c, $fc, $c0, $00, $fc, $00 |
| $2627 | | .byte$00, $cc, $00, $00, $cc, $00, $00, $cc |
| $262F | | .byte$00, $00, $cc, $00, $00, $cc, $00, $00 |
| $2637 | | .byte$cc, $00, $00, $cc, $00, $03, $cf, $00 |
| $263F | | .byte$06, $00, $02, $00, $00, $02, $00, $00 |
| $2647 | | .byte$02 |
| $2648 | | .fill55, $00 |
| $267F | | .byte$07, $00, $0a, $80, $00, $02, $00, $00 |
| $2687 | | .byte$02 |
| $2688 | | .fill55, $00 |
| $26BF | | .byte$07, $00, $2a, $a0, $00, $02, $00, $00 |
| $26C7 | | .byte$02 |
| $26C8 | | .fill55, $00 |
| $26FF | | .byte$07, $02, $aa, $80, $02, $00, $80, $02 |
| $2707 | | .byte$00, $80, $02, $00, $80, $02, $00, $80 |
| $270F | | .byte$02, $00, $80, $02, $00, $80, $02, $00 |
| $2717 | | .byte$80, $02, $00, $80, $02, $00, $80, $02 |
| $271F | | .byte$00, $80, $02, $00, $80, $02, $00, $80 |
| $2727 | | .byte$02, $00, $80, $02, $00, $80, $02, $00 |
| $272F | | .byte$80, $02, $00, $80, $02, $00, $80, $02 |
| $2737 | | .byte$00, $80, $02, $00, $80, $02, $aa, $80 |
| $273F | | .byte$01 |
| $2740 | | .fill30, $00 |
| $275E | | .byte$02, $a2, $88 |
| $2761 | | .fill30, $00 |
| $277F | | .byte$0a |
| $2780 | | .fill30, $00 |
| $279E | | .byte$2a, $28, $88 |
| $27A1 | | .fill30, $00 |
| $27BF | | .byte$0a |
| $27C0 | | .fill30, $00 |
| $27DE | | .byte$28, $aa, $a0 |
| $27E1 | | .fill30, $00 |
| $27FF | | .byte$0a |
| $2800 | | .fill30, $00 |
| $281E | | .byte$02, $aa, $80 |
| $2821 | | .fill30, $00 |
| $283F | | .byte$0a |
| $2840 | | .fill31, $00 |
| $285F | | .byte$20, $00, $00, $a0, $00, $00, $28, $00 |
| $2867 | | .byte$00, $20, $00, $00, $20, $00, $00, $54 |
| $286F | | .byte$00, $00, $54, $00, $00, $54, $00, $00 |
| $2877 | | .byte$54, $00, $00, $54, $00, $00, $54, $00 |
| $287F | | .byte$07 |
| $2880 | | .fill31, $00 |
| $289F | | .byte$80, $00, $00, $08, $00, $00, $28, $00 |
| $28A7 | | .byte$00, $20, $00, $00, $a8, $00, $00, $54 |
| $28AF | | .byte$00, $00, $54, $00, $00, $54, $00, $00 |
| $28B7 | | .byte$54, $00, $00, $54, $00, $00, $54, $00 |
| $28BF | | .byte$07 |
| $28C0 | | .fill31, $00 |
| $28DF | | .byte$08, $00, $00, $80, $00, $00, $a0, $00 |
| $28E7 | | .byte$00, $20, $00, $00, $20, $00, $00, $54 |
| $28EF | | .byte$00, $00, $54, $00, $00, $54, $00, $00 |
| $28F7 | | .byte$54, $00, $00, $54, $00, $00, $54, $00 |
| $28FF | | .byte$07 |
| $2900 | | .fill37, $00 |
| $2925 | | .byte$28, $00, $00, $aa, $00, $00, $aa, $00 |
| $292D | | .byte$00, $28, $00, $00, $aa, $00, $00, $aa |
| $2935 | | .byte$00, $00, $28, $00, $00, $00, $00, $00 |
| $293D | | .byte$00, $00, $07 |
| $2940 | | .fill30, $00 |
| $295E | | .byte$02, $20, $80, $00, $28, $00, $00, $aa |
| $2966 | | .byte$00, $00, $aa, $00, $08, $2a, $20, $00 |
| $296E | | .byte$a8, $00, $02, $aa, $00, $00, $aa, $80 |
| $2976 | | .byte$00, $28, $00, $00, $2a, $00, $02, $02 |
| $297E | | .byte$20, $07 |
| $2980 | | .fill39, $00 |
| $29A7 | | .byte$0a, $8a, $80, $00, $88, $00, $00, $8a |
| $29AF | | .byte$80, $00, $80, $80, $00, $8a, $80 |
| $29B6 | | .fill9, $00 |
| $29BF | | .byte$07, $00, $00, $00, $00, $30, $00, $00 |
| $29C7 | | .byte$30, $00, $00, $30, $00, $00, $30, $00 |
| $29CF | | .byte$00, $30, $00, $00, $30, $00, $00, $20 |
| $29D7 | | .byte$00, $02, $22, $00, $08, $a8, $80, $08 |
| $29DF | | .byte$a8, $80, $08, $20, $80, $08, $00, $80 |
| $29E7 | | .fill24, $00 |
| $29FF | | .byte$07, $00, $00, $00, $00, $30, $00, $00 |
| $2A07 | | .byte$30, $00, $00, $30, $00, $00, $30, $00 |
| $2A0F | | .byte$00, $30, $00, $00, $30, $00, $02, $22 |
| $2A17 | | .byte$00, $08, $a8, $80, $08, $a8, $80, $08 |
| $2A1F | | .byte$20, $80, $08, $00, $80 |
| $2A24 | | .fill27, $00 |
| $2A3F | | .byte$07 |
| $2A40 | | .fill18, $00 |
| $2A52 | | .byte$08, $00, $80, $08, $88, $80, $0a, $22 |
| $2A5A | | .byte$80, $0a, $8a, $80, $0a, $aa, $80, $02 |
| $2A62 | | .byte$aa, $00, $00, $20 |
| $2A66 | | .fill25, $00 |
| $2A7F | | .byte$08 |
| $2A80 | | .fill22, $00 |
| $2A96 | | .byte$88, $00, $00, $20, $00, $00, $a8, $00 |
| $2A9E | | .byte$02, $aa, $00, $0a, $22, $80, $0a, $02 |
| $2AA6 | | .byte$80, $08, $00, $80, $02, $02 |
| $2AAC | | .fill19, $00 |
| $2ABF | | .byte$08 |
| $2AC0 | | .fill16, $00 |
| $2AD0 | | .byte$30, $00, $00, $fc, $00, $00, $cc, $00 |
| $2AD8 | | .byte$00, $44, $00, $00, $54, $00, $01, $55 |
| $2AE0 | | .byte$00, $00, $54, $00, $00, $44, $00, $00 |
| $2AE8 | | .byte$cc, $00, $00, $fc, $00, $00, $30 |
| $2AEF | | .fill16, $00 |
| $2AFF | | .byte$01 |
| $2B00 | | .fill16, $00 |
| $2B10 | | .byte$cc, $00, $00, $cc, $00, $00, $cc, $00 |
| $2B18 | | .byte$00, $44, $00, $00, $54, $00, $01, $55 |
| $2B20 | | .byte$00, $00, $54, $00, $00, $44, $00, $00 |
| $2B28 | | .byte$cc, $00, $00, $cc, $00, $00, $cc |
| $2B2F | | .fill16, $00 |
| $2B3F | | .byte$01 |
| $2B40 | | .fill15, $00 |
| $2B4F | | .byte$0c, $00, $c0, $0f, $03, $c0, $03, $cf |
| $2B57 | | .byte$00, $00, $44, $00, $00, $54, $00, $01 |
| $2B5F | | .byte$55, $00, $00, $54, $00, $00, $44, $00 |
| $2B67 | | .byte$03, $cf, $00, $0f, $03, $c0, $0c, $00 |
| $2B6F | | .byte$c0 |
| $2B70 | | .fill15, $00 |
| $2B7F | | .byte$01 |
| $2B80 | | .fill15, $00 |
| $2B8F | | .byte$03, $03, $00, $03, $cf, $00, $00, $cc |
| $2B97 | | .byte$00, $00, $44, $00, $00, $54, $00, $01 |
| $2B9F | | .byte$55, $00, $00, $54, $00, $00, $44, $00 |
| $2BA7 | | .byte$00, $cc, $00, $03, $cf, $00, $03, $03 |
| $2BAF | | .fill16, $00 |
| $2BBF | | .byte$01 |
| $2BC0 | | .fill21, $00 |
| $2BD5 | | .byte$28, $00, $00, $22, $00, $00, $2a, $00 |
| $2BDD | | .byte$00, $a2, $00, $00, $2a, $00, $00, $08 |
| $2BE5 | | .fill26, $00 |
| $2BFF | | .byte$05 |
| $2C00 | | .fill21, $00 |
| $2C15 | | .byte$02, $80, $00, $0a, $20, $00, $2a, $a0 |
| $2C1D | | .byte$00, $a8, $20, $00, $2a, $a0, $00, $00 |
| $2C25 | | .byte$80 |
| $2C26 | | .fill25, $00 |
| $2C3F | | .byte$05 |
| $2C40 | | .fill22, $00 |
| $2C56 | | .byte$28, $00, $00, $a2, $00, $2a, $aa, $00 |
| $2C5E | | .byte$aa, $a2, $00, $2a, $aa, $00, $00, $08 |
| $2C66 | | .fill25, $00 |
| $2C7F | | .byte$05 |
| $2C80 | | .fill22, $00 |
| $2C96 | | .byte$02, $80, $00, $0a, $20, $2a, $aa, $a0 |
| $2C9E | | .byte$aa, $a8, $20, $2a, $aa, $00, $00, $02 |
| $2CA6 | | .byte$a0, $00, $00, $80 |
| $2CAA | | .fill21, $00 |
| $2CBF | | .byte$05 |
| $2CC0 | | .fill23, $00 |
| $2CD7 | | .byte$28, $00, $00, $a2, $2a, $aa, $aa, $aa |
| $2CDF | | .byte$aa, $a2, $2a, $aa, $aa, $00, $00, $02 |
| $2CE7 | | .fill24, $00 |
| $2CFF | | .byte$05 |
| $2D00 | | .fill37, $00 |
| $2D25 | | .byte$a0, $00, $02, $88, $00, $0a, $02 |
| $2D2C | | .fill19, $00 |
| $2D3F | | .byte$0e |
| $2D40 | | .fill31, $00 |
| $2D5F | | .byte$a8, $00, $02, $8a, $00, $0a, $02, $80 |
| $2D67 | | .byte$08, $00, $80, $0a, $02 |
| $2D6C | | .fill19, $00 |
| $2D7F | | .byte$0e |
| $2D80 | | .fill19, $00 |
| $2D93 | | .byte$a8, $00, $02, $8a, $00, $02, $02, $00 |
| $2D9B | | .byte$0a, $02, $80, $08, $00, $80, $08, $22 |
| $2DA3 | | .byte$80, $0a, $0a, $00, $02, $00, $00, $00 |
| $2DAB | | .byte$8a |
| $2DAC | | .fill19, $00 |
| $2DBF | | .byte$0e |
| $2DC0 | | .fill19, $00 |
| $2DD3 | | .byte$a8, $00, $02, $8a, $00, $0a, $02, $80 |
| $2DDB | | .byte$08, $20, $80, $08, $82, $80, $08, $82 |
| $2DE3 | | .byte$00, $08, $28, $00, $0a, $00, $00, $02 |
| $2DEB | | .byte$8a |
| $2DEC | | .fill19, $00 |
| $2DFF | | .byte$0e |
| $2E00 | | .fill13, $00 |
| $2E0D | | .byte$a8, $00, $02, $02, $00, $0a, $20, $80 |
| $2E15 | | .byte$08, $88, $80, $08, $80, $80, $08, $82 |
| $2E1D | | .byte$00, $08, $28, $00, $0a, $00, $00, $02 |
| $2E25 | | .byte$0a, $00, $02, $0a, $00, $02, $2a, $80 |
| $2E2D | | .fill18, $00 |
| $2E3F | | .byte$0e |
| $2E40 | | .fill24, $00 |
| $2E58 | | .byte$0a, $8a, $80, $08, $08, $80, $0a, $88 |
| $2E60 | | .byte$80, $00, $88, $80, $0a, $8a, $80 |
| $2E67 | | .fill24, $00 |
| $2E7F | | .byte$01 |
| $2E80 | | .fill19, $00 |
| $2E93 | | .byte$2a, $80, $00, $20, $80, $00, $a8, $80 |
| $2E9B | | .byte$02, $aa, $80, $00, $fc, $c0, $02, $aa |
| $2EA3 | | .byte$80, $00, $fc, $c0, $00, $30, $c0 |
| $2EAA | | .fill21, $00 |
| $2EBF | | .byte$0b |
| $2EC0 | | .fill57, $00 |
| $2EF9 | | .byte$2a, $aa, $a8, $2a, $aa, $a8, $07 |
| $2F00 | | .fill22, $00 |
| $2F16 | | .byte$80, $00, $03, $f0, $00, $02, $80, $00 |
| $2F1E | | .byte$02, $80, $00, $02, $00, $00, $05, $40 |
| $2F26 | | .byte$00, $04, $40, $00, $04, $40, $00, $04 |
| $2F2E | | .byte$40, $00, $04, $40, $00, $0c, $f3, $00 |
| $2F36 | | .byte$0f, $0f, $c0, $0f, $fc, $c0, $03, $f0 |
| $2F3E | | .byte$f0, $08 |
| $2F40 | | .fill22, $00 |
| $2F56 | | .byte$80, $00, $03, $f0, $00, $02, $80, $00 |
| $2F5E | | .byte$02, $82, $00, $02, $02, $00, $05, $41 |
| $2F66 | | .byte$00, $04, $15, $00, $04, $40, $00, $05 |
| $2F6E | | .byte$40, $00, $05, $40, $00, $0f, $ff, $00 |
| $2F76 | | .byte$0f, $ff, $c0, $0f, $fc, $c0, $03, $f0 |
| $2F7E | | .byte$f0, $08 |
| $2F80 | | .fill22, $00 |
| $2F96 | | .byte$02, $00, $00, $0f, $c0, $00, $02, $80 |
| $2F9E | | .byte$00, $02, $80, $00, $00, $80, $00, $01 |
| $2FA6 | | .byte$50, $00, $01, $10, $00, $01, $10, $00 |
| $2FAE | | .byte$01, $10, $00, $01, $10, $00, $cf, $30 |
| $2FB6 | | .byte$03, $f0, $f0, $03, $3f, $f0, $0f, $0f |
| $2FBE | | .byte$c0, $08 |
| $2FC0 | | .fill22, $00 |
| $2FD6 | | .byte$02, $00, $00, $0f, $c0, $00, $02, $80 |
| $2FDE | | .byte$00, $82, $80, $00, $80, $80, $00, $41 |
| $2FE6 | | .byte$50, $00, $54, $10, $00, $01, $10, $00 |
| $2FEE | | .byte$01, $50, $00, $01, $50, $00, $ff, $f0 |
| $2FF6 | | .byte$03, $ff, $f0, $03, $3f, $f0, $0f, $0f |
| $2FFE | | .byte$c0, $08 |
| ; -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= |
| ; Charset |
| $3000 | | .byte$00, $00, $3c, $3c, $3c, $3c, $00, $00 |
| $3008 | | .byte$3c, $66, $66, $7e, $66, $66, $66, $00 |
| $3010 | | .byte$7c, $66, $66, $7c, $66, $66, $7c, $00 |
| $3018 | | .byte$3c, $62, $60, $60, $60, $62, $3c, $00 |
| $3020 | | .byte$7c, $66, $66, $66, $66, $66, $7c, $00 |
| $3028 | | .byte$7e, $60, $60, $7c, $60, $60, $7e, $00 |
| $3030 | | .byte$7e, $60, $60, $7c, $60, $60, $60, $00 |
| $3038 | | .byte$3c, $62, $60, $6e, $66, $66, $3c, $00 |
| $3040 | | .byte$66, $66, $66, $7e, $66, $66, $66, $00 |
| $3048 | | .byte$3c, $18, $18, $18, $18, $18, $3c, $00 |
| $3050 | | .byte$0e, $06, $06, $06, $66, $66, $3c, $00 |
| $3058 | | .byte$66, $6c, $78, $70, $78, $6c, $66, $00 |
| $3060 | | .byte$60, $60, $60, $60, $60, $60, $7e, $00 |
| $3068 | | .byte$42, $66, $7e, $66, $66, $66, $66, $00 |
| $3070 | | .byte$66, $76, $7e, $6e, $66, $66, $66, $00 |
| $3078 | | .byte$3c, $66, $66, $66, $66, $66, $3c, $00 |
| $3080 | | .byte$7c, $66, $66, $7c, $60, $60, $60, $00 |
| $3088 | | .byte$3c, $66, $66, $66, $6e, $66, $3d, $00 |
| $3090 | | .byte$7c, $66, $66, $7c, $66, $66, $66, $00 |
| $3098 | | .byte$3c, $62, $60, $3c, $06, $46, $3c, $00 |
| $30A0 | | .byte$7e, $18, $18, $18, $18, $18, $18, $00 |
| $30A8 | | .byte$66, $66, $66, $66, $66, $66, $3c, $00 |
| $30B0 | | .byte$66, $66, $66, $66, $66, $3c, $18, $00 |
| $30B8 | | .byte$66, $66, $66, $66, $7e, $66, $42, $00 |
| $30C0 | | .byte$66, $66, $3c, $18, $3c, $66, $66, $00 |
| $30C8 | | .byte$66, $66, $66, $3c, $18, $18, $18, $00 |
| $30D0 | | .byte$7e, $06, $0c, $18, $30, $60, $7e, $00 |
| $30D8 | | .byte$00, $00, $00, $00, $00, $04, $02, $01 |
| $30E0 | | .byte$00, $00, $00, $02, $06, $42, $82, $27 |
| $30E8 | | .byte$00, $00, $00, $1c, $02, $0c, $10, $5e |
| $30F0 | | .byte$00, $00, $00, $00, $00, $00, $00, $ff |
| $30F8 | | .fill16, $00 |
| $3108 | | .byte$18, $18, $18, $18, $00, $18, $18, $00 |
| $3110 | | .byte$66, $66, $cc, $00, $00, $00, $00, $00 |
| $3118 | | .byte$3c, $42, $99, $a1, $a1, $99, $42, $3c |
| $3120 | | .byte$1c, $22, $49, $55, $55, $4e, $20, $1c |
| $3128 | | .fill16, $00 |
| $3138 | | .byte$18, $18, $30, $00, $00, $00, $00, $00 |
| $3140 | | .byte$18, $30, $30, $30, $30, $30, $18, $00 |
| $3148 | | .byte$18, $0c, $0c, $0c, $0c, $0c, $18 |
| $314F | | .fill10, $00 |
| $3159 | | .byte$18, $18, $7e, $18, $18, $00, $00, $00 |
| $3161 | | .byte$00, $00, $00, $00, $18, $18, $30, $00 |
| $3169 | | .byte$00, $00, $7c |
| $316C | | .fill9, $00 |
| $3175 | | .byte$18, $18 |
| $3177 | | .fill9, $00 |
| $3180 | | .byte$3c, $66, $66, $66, $66, $66, $3c, $00 |
| $3188 | | .byte$18, $38, $18, $18, $18, $18, $3c, $00 |
| $3190 | | .byte$3c, $46, $06, $0c, $18, $30, $7e, $00 |
| $3198 | | .byte$7e, $04, $08, $1c, $06, $46, $3c, $00 |
| $31A0 | | .byte$0c, $1c, $2c, $4c, $7e, $0c, $0c, $00 |
| $31A8 | | .byte$7e, $60, $7c, $06, $06, $46, $3c, $00 |
| $31B0 | | .byte$3c, $62, $60, $7c, $66, $66, $3c, $00 |
| $31B8 | | .byte$7e, $06, $0c, $18, $30, $30, $30, $00 |
| $31C0 | | .byte$3c, $66, $66, $3c, $66, $66, $3c, $00 |
| $31C8 | | .byte$3c, $66, $66, $3e, $06, $46, $3c, $00 |
| $31D0 | | .byte$00, $00, $18, $18, $00, $18, $18 |
| $31D7 | | .fill41, $00 |
| ; Double width charset: 0-9 |
| $3200 | | .byte$0f, $3c, $3c, $3c, $3c, $3c, $3c, $0f |
| $3208 | | .byte$03, $0f, $03, $03, $03, $03, $03, $0f |
| $3210 | | .byte$0f, $0c, $00, $00, $0f, $3c, $3c, $3f |
| $3218 | | .byte$0f, $0c, $00, $00, $00, $00, $0c, $0f |
| $3220 | | .byte$00, $03, $0c, $30, $3f, $00, $00, $00 |
| $3228 | | .byte$3f, $3c, $3c, $3f, $00, $00, $30, $3f |
| $3230 | | .byte$0f, $3c, $3c, $3f, $3c, $3c, $3c, $0f |
| $3238 | | .byte$3f, $30, $00, $00, $03, $03, $03, $03 |
| $3240 | | .byte$0f, $3c, $3c, $0f, $0f, $3c, $3c, $0f |
| $3248 | | .byte$0f, $3c, $3c, $3c, $0f, $00, $30, $0f |
| $3250 | | .byte$f0, $3c, $3c, $3c, $3c, $3c, $3c, $f0 |
| $3258 | | .byte$c0, $c0, $c0, $c0, $c0, $c0, $c0, $f0 |
| $3260 | | .byte$f0, $3c, $3c, $3c, $f0, $00, $00, $fc |
| $3268 | | .byte$f0, $3c, $3c, $f0, $f0, $3c, $3c, $f0 |
| $3270 | | .byte$f0, $f0, $f0, $f0, $fc, $f0, $f0, $f0 |
| $3278 | | .byte$fc, $00, $00, $f0, $3c, $3c, $3c, $f0 |
| $3280 | | .byte$f0, $0c, $00, $f0, $3c, $3c, $3c, $f0 |
| $3288 | | .byte$fc, $0c, $3c, $f0, $c0, $c0, $c0, $c0 |
| $3290 | | .byte$f0, $3c, $3c, $f0, $f0, $3c, $3c, $f0 |
| $3298 | | .byte$f0, $3c, $3c, $3c, $f0, $3c, $3c, $f0 |
| ; End of double-width charset |
| ; Being of "power..." charset |
| $32A0 | | .byte$0f, $0c, $0f, $0c, $0c, $00, $00, $00 |
| $32A8 | | .byte$cf, $cc, $cc, $0c, $0f, $00, $00, $00 |
| $32B0 | | .byte$cc, $cc, $cf, $cf, $cc, $00, $00, $00 |
| $32B8 | | .byte$0c, $cc, $fc, $3c, $0c, $00, $00, $00 |
| $32C0 | | .byte$fc, $c0, $f0, $c0, $f0, $00, $00, $00 |
| $32C8 | | .byte$fc, $cc, $f0, $cc, $cc, $00, $00, $00 |
| $32D0 | | .byte$55, $55, $55, $55, $55, $00, $00, $00 |
| $32D8 | | .byte$d5, $d5, $d5, $d5, $d5, $00, $00, $00 |
| $32E0 | | .byte$f5, $f5, $f5, $f5, $f5, $00, $00, $00 |
| $32E8 | | .byte$fd, $fd, $fd, $fd, $fd, $00, $00, $00 |
| $32F0 | | .byte$ff, $ff, $ff, $ff, $ff, $00, $00, $00 |
| $32F8 | | .byte$03, $00, $00, $00, $00, $00, $00, $00 |
| $3300 | | .byte$f0, $c0, $45, $45, $44, $a2, $22, $22 |
| $3308 | | .byte$0c, $0c, $3c, $30, $30, $00, $00, $00 |
| $3310 | | .byte$00, $0c, $3c, $0f, $0c, $0c, $15, $15 |
| $3318 | | .byte$15, $15, $15, $15, $00, $00, $00, $00 |
| ; "Level:" charset |
| $3320 | | .fill8, $03 |
| $3328 | | .byte$c0, $c0, $c0, $c0, $c0, $c0, $fc, $fc |
| $3330 | | .byte$ff, $ff, $f0, $fc, $fc, $f0, $ff, $ff |
| $3338 | | .byte$3c, $3c, $3c, $3c, $3c, $0f, $0f, $03 |
| $3340 | | .byte$f3, $f3, $f3, $f3, $f3, $c3, $c3, $03 |
| $3348 | | .byte$fc, $fc, $c0, $f0, $f0, $c0, $fc, $fc |
| $3350 | | .byte$f0, $f0, $f0, $f0, $f0, $f0, $ff, $ff |
| $3358 | | .byte$3c, $3c, $3c, $00, $00, $3c, $3c, $3c |
| ; LC Games charset |
| $3360 | | .byte$df, $df, $d8, $df, $df, $c0, $ff, $ff |
| $3368 | | .byte$3c, $7d, $61, $6d, $6d, $6d, $7d, $3d |
| $3370 | | .byte$e6, $f7, $b7, $f7, $f6, $b6, $b6, $b6 |
| $3378 | | .byte$37, $77, $f6, $f7, $b7, $36, $37, $37 |
| $3380 | | .byte$cf, $df, $18, $9e, $8f, $03, $df, $de |
| ; HERO double-width charset |
| $3388 | | .byte$30, $fc, $fc, $ff, $ff, $fc, $fc, $30 |
| $3390 | | .byte$30, $fc, $fc, $fc, $fc, $fc, $fc, $33 |
| $3398 | | .byte$3f, $ff, $fc, $ff, $ff, $fc, $ff, $3f |
| $33A0 | | .byte$f0, $fc, $00, $c0, $c0, $00, $fc, $f3 |
| $33A8 | | .byte$3f, $ff, $fc, $fc, $ff, $ff, $fc, $30 |
| $33B0 | | .byte$c0, $f0, $fc, $fc, $f0, $c0, $f0, $3c |
| $33B8 | | .byte$0f, $3f, $fc, $fc, $fc, $fc, $3f, $cf |
| $33C0 | | .byte$c0, $f0, $fc, $fc, $fc, $fc, $f0, $c3 |
| ; Logo charset |
| $33C8 | | .byte$7c, $fe, $fe, $fe, $fa, $fe, $fa, $fa |
| $33D0 | | .byte$07, $0f, $0f, $0f, $0f, $0f, $0f, $0f |
| $33D8 | | .byte$c0, $e0, $e0, $e0, $a0, $e0, $a0, $a0 |
| $33E0 | | .byte$7f, $ff, $ff, $ff, $ff, $7f, $3f, $1f |
| $33E8 | | .byte$ff, $ff, $ff, $ff, $ff, $80, $df, $e8 |
| $33F0 | | .byte$fc, $fe, $fe, $fe, $fa, $06, $fc, $00 |
| $33F8 | | .byte$7f, $ff, $ff, $ff, $ff, $7f, $7f, $3f |
| $3400 | | .byte$ff, $ff, $ff, $ff, $ff, $00, $7f, $a0 |
| $3408 | | .byte$f0, $fc, $fe, $fb, $fd, $3e, $de, $3f |
| $3410 | | .byte$00, $00, $00, $00, $80, $80, $c0, $40 |
| $3418 | | .byte$01, $0f, $3f, $7f, $ff, $fe, $f9, $f7 |
| $3420 | | .byte$ff, $ff, $ff, $ff, $ff, $00, $ff, $01 |
| $3428 | | .byte$00, $e0, $f8, $fc, $ff, $ff, $3f, $df |
| $3430 | | .byte$00, $00, $00, $00, $00, $80, $c0, $e0 |
| $3438 | | .byte$fa, $fa, $fa, $fa, $fa, $fa, $e0, $df |
| $3440 | | .byte$00, $00, $00, $00, $00, $00, $00, $ff |
| $3448 | | .byte$0f, $0f, $0f, $0f, $0f, $0f, $00, $ff |
| $3450 | | .byte$a0, $a0, $a0, $a0, $a0, $a0, $00, $f0 |
| $3458 | | .byte$0f, $07, $03, $01, $00, $00, $00, $7f |
| $3460 | | .byte$f4, $fa, $fd, $fe, $ff, $7f, $3f, $ff |
| $3468 | | .byte$00, $00, $00, $80, $40, $a0, $d0, $e8 |
| $3470 | | .byte$3f, $1f, $0f, $0f, $07, $07, $00, $7f |
| $3478 | | .byte$a0, $d0, $d0, $e8, $f4, $f4, $00, $ff |
| $3480 | | .byte$1f, $1f, $1f, $1f, $1f, $1f, $3f, $fe |
| $3488 | | .byte$40, $40, $40, $40, $40, $40, $40, $c0 |
| $3490 | | .byte$0f, $1f, $3f, $3f, $7e, $7d, $7d, $fb |
| $3498 | | .byte$4c, $b8, $40, $40, $c0, $80, $00, $00 |
| $34A0 | | .byte$7f, $1f, $0f, $07, $03, $03, $01, $01 |
| $34A8 | | .byte$e0, $f0, $d8, $e8, $ec, $f4, $f4, $f6 |
| $34B0 | | .byte$bf, $bf, $bf, $bf, $df, $ef, $f7, $fb |
| $34B8 | | .byte$ff, $ff, $ff, $ff, $e0, $f7, $fa, $fd |
| $34C0 | | .byte$ff, $ff, $ff, $ff, $00, $ff, $00, $0f |
| $34C8 | | .byte$f8, $f8, $f8, $e8, $18, $f0, $00, $a0 |
| $34D0 | | .byte$ff, $ff, $ff, $ff, $fc, $fb, $fa, $fa |
| $34D8 | | .byte$ff, $ff, $ff, $ff, $00, $ff, $00, $00 |
| $34E0 | | .byte$f4, $fa, $fa, $fa, $06, $fc, $00, $00 |
| $34E8 | | .byte$ff, $ff, $ff, $ff, $00, $ff, $00, $1f |
| $34F0 | | .byte$fe, $fd, $fb, $e6, $1c, $f0, $00, $d0 |
| $34F8 | | .byte$80, $80, $00, $00, $00, $00, $00, $00 |
| $3500 | | .byte$fa, $fa, $fa, $fa, $fa, $fa, $fa, $fb |
| $3508 | | .byte$00, $00, $00, $00, $00, $00, $00, $01 |
| $3510 | | .byte$fa, $fa, $fa, $fa, $fa, $fa, $fa, $f6 |
| $3518 | | .byte$f9, $fa, $fa, $fa, $fa, $fa, $fa, $fa |
| $3520 | | .byte$fe, $ff, $7f, $3f, $1f, $0f, $07, $03 |
| $3528 | | .byte$8f, $4f, $af, $df, $ef, $f7, $fb, $ff |
| $3530 | | .fill8, $a0 |
| $3538 | | .fill8, $fa |
| $3540 | | .byte$0f, $0f, $07, $07, $03, $01, $01, $00 |
| $3548 | | .byte$d0, $e8, $f4, $f4, $fa, $fa, $fd, $fd |
| $3550 | | .byte$00, $00, $00, $00, $00, $00, $00, $80 |
| $3558 | | .byte$7d, $7d, $7e, $3f, $3f, $1f, $0f, $0f |
| $3560 | | .byte$00, $80, $80, $c0, $e0, $f0, $fc, $ff |
| $3568 | | .byte$01, $03, $03, $07, $0f, $1f, $7f, $ff |
| $3570 | | .byte$f4, $f4, $ec, $e8, $d8, $b0, $a0, $60 |
| $3578 | | .byte$fa, $fa, $fa, $fa, $fa, $f6, $7c, $00 |
| $3580 | | .byte$01, $00, $00, $00, $00, $00, $00, $00 |
| $3588 | | .byte$ff, $ff, $7f, $3f, $1f, $0f, $07, $00 |
| $3590 | | .byte$a0, $a0, $a0, $a0, $a0, $60, $c0, $00 |
| $3598 | | .byte$fb, $ff, $ff, $ff, $ff, $c0, $7f, $00 |
| $35A0 | | .byte$ff, $ff, $ff, $ff, $ff, $00, $ff, $00 |
| $35A8 | | .byte$c0, $e0, $e0, $e0, $a0, $60, $c0, $00 |
| $35B0 | | .byte$fe, $7f, $3f, $3f, $1f, $1f, $0f, $00 |
| $35B8 | | .byte$80, $40, $40, $a0, $a0, $60, $c0, $00 |
| $35C0 | | .byte$07, $03, $01, $00, $00, $00, $00, $00 |
| $35C8 | | .byte$ff, $ff, $df, $67, $38, $0f, $01, $00 |
| $35D0 | | .byte$ff, $ff, $ff, $ff, $fe, $01, $ff, $00 |
| $35D8 | | .byte$fe, $f9, $f7, $cc, $38, $e0, $00, $00 |
| $35E0 | | .byte$c0, $80, $00, $00, $00, $00, $00, $00 |
| $35E8 | | .byte$38, $7c, $fe, $fe, $fa, $74, $38, $00 |
| ; is back --- charset |
| $35F0 | | .fill8, $06 |
| $35F8 | | .byte$7e, $fe, $c0, $fc, $7e, $06, $fe, $fc |
| $3600 | | .byte$fc, $fe, $c6, $fc, $fe, $c6, $fe, $fc |
| $3608 | | .byte$38, $38, $7c, $6c, $7c, $fe, $c6, $c6 |
| $3610 | | .byte$7c, $fe, $c6, $c0, $c0, $c6, $fe, $7c |
| $3618 | | .byte$c6, $ce, $dc, $f8, $f8, $dc, $ce, $c6 |
| $3620 | | .byte$00, $00, $00, $ff, $00, $00, $00, $00 |
| $3628 | | .byte$00, $00, $00, $f0, $00, $00, $00, $00 |
| ; Temporary buffer for BCD-to-ASCII digit conversion. |
| ; Holds individual ASCII digit characters (units at [0], tens at [1], etc.). |
| ; Also used as an indexed array: bcd_digit_buffer,x |
| $3630 | | bcd_digit_buffer.byte$00; x-ref: $3702, $371A, $372A, $373F, $374E, ... |
| $3631 | | bcd_digit_tens.byte$00; Tens digit of BCD conversion result (ASCII) ; x-ref: $3705, $6429 |
| $3632 | | bcd_digit_hundreds.byte$00, $00, $00, $00, $00, $00; Hundreds digit of BCD conversion result (ASCII) ; x-ref: $3708, $642C |
| ; Leading-zero suppression disable flag. |
| ; When non-zero, all digits are printed including leading zeros. |
| ; When zero, leading '0' chars are replaced with spaces. |
| zero_suppress_disable |
| $3638 | | .byte$00; x-ref: $373A, $6109, $6D4E |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| ; Sets VIC-II vertical scroll offset to 3 and enables 25-row display mode. |
| ; Clears bitmap mode (bit 5) while preserving DEN, ECM, and RST8 bits. |
| ; |
| ; Inputs: None |
| ; Outputs: A (modified) |
| ; Side Effects: Modifies VIC-II Control Register 1 ($D011) |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| set_vic_scroll_and_rows |
| $3639 | ad 11 d0 | lda$d011; Read current VIC-II control register 1 ; x-ref: $6966, $6D49 VIC Control Register 1 |
| $363C | 29 d0 | and#$d0; Keep DEN, ECM, RST8; clear YSCROLL, RSEL, BMM |
| $363E | 09 0b | ora#$0b; Set YSCROLL=3, RSEL=1 (25 rows) |
| $3640 | 8d 11 d0 | sta$d011; Apply updated scroll/row settings; VIC Control Register 1 |
| $3643 | 60 | rts |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| ; Clears the entire screen memory ($0400-$07E7) with spaces ($20) |
| ; and fills color RAM ($D800-$DBE7) with the color value in Y. |
| ; |
| ; Inputs: Y = color value to fill color RAM with |
| ; Outputs: X = 0 (loop counter exhausted), A = Y (color value) |
| ; Side Effects: Screen memory and color RAM are overwritten |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| $3644 | a2 00 | clear_screenldx#$00; Start index at 0 ; x-ref: $5ECB, $6041, $614C, $6608, $6675, ... |
| $3646 | a9 20 | b_3646lda#$20; Space character (screen clear) ; x-ref: $3664 |
| $3648 | 9d 00 04 | staSCREEN_RAM,x; Screen RAM rows 0-5 ($0400+X) |
| $364B | 9d fa 04 | staSCREEN_RAM_R6C10,x; Screen RAM rows 6-12 ($04FA+X) |
| $364E | 9d f4 05 | staSCREEN_RAM_R12C20,x; Screen RAM rows 12-18 ($05F4+X) |
| $3651 | 9d ee 06 | staSCREEN_RAM_R18C30,x; Screen RAM rows 18-24 ($06EE+X) |
| $3654 | 98 | tya; Use Y as color value |
| $3655 | 9d 00 d8 | staCOLOR_RAM,x; Fill color RAM rows 0-5 |
| $3658 | 9d fa d8 | staCOLOR_RAM_R6C10,x; Fill color RAM rows 6-12 |
| $365B | 9d f4 d9 | staCOLOR_RAM_R12C20,x; Fill color RAM rows 12-18 |
| $365E | 9d ee da | staCOLOR_RAM_R18C30,x; Fill color RAM rows 18-24 |
| $3661 | e8 | inx; Next byte |
| $3662 | e0 fa | cpx#$fa; Loop 250 times (4x250 = 1000 bytes) |
| $3664 | d0 e0 | bneb_3646 |
| $3666 | 60 | rts |
| $3667 | ad 11 d0 | enable_screenlda$d011; x-ref: $5F25, $60B3, $6166, $6638, $668D, ...; VIC Control Register 1 |
| $366A | 29 10 | and#$10 |
| $366C | d0 0f | bner_367D |
| $366E | a9 3c | lda#$3c |
| $3670 | cd 12 d0 | b_3670cmp$d012; x-ref: $3673 Raster Position |
| $3673 | b0 fb | bcsb_3670 |
| $3675 | ad 11 d0 | lda$d011; VIC Control Register 1 |
| $3678 | 09 10 | ora#$10 |
| $367A | 8d 11 d0 | sta$d011; VIC Control Register 1 |
| $367D | 60 | r_367Drts; x-ref: $366C |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| ; Blanks the screen by clearing the VIC-II DEN (Display Enable) bit. |
| ; Waits for the raster to reach line 251 (bottom border) before disabling |
| ; the display to avoid visual glitches. If the display is already blanked, |
| ; returns immediately. After blanking, disables VIC interrupts and restores |
| ; the default KERNAL IRQ vector via j_218E. |
| ; |
| ; Inputs: None |
| ; Outputs: None |
| ; Side Effects: Display is turned off, VIC interrupts disabled, IRQ vector restored |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| $367E | ad 11 d0 | blank_screenlda$d011; Read VIC-II control register 1 ; x-ref: $5EC8, $603C, $6104, $6122, $65F8, ...; VIC Control Register 1 |
| $3681 | 29 10 | and#$10; Isolate DEN bit (bit 4 = display enable) |
| $3683 | f0 12 | beqr_3697; Display already off? Skip |
| $3685 | a9 fb | lda#$fb; Target raster line 251 (bottom border) |
| $3687 | cd 12 d0 | b_3687cmp$d012; Wait for raster to reach line 251 ; x-ref: $368A Raster Position |
| $368A | b0 fb | bcsb_3687 |
| $368C | ad 11 d0 | lda$d011; Read control register again; VIC Control Register 1 |
| $368F | 29 ef | and#$ef; Clear DEN bit to blank display |
| $3691 | 8d 11 d0 | sta$d011; Store back: display now off; VIC Control Register 1 |
| $3694 | 4c 8e 21 | jmpirq_raster_disable; Disable VIC IRQs, restore default KERNAL IRQ |
| $3697 | 60 | r_3697rts; x-ref: $3683 |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| ; Waits for a specified number of video frames by polling the VIC-II raster |
| ; register ($D012). Loops until raster line $FB is reached, repeating X times. |
| ; Used as a frame-accurate delay (e.g., X=$3C ≈ 60 frames ≈ ~1 second on PAL). |
| ; |
| ; Inputs: X = number of frames to wait |
| ; Outputs: X = 0, A = #$FB (clobbered) |
| ; Side Effects: Blocks execution until the raster condition is met X times |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| $3698 | a9 fb | wait_raster_frameslda#$fb; Target raster line = 251 (near bottom of screen) ; x-ref: $60B0 |
| $369A | cd 12 d0 | b_369Acmp$d012; Wait while raster hasn't reached target line yet ; x-ref: $369D, $36A5 Raster Position |
| $369D | b0 fb | bcsb_369A |
| $369F | cd 12 d0 | b_369Fcmp$d012; Wait while raster is still at/past target line ; x-ref: $36A2 Raster Position |
| $36A2 | 90 fb | bccb_369F |
| $36A4 | ca | dex; Decrement frame counter |
| $36A5 | d0 f3 | bneb_369A; Loop until X frames have elapsed |
| $36A7 | 60 | rts |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| ; Draws encoded text to screen RAM and sets color RAM for each character. |
| ; Reads from source pointer ($FB/$FC), writes to screen pointer ($FD/$FE). |
| ; $00 in source = end of string, $FF = skip to next row. |
| ; Each row processes up to 40 columns (screen width). |
| ; |
| ; Inputs: A = color value, ($FB/$FC) = source text pointer, ($FD/$FE) = screen RAM destination |
| ; Outputs: None (screen and color RAM updated in place) |
| ; Side Effects: Writes to screen RAM and color RAM ($D800-$DBFF) |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| $36A8 | 85 ff | draw_text_with_colorstazp_temp; Store color value ; x-ref: $5EE0, $5EF5, $5F0A, $5F1F, $62C9, ... |
| $36AA | a0 00 | ldy#$00; Y = source/dest index |
| $36AC | a2 28 | j_36ACldx#$28; X = 40 columns per row ; x-ref: $36EB |
| $36AE | b1 fb | j_36AElda(zp_ptr_src_lo),y; Load next source byte ; x-ref: $36D6 |
| $36B0 | f0 3c | beqr_36EE; $00 = end of string → return |
| $36B2 | c9 ff | cmp#$ff; Check for $FF marker |
| $36B4 | f0 23 | beqb_36D9; $FF = skip to next row |
| $36B6 | 91 fd | sta(zp_ptr_dst_lo),y; Write char to screen RAM |
| $36B8 | a5 fd | ldazp_ptr_dst_lo; Copy screen ptr low to $02 |
| $36BA | 85 02 | stazp_work0 |
| $36BC | a5 fe | ldazp_ptr_dst_hi; Mask high byte to 2 bits |
| $36BE | 29 03 | and#$03 |
| $36C0 | 18 | clc; Add $D8 → color RAM base |
| $36C1 | 69 d8 | adc#$d8 |
| $36C3 | 85 03 | stazp_work1 |
| $36C5 | a5 ff | ldazp_temp; Write color to color RAM |
| $36C7 | 91 02 | sta(zp_work0),y; Advance source pointer |
| $36C9 | e6 fb | inczp_ptr_src_lo |
| $36CB | d0 02 | bneb_36CF |
| $36CD | e6 fc | inczp_ptr_src_hi |
| $36CF | e6 fd | b_36CFinczp_ptr_dst_lo; Advance dest pointer ; x-ref: $36CB |
| $36D1 | d0 02 | bneb_36D5 |
| $36D3 | e6 fe | inczp_ptr_dst_hi |
| $36D5 | ca | b_36D5dex; Columns remaining-- ; x-ref: $36D1 |
| $36D6 | 4c ae 36 | jmpj_36AE; Continue row |
| $36D9 | e6 fb | b_36D9inczp_ptr_src_lo; Skip $FF marker byte ; x-ref: $36B4 |
| $36DB | d0 02 | bneb_36DF |
| $36DD | e6 fc | inczp_ptr_src_hi |
| $36DF | 8a | b_36DFtxa; X = remaining cols in row ; x-ref: $36DB |
| $36E0 | 18 | clc |
| $36E1 | 65 fd | adczp_ptr_dst_lo; Add remaining cols to dest ptr |
| $36E3 | 85 fd | stazp_ptr_dst_lo |
| $36E5 | a9 00 | lda#$00; Carry into high byte |
| $36E7 | 65 fe | adczp_ptr_dst_hi |
| $36E9 | 85 fe | stazp_ptr_dst_hi |
| $36EB | 4c ac 36 | jmpj_36AC; Start next row |
| $36EE | 60 | r_36EErts; x-ref: $36B0 |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| ; Converts the binary value in A to three ASCII decimal digit characters |
| ; (hundreds, tens, units) and prints them to the screen at ($FD) with |
| ; leading zero suppression. Uses repeated subtraction for the conversion. |
| ; |
| ; Inputs: A = binary value (0-255), X = digit count for display, |
| ; ($FD/$FE) = pointer to screen destination |
| ; Outputs: Screen memory at ($FD) is updated with decimal ASCII digits |
| ; Side Effects: Digit buffer a_3630-a_3632 is overwritten, zpa_FF is modified |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| print_byte_as_decimal |
| $36EF | 86 ff | stxzp_temp; Save digit count for print epilogue ; x-ref: $6E13 |
| $36F1 | a0 2f | ldy#$2f; Y = $2F ('0'-1), will count hundreds |
| $36F3 | a2 3a | ldx#$3a; X = $3A ('9'+1), will count tens |
| $36F5 | 38 | sec; Prepare for subtraction |
| $36F6 | c8 | b_36F6iny; Next hundreds digit ; x-ref: $36F9 |
| $36F7 | e9 64 | sbc#$64; Subtract 100 |
| $36F9 | b0 fb | bcsb_36F6; Loop while A >= 0 (hundreds) |
| $36FB | ca | b_36FBdex; Next tens digit ; x-ref: $36FE |
| $36FC | 69 0a | adc#$0a; Add 10 (undo overshoot) |
| $36FE | 30 fb | bmib_36FB; Loop while A < 0 (tens) |
| $3700 | 69 2f | adc#$2f; Convert units remainder to ASCII |
| $3702 | 8d 30 36 | stabcd_digit_buffer; Store units digit |
| $3705 | 8e 31 36 | stxbcd_digit_tens; Store tens digit (ASCII in X); Tens digit of BCD conversion result (ASCII) |
| $3708 | 8c 32 36 | stybcd_digit_hundreds; Store hundreds digit (ASCII in Y); Hundreds digit of BCD conversion result (ASCII) |
| $370B | 4c 33 37 | jmpj_3733; Jump to shared print/suppress routine |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| ; Unpacks BCD-encoded bytes from ($FB) into individual ASCII digit characters |
| ; and prints them to the screen at ($FD). Leading zeros are suppressed (replaced |
| ; with spaces) unless the flag at a_3638 is non-zero. |
| ; The digit count in X specifies the total number of screen characters to produce. |
| ; |
| ; Inputs: X = digit count, ($FB/$FC) = pointer to packed BCD source, |
| ; ($FD/$FE) = pointer to screen destination |
| ; Outputs: Screen memory at ($FD) is updated with ASCII digits |
| ; Side Effects: Temporary buffer a_3630 is overwritten, zpa_FF is modified |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| $370E | 86 ff | print_bcd_numberstxzp_temp; Save digit count ; x-ref: $6098, $6DDA |
| $3710 | a0 00 | ldy#$00; Y = source byte index |
| $3712 | a2 00 | ldx#$00; X = destination digit index |
| $3714 | b1 fb | b_3714lda(zp_ptr_src_lo),y; Load packed BCD byte from source ; x-ref: $3731 |
| $3716 | 29 0f | and#$0f; Isolate low nibble (ones digit) |
| $3718 | 09 30 | ora#$30; Convert to ASCII '0'-'9' (screen code) |
| $371A | 9d 30 36 | stabcd_digit_buffer,x; Store digit in temp buffer |
| $371D | e8 | inx |
| $371E | e4 ff | cpxzp_temp; All digits extracted? Done |
| $3720 | f0 11 | beqj_3733; Reload same BCD byte for high nibble |
| $3722 | b1 fb | lda(zp_ptr_src_lo),y |
| $3724 | 4a | lsra; Shift high nibble down (4x LSR) |
| $3725 | 4a | lsra |
| $3726 | 4a | lsra |
| $3727 | 4a | lsra |
| $3728 | 09 30 | ora#$30; Convert to ASCII '0'-'9' |
| $372A | 9d 30 36 | stabcd_digit_buffer,x; Store tens digit in temp buffer |
| $372D | c8 | iny; Next source byte |
| $372E | e8 | inx |
| $372F | e4 ff | cpxzp_temp; All digits done? Loop if not |
| $3731 | d0 e1 | bneb_3714 |
| $3733 | a0 00 | j_3733ldy#$00; Y = output screen index ; x-ref: $370B, $3720 |
| $3735 | a6 ff | ldxzp_temp; X = last digit index |
| $3737 | ca | dex |
| $3738 | f0 14 | beqb_374E; Only 1 digit? Skip zero suppression |
| $373A | ad 38 36 | ldazero_suppress_disable; Check zero-suppression disable flag |
| $373D | d0 0f | bneb_374E; Flag set? Skip suppression |
| $373F | bd 30 36 | b_373Fldabcd_digit_buffer,x; Read digit from buffer (MSB first) ; x-ref: $374C |
| $3742 | c9 30 | cmp#$30; Is it '0'? |
| $3744 | d0 0b | bneb_3751; Non-zero found, start printing |
| $3746 | a9 20 | lda#$20; Replace leading zero with space |
| $3748 | 91 fd | sta(zp_ptr_dst_lo),y; Write space to screen |
| $374A | c8 | iny |
| $374B | ca | dex; Next most-significant digit |
| $374C | d0 f1 | bneb_373F |
| $374E | bd 30 36 | b_374Eldabcd_digit_buffer,x; Load digit from buffer ; x-ref: $3738, $373D, $3755 |
| $3751 | 91 fd | b_3751sta(zp_ptr_dst_lo),y; Write digit/char to screen ; x-ref: $3744 |
| $3753 | c8 | iny |
| $3754 | ca | dex; Previous digit position |
| $3755 | 10 f7 | bplb_374E; More digits? Continue output |
| $3757 | 60 | rts |
| $3758 | | typewriter_done_flag.byte$00; x-ref: $375D, $3769, $377D, $60B9 |
| $3759 | | typewriter_col_index.byte$00; x-ref: $3760, $379A, $37BA, $37C0, $37D4 |
| typewriter_delay_counter |
| $375A | | .byte$00; x-ref: $3765, $376F, $37AC, $37D9 |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| ; Initializes the typewriter text effect. |
| ; Resets the done flag, column index, and delay counter so the |
| ; update_typewriter routine can begin printing characters one at a time. |
| ; |
| ; Inputs: zpp_F5/F6 = pointer to encoded text data |
| ; zpa_F7/F8 = pointer to screen memory destination row |
| ; Outputs: typewriter_done_flag, typewriter_col_index, typewriter_delay_counter |
| ; Side Effects: None |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| $375B | a9 00 | init_typewriterlda#$00; Clear accumulator ; x-ref: $60AB |
| $375D | 8d 58 37 | statypewriter_done_flag; Reset done flag = not done |
| $3760 | 8d 59 37 | statypewriter_col_index; Reset column index to 0 |
| $3763 | a9 01 | lda#$01; Initial delay = 1 (start immediately) |
| $3765 | 8d 5a 37 | statypewriter_delay_counter |
| $3768 | 60 | rts |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| ; Advances the typewriter text effect by one tick. |
| ; Reads encoded text from (zpp_F5),Y and writes characters to screen memory |
| ; at (zpa_F7),Y. Supports control codes: |
| ; $00 = end of text (sets done flag to $FF) |
| ; $FF = advance to next screen row (+40 cols), reset column |
| ; $FE = pause (sets delay counter to 60 frames) |
| ; $1E = blank separator (increments column without writing) |
| ; other = screen code character, written to screen |
| ; |
| ; Inputs: zpp_F5/F6 = pointer to current position in text data |
| ; zpa_F7/F8 = pointer to current screen row |
| ; Outputs: typewriter_done_flag = $FF when complete |
| ; Side Effects: Writes characters to screen memory; sets a_8B76 flag for |
| ; non-space characters |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| $3769 | ad 58 37 | update_typewriterldatypewriter_done_flag; Check if typewriter already finished ; x-ref: $60D3 |
| $376C | f0 01 | beqb_376F; If done ($FF), exit early |
| $376E | 60 | rts |
| $376F | ce 5a 37 | b_376Fdectypewriter_delay_counter; Decrement frame delay counter ; x-ref: $376C |
| $3772 | f0 01 | beqb_3775 |
| $3774 | 60 | rts; Not yet zero, wait more frames |
| $3775 | a0 00 | b_3775ldy#$00; x-ref: $3772 |
| $3777 | b1 f5 | typewriter_read_looplda(zp_ptr_text_lo),y; Y = 0, index into text data ; x-ref: $379D, $37BD |
| $3779 | d0 06 | bneb_3781; Read next encoded byte from text data |
| $377B | a9 ff | lda#$ff; If non-zero, check control codes |
| $377D | 8d 58 37 | statypewriter_done_flag; $00 = end of text, mark done |
| $3780 | 60 | rts |
| $3781 | c9 ff | b_3781cmp#$ff; Is it $FF? (next row marker) ; x-ref: $3779 |
| $3783 | d0 1b | bneb_37A0 |
| $3785 | e6 f5 | inczp_ptr_text_lo; Advance text data pointer |
| $3787 | d0 02 | bneb_378B |
| $3789 | e6 f6 | inczp_ptr_text_hi |
| $378B | a5 f7 | b_378Bldazp_ptr_screen_lo; Advance screen pointer by 40 columns (next row) ; x-ref: $3787 |
| $378D | 18 | clc |
| $378E | 69 28 | adc#$28 |
| $3790 | 85 f7 | stazp_ptr_screen_lo |
| $3792 | a5 f8 | ldazp_ptr_screen_hi |
| $3794 | 69 00 | adc#$00 |
| $3796 | 85 f8 | stazp_ptr_screen_hi |
| $3798 | a9 00 | lda#$00 |
| $379A | 8d 59 37 | statypewriter_col_index; Reset column index for new row |
| $379D | 4c 77 37 | jmptypewriter_read_loop; Loop back to read next byte |
| $37A0 | c9 fe | b_37A0cmp#$fe; Is it $FE? (pause marker) ; x-ref: $3783 |
| $37A2 | d0 0c | bneb_37B0 |
| $37A4 | e6 f5 | inczp_ptr_text_lo; Advance text data pointer past marker |
| $37A6 | d0 02 | bneb_37AA |
| $37A8 | e6 f6 | inczp_ptr_text_hi |
| $37AA | a9 3c | b_37AAlda#$3c; Set delay to 60 frames (~1 second pause) ; x-ref: $37A6 |
| $37AC | 8d 5a 37 | statypewriter_delay_counter |
| $37AF | 60 | rts |
| $37B0 | c9 1e | b_37B0cmp#$1e; Is it $1E? (blank separator) ; x-ref: $37A2 |
| $37B2 | d0 0c | bneb_37C0 |
| $37B4 | e6 f5 | inczp_ptr_text_lo; Advance text pointer (skip separator) |
| $37B6 | d0 02 | bneb_37BA |
| $37B8 | e6 f6 | inczp_ptr_text_hi |
| $37BA | ee 59 37 | b_37BAinctypewriter_col_index; Increment column without writing to screen ; x-ref: $37B6 |
| $37BD | 4c 77 37 | jmptypewriter_read_loop; Loop back to read next byte |
| $37C0 | ac 59 37 | b_37C0ldytypewriter_col_index; Regular char: Y = current column index ; x-ref: $37B2 |
| $37C3 | 91 f7 | sta(zp_ptr_screen_lo),y; Write screen code to screen memory |
| $37C5 | c9 20 | cmp#$20; Is it a space ($20)? |
| $37C7 | f0 05 | beqb_37CE |
| $37C9 | a9 01 | lda#$01; Non-space: set flag (e.g., trigger SFX) |
| $37CB | 8d 76 8b | stasfx7_enable |
| $37CE | e6 f5 | b_37CEinczp_ptr_text_lo; Advance text data pointer ; x-ref: $37C7 |
| $37D0 | d0 02 | bneb_37D4 |
| $37D2 | e6 f6 | inczp_ptr_text_hi |
| $37D4 | ee 59 37 | b_37D4inctypewriter_col_index; Advance column index ; x-ref: $37D0 |
| $37D7 | a9 05 | lda#$05; Delay 5 frames between characters |
| $37D9 | 8d 5a 37 | statypewriter_delay_counter |
| $37DC | 60 | rts |
| $37DD | | .fill35, $00 |
| ; -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= |
| ; Charset (???) |
| $3800 | | .fill11, $00 |
| $380B | | .byte$04, $00, $00, $10, $00, $00, $40, $00 |
| $3813 | | .byte$00, $20, $00, $02, $00, $a0, $c8, $22 |
| $381B | | .byte$40, $e4, $ed, $df, $ff, $09, $46, $0a |
| $3823 | | .byte$9f, $6e, $fd, $df, $3b, $02, $10, $00 |
| $382B | | .byte$44, $a0, $ec, $f1, $7b, $1c, $34, $24 |
| $3833 | | .byte$2c, $ea, $a2, $56, $55, $38, $11, $12 |
| $383B | | .byte$02, $24, $1a, $08, $11, $1c, $08, $0c |
| $3843 | | .byte$08, $08, $10, $1c, $14, $ef, $f5, $b7 |
| $384B | | .byte$fd, $bc, $59, $30, $11, $fe, $ed, $7d |
| $3853 | | .byte$7f, $26, $43, $0a, $09, $ff, $db, $f5 |
| $385B | | .byte$60, $10, $00, $08, $08, $95, $55, $4a |
| $3863 | | .byte$32, $2a, $24, $2c, $14, $7b, $3b, $d6 |
| $386B | | .byte$ee, $de, $37, $77, $7b, $ec, $de, $df |
| $3873 | | .byte$ee, $ed, $6b, $b5, $dc, $bc, $7e, $bf |
| $387B | | .byte$b7, $ab, $dd, $bc, $7b, $74, $ba, $f7 |
| $3883 | | .byte$af, $dc, $bb, $7d, $be, $73, $3b, $d6 |
| $388B | | .byte$e8, $be, $37, $74, $6b, $ec, $1c, $d3 |
| $3893 | | .byte$ac, $6d, $6b, $95, $d6, $9c, $66, $b9 |
| $389B | | .byte$37, $ab, $dd, $a4, $7b, $3c, $78, $e2 |
| $38A3 | | .byte$f6, $77, $f3, $dd, $0d, $3c, $f8, $f0 |
| $38AB | | .byte$ac, $84, $be, $e8, $cc, $82, $ff, $59 |
| $38B3 | | .byte$51, $87, $bc, $ff, $76, $1e, $3f, $79 |
| $38BB | | .byte$37, $06, $3c, $1f, $1f, $04, $0b, $1b |
| $38C3 | | .byte$0e, $06, $1b, $0d, $0d, $d0, $b0, $60 |
| $38CB | | .byte$b0, $f8, $78, $b0, $90, $00, $18, $1d |
| $38D3 | | .byte$87, $fb, $bd, $d7, $ff, $06, $0f, $19 |
| $38DB | | .byte$b6, $ef, $5b, $bd, $ff, $00, $00, $81 |
| $38E3 | | .byte$c3, $e2, $b1, $df, $ff, $ff, $d7, $bd |
| $38EB | | .byte$fb, $87, $1d, $18, $00, $ff, $bd, $5b |
| $38F3 | | .byte$ef, $b6, $19, $0f, $06, $ff, $df, $b1 |
| $38FB | | .byte$e2, $c3, $81, $00, $00, $20, $6c, $f7 |
| $3903 | | .byte$df, $fd, $fe, $ff, $7b, $fb, $7f, $ff |
| $390B | | .byte$f7, $ff, $fd, $d8, $08, $f7, $df, $fe |
| $3913 | | .byte$b7, $cf, $85, $00, $00, $6f, $f6, $1b |
| $391B | | .byte$df, $7b, $f2, $db, $be, $00, $40, $d9 |
| $3923 | | .byte$fb, $ff, $fe, $ef, $df, $be, $fb, $df |
| $392B | | .byte$e7, $ef, $bc, $fb, $6f, $37, $3f, $1f |
| $3933 | | .byte$2e, $3f, $f7, $7d, $77, $7f, $dd, $ef |
| $393B | | .byte$3f, $f7, $ce, $7f, $77, $1d, $0f, $0b |
| $3943 | | .byte$0f, $1f, $37, $3f, $1e, $db, $f6, $fc |
| $394B | | .byte$be, $fc, $b8, $f1, $f8, $7e, $fe, $db |
| $3953 | | .byte$f6, $fc, $be, $7b, $fe, $f8, $ec, $fc |
| $395B | | .byte$b8, $f1, $f8, $78, $f4, $09, $26, $1f |
| $3963 | | .byte$16, $6d, $1f, $6f, $b3, $48, $d0, $64 |
| $396B | | .byte$f8, $ec, $f5, $fe, $bd, $af, $7b, $77 |
| $3973 | | .byte$17, $4d, $1b, $17, $02, $fd, $dd, $ea |
| $397B | | .byte$fe, $aa, $d4, $e8, $40, $ff, $ff, $ff |
| $3983 | | .byte$ff, $00, $00, $00, $00, $ff, $ff, $ff |
| $398B | | .byte$00, $00, $00, $00, $00, $ff, $ff, $00 |
| $3993 | | .byte$00, $00, $00, $00, $00, $ff, $00, $00 |
| $399B | | .byte$00, $00, $00, $00, $00, $5e, $ed, $f3 |
| $39A3 | | .byte$f7, $ef, $6f, $17, $79, $7c, $9a, $e7 |
| $39AB | | .byte$ef, $ef, $e6, $d9, $3b, $fe, $7c, $3d |
| $39B3 | | .byte$41, $ee, $ef, $5f, $1e, $3b, $3a, $b4 |
| $39BB | | .byte$cf, $c7, $3a, $7c, $fe, $34, $76, $26 |
| $39C3 | | .byte$02, $68, $ed, $6d, $01, $5c, $9a, $67 |
| $39CB | | .byte$73, $22, $9c, $d8, $8a, $06, $36, $74 |
| $39D3 | | .byte$30, $21, $4d, $6e, $48, $37, $7a, $b0 |
| $39DB | | .byte$c7, $d6, $b8, $10, $cc |
| $39E0 | | .fill32, $00 |
| ; -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= |
| ; Intro Sprites |
| ; sprite #E8: L |
| $3A00 | | .byte$00, $00, $00, $f8, $00, $00, $f8, $00 |
| $3A08 | | .byte$00, $f8, $00, $00, $f8, $00, $00, $f8 |
| $3A10 | | .byte$00, $00, $f8, $00, $00, $f8, $00, $00 |
| $3A18 | | .byte$f8, $00, $00, $f8, $00, $00, $f8, $00 |
| $3A20 | | .byte$00, $f8, $00, $00, $f8, $00, $00, $f8 |
| $3A28 | | .byte$00, $00, $f8, $00, $00, $ff, $ff, $f0 |
| $3A30 | | .byte$ff, $ff, $f0, $ff, $ff, $f0, $ff, $ff |
| $3A38 | | .byte$f0, $ff, $ff, $f0, $00, $00, $00, $01 |
| ; Srite #$E9: C |
| $3A40 | | .byte$00, $00, $00, $01, $ff, $f0, $01, $ff |
| $3A48 | | .byte$f0, $01, $ff, $f0, $01, $ff, $f0, $01 |
| $3A50 | | .byte$ff, $f0, $01, $f0, $00, $01, $f0, $00 |
| $3A58 | | .byte$01, $ff, $f0, $01, $ff, $f0, $01, $ff |
| $3A60 | | .byte$f0, $01, $ff, $f0, $01, $ff, $f0 |
| $3A67 | | .fill24, $00 |
| $3A7F | | .byte$01 |
| ; Sprite #$EA: Vertical MES |
| $3A80 | | .byte$00, $00, $00, $70, $f8, $00, $f1, $fc |
| $3A88 | | .byte$00, $c3, $8c, $00, $c7, $0c, $00, $ce |
| $3A90 | | .byte$0c, $00, $fc, $3c, $00, $78, $38, $00 |
| $3A98 | | .byte$00, $00, $00, $c0, $0c, $00, $c3, $0c |
| $3AA0 | | .byte$00, $c3, $0c, $00, $c3, $0c, $00, $c3 |
| $3AA8 | | .byte$0c, $00, $ff, $fc, $00, $ff, $fc, $00 |
| $3AB0 | | .byte$00, $00, $00, $ff, $fc, $00, $ff, $fc |
| $3AB8 | | .byte$00, $70, $00, $00, $38, $00, $00, $01 |
| ; Sprite #$EB: Vertical GAM |
| $3AC0 | | .byte$70, $00, $00, $ff, $fc, $00, $ff, $fc |
| $3AC8 | | .byte$00, $00, $00, $00, $7f, $fc, $00, $ff |
| $3AD0 | | .byte$fc, $00, $c3, $00, $00, $c3, $00, $00 |
| $3AD8 | | .byte$c3, $00, $00, $ff, $fc, $00, $7f, $fc |
| $3AE0 | | .byte$00, $00, $00, $00, $73, $f8, $00, $f3 |
| $3AE8 | | .byte$fc, $00, $c3, $0c, $00, $c3, $0c, $00 |
| $3AF0 | | .byte$c0, $0c, $00, $ff, $fc, $00, $7f, $f8 |
| $3AF8 | | .byte$00, $00, $00, $00, $00, $00, $00, $01 |
| ; Sprite #$EC: PRE |
| $3B00 | | .byte$0f, $cf, $cf, $0f, $ef, $ef, $0c, $6c |
| $3B08 | | .byte$6c, $0c, $6c, $6c, $0c, $6c, $6c, $0c |
| $3B10 | | .byte$6c, $6c, $0c, $6c, $6f, $0c, $6c, $ef |
| $3B18 | | .byte$0f, $ef, $cc, $0f, $cf, $8c, $0c, $0c |
| $3B20 | | .byte$cc, $0c, $0c, $cc, $0c, $0c, $6f, $0c |
| $3B28 | | .byte$0c, $6f |
| $3B2A | | .fill21, $00 |
| $3B3F | | .byte$01 |
| ; Sprite #$ED: ESEN |
| $3B40 | | .byte$cf, $9f, $b1, $df, $df, $b1, $18, $d8 |
| $3B48 | | .byte$39, $18, $d8, $39, $1c, $18, $3d, $0e |
| $3B50 | | .byte$18, $3d, $87, $1f, $3f, $83, $9f, $3f |
| $3B58 | | .byte$01, $d8, $37, $00, $d8, $37, $18, $d8 |
| $3B60 | | .byte$33, $18, $d8, $33, $df, $df, $b1, $cf |
| $3B68 | | .byte$9f, $b1 |
| $3B6A | | .fill21, $00 |
| $3B7F | | .byte$01 |
| ; Sprite #$EE: NTS |
| $3B80 | | .byte$bf, $3e, $00, $bf, $7f, $00, $8c, $63 |
| $3B88 | | .byte$00, $8c, $63, $00, $8c, $70, $00, $8c |
| $3B90 | | .byte$38, $00, $8c, $1c, $00, $8c, $0e, $00 |
| $3B98 | | .byte$8c, $07, $00, $8c, $03, $00, $8c, $63 |
| $3BA0 | | .byte$00, $8c, $63, $00, $8c, $7f, $00, $8c |
| $3BA8 | | .byte$3e |
| $3BA9 | | .fill22, $00 |
| $3BBF | | .byte$01 |
| ; Sprite #$EF: LC GA |
| $3BC0 | | .byte$00, $00, $00, $00, $00, $00, $ef, $e1 |
| $3BC8 | | .byte$e7, $ef, $e3, $ef, $ef, $e3, $ef, $ee |
| $3BD0 | | .byte$03, $0d, $ef, $e3, $6f, $ef, $e3, $6f |
| $3BD8 | | .byte$ef, $e3, $6f, $e0, $03, $6d, $ff, $e3 |
| $3BE0 | | .byte$ed, $ff, $e3, $ed, $ff, $e1, $cd |
| $3BE7 | | .fill24, $00 |
| $3BFF | | .byte$01 |
| ; Sprite #$F0: AMES |
| $3C00 | | .byte$00, $00, $00, $00, $00, $00, $20, $be |
| $3C08 | | .byte$78, $b1, $be, $f8, $bb, $be, $f8, $bf |
| $3C10 | | .byte$b0, $c0, $bf, $bc, $f0, $bf, $bc, $f8 |
| $3C18 | | .byte$b5, $bc, $78, $b1, $b0, $18, $b1, $be |
| $3C20 | | .byte$f8, $b1, $be, $f8, $b1, $be, $f0 |
| $3C27 | | .fill24, $00 |
| $3C3F | | .byte$01, $00, $00, $00, $77, $f1, $f7, $10 |
| $3C47 | | .byte$12, $18, $10, $10, $10, $10, $00, $00 |
| $3C4F | | .byte$11, $f0, $b2, $10, $10, $90, $10, $10 |
| $3C57 | | .byte$90, $10, $00, $90, $1f, $f0, $90, $00 |
| $3C5F | | .byte$10, $10, $00, $10 |
| $3C63 | | .fill28, $00 |
| $3C7F | | .byte$0e, $00, $00, $00, $21, $7c, $f0, $93 |
| $3C87 | | .byte$41, $80, $0e, $41, $00, $04, $41, $00 |
| $3C8F | | .byte$00, $49, $20, $00, $41, $00, $00, $41 |
| $3C97 | | .byte$00, $00, $40, $80, $00, $4d, $e0, $00 |
| $3C9F | | .byte$41, $00, $00, $41 |
| $3CA3 | | .fill28, $00 |
| $3CBF | | .byte$0e, $3b, $f8, $f7, $08, $08, $08, $00 |
| $3CC7 | | .byte$08, $00, $00, $00, $00, $00, $18, $10 |
| $3CCF | | .byte$00, $08, $00, $00, $08, $00, $00, $00 |
| $3CD7 | | .byte$00, $00, $18, $00, $00, $08, $00, $00 |
| $3CDF | | .byte$08 |
| $3CE0 | | .fill31, $00 |
| $3CFF | | .byte$06, $22, $f9, $e0, $96, $83, $00, $0c |
| $3D07 | | .fill9, $00 |
| $3D10 | | .byte$02, $00, $00, $02, $00, $00, $00, $00 |
| $3D18 | | .byte$00, $03, $00, $00, $02 |
| $3D1D | | .fill34, $00 |
| $3D3F | | .byte$06, $60, $00, $06, $80, $00, $08 |
| $3D46 | | .fill39, $00 |
| $3D6D | | .byte$1f, $ff, $ff, $20 |
| $3D71 | | .fill14, $00 |
| $3D7F | | .byte$01, $7f, $ff, $e0, $80 |
| $3D84 | | .fill41, $00 |
| $3DAD | | .byte$7f, $e0, $00, $80 |
| $3DB1 | | .fill14, $00 |
| $3DBF | | .byte$01, $7f, $ff, $80, $80 |
| $3DC4 | | .fill22, $00 |
| $3DDA | | .byte$10, $00, $00, $10, $00, $00, $10, $00 |
| $3DE2 | | .byte$00, $10, $00, $00, $10, $00, $00, $10 |
| $3DEA | | .byte$00, $00, $20, $7f, $ff, $c0, $80 |
| $3DF1 | | .fill14, $00 |
| $3DFF | | .byte$01, $00, $03, $f0, $00, $1c, $00, $00 |
| $3E07 | | .byte$60, $00, $00, $80, $00, $01 |
| $3E0D | | .fill11, $00 |
| $3E18 | | .byte$10, $00, $00, $20, $00, $00, $40, $00 |
| $3E20 | | .byte$00, $40, $00, $00, $80, $00, $00, $80 |
| $3E28 | | .fill23, $00 |
| $3E3F | | .byte$01, $ff, $ff, $80 |
| $3E43 | | .fill60, $00 |
| $3E7F | | .byte$01 |
| $3E80 | | joystick_state.byte$00; x-ref: $1D54, $1D60, $1D7A, $3E82, $3E92, ... |
| $3E81 | | joystick_prev_state.byte$00; x-ref: $3E85, $5D5E, $5D78, $5DB2, $5DD0, ... |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| ; Reads joystick port 2 and updates the current joystick state. |
| ; Saves the previous state for edge detection before reading new input. |
| ; If the SID paddle register ($D419) reads zero, clears bit 5 of the |
| ; joystick value (masks out a secondary fire button or paddle input). |
| ; |
| ; Inputs: None |
| ; Outputs: joystick_state = current joystick bits, joystick_prev_state = previous frame |
| ; Side Effects: None |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| $3E82 | ad 80 3e | read_joystickldajoystick_state; save current state as previous ; x-ref: $20F5, $5D54 |
| $3E85 | 8d 81 3e | stajoystick_prev_state |
| $3E88 | ad 00 dc | lda$dc00; read joystick port 2 (active low); CIA1: Data Port Register A |
| $3E8B | ae 19 d4 | ldx$d419; read SID paddle register; Analog/Digital Converter: Game Paddle 1 |
| $3E8E | d0 02 | bneb_3E92; paddle != 0? skip masking |
| $3E90 | 29 df | and#$df; clear bit 5 (secondary fire) if paddle=0 |
| $3E92 | 8d 80 3e | b_3E92stajoystick_state; store new joystick state ; x-ref: $3E8E |
| $3E95 | 60 | rts |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| ; Filters phantom joystick inputs caused by keyboard matrix ghosting. |
| ; Reads the current joystick state (a_3E80) and for each active direction/fire |
| ; bit, checks if the corresponding keyboard row shows a key pressed. If the |
| ; key is NOT pressed, the joystick bit is cleared as a ghost artifact. |
| ; |
| ; Bit mapping: |
| ; Bit 0 (Up) -> keyboard row a_3F10, mask $02 |
| ; Bit 1 (Down) -> keyboard row a_3F10, mask $20 |
| ; Bit 2 (Left) -> keyboard row a_3F10, mask $04 |
| ; Bit 3 (Right) -> keyboard row a_3F12, mask $04 |
| ; Bit 4 (Fire) -> keyboard row a_3F0E, mask $80 OR a_3F14, mask $10 |
| ; |
| ; Inputs: a_3E80 (raw joystick state), a_3F0C-a_3F16 (keyboard scan results) |
| ; Outputs: a_3E80 (filtered joystick state) |
| ; Side Effects: None |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| filter_joystick_from_keyboard |
| $3E96 | ad 80 3e | ldajoystick_state; check joystick Up bit ; x-ref: $20FB |
| $3E99 | 29 01 | and#$01; bit 0 = Up |
| $3E9B | f0 0f | beqb_3EAC; skip if Up not active |
| $3E9D | ad 10 3f | ldakb_row4_cur; check keyboard row for Up ghost |
| $3EA0 | 29 02 | and#$02; key pressed? (active low) |
| $3EA2 | d0 08 | bneb_3EAC; skip clear if key is pressed |
| $3EA4 | ad 80 3e | ldajoystick_state |
| $3EA7 | 29 fe | and#$fe; clear bit 0 (Up) - ghost input |
| $3EA9 | 8d 80 3e | stajoystick_state |
| $3EAC | ad 80 3e | b_3EACldajoystick_state; check joystick Down bit ; x-ref: $3E9B, $3EA2 |
| $3EAF | 29 02 | and#$02; bit 1 = Down |
| $3EB1 | f0 0f | beqb_3EC2; skip if Down not active |
| $3EB3 | ad 10 3f | ldakb_row4_cur; check keyboard row for Down ghost |
| $3EB6 | 29 20 | and#$20; key pressed? |
| $3EB8 | d0 08 | bneb_3EC2; skip clear if key is pressed |
| $3EBA | ad 80 3e | ldajoystick_state |
| $3EBD | 29 fd | and#$fd; clear bit 1 (Down) - ghost input |
| $3EBF | 8d 80 3e | stajoystick_state |
| $3EC2 | ad 80 3e | b_3EC2ldajoystick_state; check joystick Left bit ; x-ref: $3EB1, $3EB8 |
| $3EC5 | 29 04 | and#$04; bit 2 = Left |
| $3EC7 | f0 0f | beqb_3ED8; skip if Left not active |
| $3EC9 | ad 10 3f | ldakb_row4_cur; check keyboard row for Left ghost |
| $3ECC | 29 04 | and#$04; key pressed? |
| $3ECE | d0 08 | bneb_3ED8; skip clear if key is pressed |
| $3ED0 | ad 80 3e | ldajoystick_state |
| $3ED3 | 29 fb | and#$fb; clear bit 2 (Left) - ghost input |
| $3ED5 | 8d 80 3e | stajoystick_state |
| $3ED8 | ad 80 3e | b_3ED8ldajoystick_state; check joystick Right bit ; x-ref: $3EC7, $3ECE |
| $3EDB | 29 08 | and#$08; bit 3 = Right |
| $3EDD | f0 0f | beqb_3EEE; skip if Right not active |
| $3EDF | ad 12 3f | ldakb_row5_cur; check keyboard row for Right ghost |
| $3EE2 | 29 04 | and#$04; key pressed? |
| $3EE4 | d0 08 | bneb_3EEE; skip clear if key is pressed |
| $3EE6 | ad 80 3e | ldajoystick_state |
| $3EE9 | 29 f7 | and#$f7; clear bit 3 (Right) - ghost input |
| $3EEB | 8d 80 3e | stajoystick_state |
| $3EEE | ad 80 3e | b_3EEEldajoystick_state; check joystick Fire bit ; x-ref: $3EDD, $3EE4 |
| $3EF1 | 29 10 | and#$10; bit 4 = Fire |
| $3EF3 | f0 16 | beqr_3F0B; skip if Fire not active |
| $3EF5 | ad 0e 3f | ldakb_row1_cur; check 1st keyboard row for Fire ghost |
| $3EF8 | 29 80 | and#$80; key pressed? |
| $3EFA | f0 07 | beqb_3F03; no ghost from this row, check 2nd row |
| $3EFC | ad 14 3f | ldakb_row6_cur; check 2nd keyboard row for Fire ghost |
| $3EFF | 29 10 | and#$10; key pressed? |
| $3F01 | d0 08 | bner_3F0B; key confirms Fire - keep it |
| $3F03 | ad 80 3e | b_3F03ldajoystick_state; x-ref: $3EFA |
| $3F06 | 29 ef | and#$ef; clear bit 4 (Fire) - ghost input |
| $3F08 | 8d 80 3e | stajoystick_state |
| $3F0B | 60 | r_3F0Brts; x-ref: $3EF3, $3F01 |
| $3F0C | | kb_row0_cur.byte$00; x-ref: $3F18, $3F49, $3F8B, $6182, $6EA7 |
| $3F0D | | kb_row0_prev.byte$00; x-ref: $3F1B, $6185, $6EAA |
| $3F0E | | kb_row1_cur.byte$00; x-ref: $3EF5, $3F1E, $3F54, $3F8E |
| $3F0F | | kb_row1_prev.byte$00; x-ref: $3F21 |
| $3F10 | | kb_row4_cur.byte$00; x-ref: $3E9D, $3EB3, $3EC9, $3F24, $3F5F, ... |
| $3F11 | | kb_row4_prev.byte$00; x-ref: $3F27 |
| $3F12 | | kb_row5_cur.byte$00; x-ref: $3EDF, $3F2A, $3F6A, $3F94 |
| $3F13 | | kb_row5_prev.byte$00; x-ref: $3F2D |
| $3F14 | | kb_row6_cur.byte$00; x-ref: $3EFC, $3F30, $3F75, $3F97 |
| $3F15 | | kb_row6_prev.byte$00; x-ref: $3F33 |
| $3F16 | | kb_row7_cur.byte$00; x-ref: $3F36, $3F80, $3F9A, $8093 |
| $3F17 | | kb_row7_prev.byte$00; x-ref: $3F39, $8096 |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| ; Scans 6 rows of the C128 keyboard matrix via CIA1 ($DC00-$DC02). |
| ; First saves the previous scan results into shadow variables (a_3F0D, |
| ; a_3F0F, a_3F11, a_3F13, a_3F15, a_3F17), then selects each keyboard |
| ; row by writing the row-select mask to CIA1 Port A and reading the |
| ; column state from CIA1 Port B. |
| ; |
| ; Row mapping: |
| ; $FE -> row 0 -> a_3F0C $FD -> row 1 -> a_3F0E |
| ; $EF -> row 4 -> a_3F10 $DF -> row 5 -> a_3F12 |
| ; $BF -> row 6 -> a_3F14 $7F -> row 7 -> a_3F16 |
| ; |
| ; Inputs: None |
| ; Outputs: a_3F0C-a_3F16 (current scan), a_3F0D-a_3F17 (previous scan) |
| ; Side Effects: Temporarily sets CIA1 DDRA to output ($FF), restores to $00 |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| $3F18 | ad 0c 3f | scan_keyboard_matrixldakb_row0_cur; save previous row 0 scan ; x-ref: $20F8 |
| $3F1B | 8d 0d 3f | stakb_row0_prev; previous row 0 result |
| $3F1E | ad 0e 3f | ldakb_row1_cur; save previous row 1 scan |
| $3F21 | 8d 0f 3f | stakb_row1_prev; previous row 1 result |
| $3F24 | ad 10 3f | ldakb_row4_cur; save previous row 4 scan |
| $3F27 | 8d 11 3f | stakb_row4_prev; previous row 4 result |
| $3F2A | ad 12 3f | ldakb_row5_cur; save previous row 5 scan |
| $3F2D | 8d 13 3f | stakb_row5_prev; previous row 5 result |
| $3F30 | ad 14 3f | ldakb_row6_cur; save previous row 6 scan |
| $3F33 | 8d 15 3f | stakb_row6_prev; previous row 6 result |
| $3F36 | ad 16 3f | ldakb_row7_cur; save previous row 7 scan |
| $3F39 | 8d 17 3f | stakb_row7_prev; previous row 7 result |
| $3F3C | a9 ff | lda#$ff; set all Port A bits to output |
| $3F3E | 8d 02 dc | sta$dc02; CIA1: Data Direction Register A |
| $3F41 | a9 fe | lda#$fe; select keyboard row 0 |
| $3F43 | 8d 00 dc | sta$dc00; CIA1: Data Port Register A |
| $3F46 | ad 01 dc | lda$dc01; read column state for row 0; CIA1: Data Port Register B |
| $3F49 | 8d 0c 3f | stakb_row0_cur; store row 0 result |
| $3F4C | a9 fd | lda#$fd; select keyboard row 1 |
| $3F4E | 8d 00 dc | sta$dc00; CIA1: Data Port Register A |
| $3F51 | ad 01 dc | lda$dc01; read column state for row 1; CIA1: Data Port Register B |
| $3F54 | 8d 0e 3f | stakb_row1_cur; store row 1 result |
| $3F57 | a9 ef | lda#$ef; select keyboard row 4 |
| $3F59 | 8d 00 dc | sta$dc00; CIA1: Data Port Register A |
| $3F5C | ad 01 dc | lda$dc01; read column state for row 4; CIA1: Data Port Register B |
| $3F5F | 8d 10 3f | stakb_row4_cur; store row 4 result |
| $3F62 | a9 df | lda#$df; select keyboard row 5 |
| $3F64 | 8d 00 dc | sta$dc00; CIA1: Data Port Register A |
| $3F67 | ad 01 dc | lda$dc01; read column state for row 5; CIA1: Data Port Register B |
| $3F6A | 8d 12 3f | stakb_row5_cur; store row 5 result |
| $3F6D | a9 bf | lda#$bf; select keyboard row 6 |
| $3F6F | 8d 00 dc | sta$dc00; CIA1: Data Port Register A |
| $3F72 | ad 01 dc | lda$dc01; read column state for row 6; CIA1: Data Port Register B |
| $3F75 | 8d 14 3f | stakb_row6_cur; store row 6 result |
| $3F78 | a9 7f | lda#$7f; select keyboard row 7 |
| $3F7A | 8d 00 dc | sta$dc00; CIA1: Data Port Register A |
| $3F7D | ad 01 dc | lda$dc01; read column state for row 7; CIA1: Data Port Register B |
| $3F80 | 8d 16 3f | stakb_row7_cur; store row 7 result |
| $3F83 | a9 00 | lda#$00; restore Port A to input mode |
| $3F85 | 8d 02 dc | sta$dc02; CIA1: Data Direction Register A |
| $3F88 | 60 | rts |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| ; Resets all keyboard matrix current-scan variables to $FF (no keys pressed). |
| ; Used during state transitions to prevent stale key presses from being |
| ; processed. The CIA keyboard matrix is active-low, so $FF means all bits |
| ; high = no keys held. |
| ; |
| ; Inputs: None |
| ; Outputs: kb_row0_cur..kb_row7_cur all set to $FF |
| ; Side Effects: None |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| $3F89 | a9 ff | reset_keyboard_statelda#$ff; $FF = no keys pressed (active-low) ; x-ref: $1D4A |
| $3F8B | 8d 0c 3f | stakb_row0_cur; Clear row 0 |
| $3F8E | 8d 0e 3f | stakb_row1_cur; Clear row 1 |
| $3F91 | 8d 10 3f | stakb_row4_cur; Clear row 4 |
| $3F94 | 8d 12 3f | stakb_row5_cur; Clear row 5 |
| $3F97 | 8d 14 3f | stakb_row6_cur; Clear row 6 |
| $3F9A | 8d 16 3f | stakb_row7_cur; Clear row 7 |
| $3F9D | 60 | rts |
| ; Current room/screen index within the level map. |
| ; Bits 2-0 = column (0-7), bits 5-3 = row (0-11). |
| ; Used to index the screen data pointer table at $E000. |
| $3F9E | | current_room_index.byte$00; x-ref: $4AEA, $4B1E, $4E17, $5011, $5018, ... |
| ; Color value for the top section of the playfield. |
| ; Loaded from the level palette table f_48F9 based on world index. |
| $3F9F | | level_color_top.byte$00; x-ref: $49FF, $4E2F, $4E50 |
| $3FA0 | | level_color_bottom.byte$00; Color value for the bottom section of the playfield ; x-ref: $4A05, $4E42, $4E56 |
| $3FA1 | | level_color_border.byte$00; Border/background color 3 for the level ; x-ref: $4A0B, $4CD0, $4E22 |
| level_color_multicolor |
| $3FA2 | | .byte$00; VIC-II ECM multicolor value ($D023) for the level ; x-ref: $4A11, $64B0 |
| ; Current active background color applied to color RAM ($D828+) and VIC-II |
| ; background color 3 ($D024). Updated via set_screen_color routine. |
| ; Skips cells with color value 2 (used for special tiles). |
| $3FA3 | | active_bg_color.byte$00; x-ref: $4E25, $4E62, $4F41, $4F50, $4F91, ... |
| ; Screen slot occupancy flag from f_EF78 lookup. |
| ; Non-zero = slot occupied (partial color fill, bg3 active). |
| ; Zero = empty slot (full color fill). Also used as hero death trigger |
| ; in collision routines — $FF signals death. |
| $3FA4 | | screen_slot_status.byte$00; x-ref: $1E9F, $1EE0, $4C81, $4CCB, $4E1D, ... |
| ; Map decompression in-progress flag. |
| ; $FF = decompression active (tile 16/hero entity init enabled). |
| ; $00 = decompression complete. |
| $3FA5 | | map_decompressing.byte$00; x-ref: $4A64, $4A6C, $4FE8 |
| ; Set to $FF when screen content has changed and needs redraw. |
| ; Checked by animation subsystems to trigger re-initialization. |
| ; Cleared to $00 at the start of render_level_screen. |
| $3FA6 | | screen_changed_flag.byte$00; x-ref: $4B1B, $4D02, $7A20 |
| ; Rendering lock flag. |
| ; Set to $FF at start of render_level_screen, cleared to $00 at end. |
| ; Prevents re-entrant rendering during IRQ-driven updates. |
| rendering_in_progress |
| $3FA7 | | .byte$00; x-ref: $4AF2, $4CDD, $7798, $7802, $7AD4, ... |
| ; Snapshot of combined animation subsystem flags (OR of 3 subsystems). |
| ; Saved at start of render_level_screen to preserve animation state |
| ; across the re-initialization of all tile subsystems. |
| saved_animation_flags |
| $3FA8 | | .byte$00; x-ref: $4AFE, $4C33 |
| ; Lo-byte pointer table for predefined screen row patterns. |
| ; 17 entries ($3FA9-$3FB9), paired with row_pattern_ptrs_hi. |
| ; Used by screen decompressor to copy 40-byte row templates. |
| $3FA9 | | row_pattern_ptrs_lo.byte$c0, $e8, $10, $38, $60, $88, $b0, $d8; x-ref: $4D37 |
| $3FB1 | | .byte$00, $28, $50, $78, $a0, $c8, $f0, $18 |
| $3FB9 | | .byte$40 |
| ; Hi-byte pointer table for predefined screen row patterns. |
| ; 17 entries ($3FBA-$3FCA), paired with row_pattern_ptrs_lo. |
| $3FBA | | row_pattern_ptrs_hi.byte$e0, $e0, $e1, $e1, $e1, $e1, $e1, $e1; x-ref: $4D3C |
| $3FC2 | | .byte$e2, $e2, $e2, $e2, $e2, $e2, $e2, $e3 |
| $3FCA | | .byte$e3 |
| $3FCB | | .fill40, $00 |
| $3FF3 | | .byte$01, $02, $00, $01, $00, $02, $00, $02 |
| $3FFB | | .byte$01, $02, $00, $01, $00, $02, $00, $02 |
| $4003 | | .byte$01, $02, $00, $01, $00, $02, $00, $02 |
| $400B | | .byte$01, $02, $00, $01, $00, $02, $00, $02 |
| $4013 | | .byte$01, $02, $00, $01, $00, $02, $00, $02 |
| $401B | | .byte$00, $01, $02, $00, $02, $01, $01, $00 |
| $4023 | | .byte$00, $01, $02, $00, $02, $01, $01, $00 |
| $402B | | .byte$00, $01, $02, $00, $02, $01, $01, $00 |
| $4033 | | .byte$00, $01, $02, $00, $02, $01, $01, $00 |
| $403B | | .byte$00, $01, $02, $00, $02, $01, $01, $00 |
| $4043 | | .byte$01, $00, $00, $02, $00, $01, $00, $02 |
| $404B | | .byte$01, $00, $00, $02, $00, $01, $00, $02 |
| $4053 | | .byte$01, $00, $00, $02, $00, $01, $00, $02 |
| $405B | | .byte$01, $00, $00, $02, $00, $01, $00, $02 |
| $4063 | | .byte$01, $00, $00, $02, $00, $01, $00, $02 |
| $406B | | .byte$00, $02, $01, $00, $01, $00, $02, $01 |
| $4073 | | .byte$00, $02, $01, $00, $01, $00, $02, $01 |
| $407B | | .byte$00, $02, $01, $00, $01, $00, $02, $01 |
| $4083 | | .byte$00, $02, $01, $00, $01, $00, $02, $01 |
| $408B | | .byte$00, $02, $01, $00, $01, $00, $02, $01 |
| $4093 | | .byte$02, $00, $00, $01, $02, $00, $02, $00 |
| $409B | | .byte$02, $00, $00, $01, $02, $00, $02, $00 |
| $40A3 | | .byte$02, $00, $00, $01, $02, $00, $02, $00 |
| $40AB | | .byte$02, $00, $00, $01, $02, $00, $02, $00 |
| $40B3 | | .byte$02, $00, $00, $01, $02, $00, $02, $00 |
| $40BB | | .byte$01, $02, $00, $01, $00, $02, $00, $02 |
| $40C3 | | .byte$01, $02, $00, $01, $00, $02, $00, $02 |
| $40CB | | .byte$01, $02, $00, $01, $00, $02, $00, $02 |
| $40D3 | | .byte$01, $02, $00, $01, $00, $02, $00, $02 |
| $40DB | | .byte$01, $02, $00, $01, $00, $02, $00, $02 |
| $40E3 | | .byte$00, $01, $02, $00, $02, $01, $01, $00 |
| $40EB | | .byte$00, $01, $02, $00, $02, $01, $01, $00 |
| $40F3 | | .byte$00, $01, $02, $00, $02, $01, $01, $00 |
| $40FB | | .byte$00, $01, $02, $00, $02, $01, $01, $00 |
| $4103 | | .byte$00, $01, $02, $00, $02, $01, $01, $00 |
| $410B | | .byte$01, $00, $00, $02, $00, $01, $00, $02 |
| $4113 | | .byte$01, $00, $00, $02, $00, $01, $00, $02 |
| $411B | | .byte$01, $00, $00, $02, $00, $01, $00, $02 |
| $4123 | | .byte$01, $00, $00, $02, $00, $01, $00, $02 |
| $412B | | .byte$01, $00, $00, $02, $00, $01, $00, $02 |
| $4133 | | .byte$00, $02, $01, $00, $01, $00, $02, $01 |
| $413B | | .byte$00, $02, $01, $00, $01, $00, $02, $01 |
| $4143 | | .byte$00, $02, $01, $00, $01, $00, $02, $01 |
| $414B | | .byte$00, $02, $01, $00, $01, $00, $02, $01 |
| $4153 | | .byte$00, $02, $01, $00, $01, $00, $02, $01 |
| $415B | | .byte$02, $00, $00, $01, $02, $00, $02, $00 |
| $4163 | | .byte$02, $00, $00, $01, $02, $00, $02, $00 |
| $416B | | .byte$02, $00, $00, $01, $02, $00, $02, $00 |
| $4173 | | .byte$02, $00, $00, $01, $02, $00, $02, $00 |
| $417B | | .byte$02, $00, $00, $01, $02, $00, $02, $00 |
| $4183 | | .byte$01, $02, $00, $01, $00, $02, $00, $02 |
| $418B | | .byte$01, $02, $00, $01, $00, $02, $00, $02 |
| $4193 | | .byte$01, $02, $00, $01, $00, $02, $00, $02 |
| $419B | | .byte$01, $02, $00, $01, $00, $02, $00, $02 |
| $41A3 | | .byte$01, $02, $00, $01, $00, $02, $00, $02 |
| $41AB | | .byte$00, $01, $02, $00, $02, $01, $01, $00 |
| $41B3 | | .byte$00, $01, $02, $00, $02, $01, $01, $00 |
| $41BB | | .byte$00, $01, $02, $00, $02, $01, $01, $00 |
| $41C3 | | .byte$00, $01, $02, $00, $02, $01, $01, $00 |
| $41CB | | .byte$00, $01, $02, $00, $02, $01, $01, $00 |
| $41D3 | | .byte$01, $00, $00, $02, $00, $01, $00, $02 |
| $41DB | | .byte$01, $00, $00, $02, $00, $01, $00, $02 |
| $41E3 | | .byte$01, $00, $00, $02, $00, $01, $00, $02 |
| $41EB | | .byte$01, $00, $00, $02, $00, $01, $00, $02 |
| $41F3 | | .byte$01, $00, $00, $02, $00, $01, $00, $02 |
| $41FB | | .byte$00, $02, $01, $00, $01, $00, $02, $01 |
| $4203 | | .byte$00, $02, $01, $00, $01, $00, $02, $01 |
| $420B | | .byte$00, $02, $01, $00, $01, $00, $02, $01 |
| $4213 | | .byte$00, $02, $01, $00, $01, $00, $02, $01 |
| $421B | | .byte$00, $02, $01, $00, $01, $00, $02, $01 |
| $4223 | | .byte$02, $00, $00, $01, $02, $00, $02, $00 |
| $422B | | .byte$02, $00, $00, $01, $02, $00, $02, $00 |
| $4233 | | .byte$02, $00, $00, $01, $02, $00, $02, $00 |
| $423B | | .byte$02, $00, $00, $01, $02, $00, $02, $00 |
| $4243 | | .byte$02, $00, $00, $01, $02, $00, $02 |
| $424A | | .fill41, $00 |
| $4273 | | .byte$1a, $1b, $1c, $1a, $1b, $1c, $1a, $1b |
| $427B | | .byte$1c, $1a, $1b, $1c, $1a, $1b, $1c, $1a |
| $4283 | | .byte$1b, $1c, $1a, $1b, $1c, $1a, $1b, $1c |
| $428B | | .byte$1a, $1b, $1c, $1a, $1b, $1c, $1a, $1b |
| $4293 | | .byte$1c, $1a, $1b, $1c, $1a, $1b, $1c, $1a |
| $429B | | .byte$21, $23, $24, $21, $25, $24, $20, $25 |
| $42A3 | | .byte$21, $23, $24, $21, $25, $24, $20, $25 |
| $42AB | | .byte$21, $23, $24, $21, $25, $24, $20, $25 |
| $42B3 | | .byte$21, $23, $24, $21, $25, $24, $20, $25 |
| $42BB | | .byte$21, $23, $24, $21, $25, $24, $20, $25 |
| $42C3 | | .byte$20, $23, $20, $21, $22, $21, $22, $21 |
| $42CB | | .byte$20, $23, $20, $21, $22, $21, $22, $21 |
| $42D3 | | .byte$20, $23, $20, $21, $22, $21, $22, $21 |
| $42DB | | .byte$20, $23, $20, $21, $22, $21, $22, $21 |
| $42E3 | | .byte$20, $23, $20, $21, $22, $21, $22, $21 |
| $42EB | | .byte$20, $22, $21, $24, $24, $20, $20, $23 |
| $42F3 | | .byte$20, $22, $21, $24, $24, $20, $20, $23 |
| $42FB | | .byte$20, $22, $21, $24, $24, $20, $20, $23 |
| $4303 | | .byte$20, $22, $21, $24, $24, $20, $20, $23 |
| $430B | | .byte$20, $22, $21, $24, $24, $20, $20, $23 |
| $4313 | | .byte$23, $24, $24, $20, $22, $21, $25, $24 |
| $431B | | .byte$23, $24, $24, $20, $22, $21, $25, $24 |
| $4323 | | .byte$23, $24, $24, $20, $22, $21, $25, $24 |
| $432B | | .byte$23, $24, $24, $20, $22, $21, $25, $24 |
| $4333 | | .byte$23, $24, $24, $20, $22, $21, $25, $24 |
| $433B | | .byte$25, $21, $23, $21, $20, $25, $21, $25 |
| $4343 | | .byte$25, $21, $23, $21, $20, $25, $21, $25 |
| $434B | | .byte$25, $21, $23, $21, $20, $25, $21, $25 |
| $4353 | | .byte$25, $21, $23, $21, $20, $25, $21, $25 |
| $435B | | .byte$25, $21, $23, $21, $20, $25, $21, $25 |
| $4363 | | .byte$21, $23, $24, $21, $25, $24, $20, $25 |
| $436B | | .byte$21, $23, $24, $21, $25, $24, $20, $25 |
| $4373 | | .byte$21, $23, $24, $21, $25, $24, $20, $25 |
| $437B | | .byte$21, $23, $24, $21, $25, $24, $20, $25 |
| $4383 | | .byte$21, $23, $24, $21, $25, $24, $20, $25 |
| $438B | | .byte$20, $23, $20, $21, $22, $21, $22, $21 |
| $4393 | | .byte$20, $23, $20, $21, $22, $21, $22, $21 |
| $439B | | .byte$20, $23, $20, $21, $22, $21, $22, $21 |
| $43A3 | | .byte$20, $23, $20, $21, $22, $21, $22, $21 |
| $43AB | | .byte$20, $23, $20, $21, $22, $21, $22, $21 |
| $43B3 | | .byte$20, $22, $21, $24, $24, $20, $20, $23 |
| $43BB | | .byte$20, $22, $21, $24, $24, $20, $20, $23 |
| $43C3 | | .byte$20, $22, $21, $24, $24, $20, $20, $23 |
| $43CB | | .byte$20, $22, $21, $24, $24, $20, $20, $23 |
| $43D3 | | .byte$20, $22, $21, $24, $24, $20, $20, $23 |
| $43DB | | .byte$23, $24, $24, $20, $22, $21, $25, $24 |
| $43E3 | | .byte$23, $24, $24, $20, $22, $21, $25, $24 |
| $43EB | | .byte$23, $24, $24, $20, $22, $21, $25, $24 |
| $43F3 | | .byte$23, $24, $24, $20, $22, $21, $25, $24 |
| $43FB | | .byte$23, $24, $24, $20, $22, $21, $25, $24 |
| $4403 | | .byte$25, $21, $23, $21, $20, $25, $21, $25 |
| $440B | | .byte$25, $21, $23, $21, $20, $25, $21, $25 |
| $4413 | | .byte$25, $21, $23, $21, $20, $25, $21, $25 |
| $441B | | .byte$25, $21, $23, $21, $20, $25, $21, $25 |
| $4423 | | .byte$25, $21, $23, $21, $20, $25, $21, $25 |
| $442B | | .byte$21, $23, $24, $21, $25, $24, $20, $25 |
| $4433 | | .byte$21, $23, $24, $21, $25, $24, $20, $25 |
| $443B | | .byte$21, $23, $24, $21, $25, $24, $20, $25 |
| $4443 | | .byte$21, $23, $24, $21, $25, $24, $20, $25 |
| $444B | | .byte$21, $23, $24, $21, $25, $24, $20, $25 |
| $4453 | | .byte$20, $23, $20, $21, $22, $21, $22, $21 |
| $445B | | .byte$20, $23, $20, $21, $22, $21, $22, $21 |
| $4463 | | .byte$20, $23, $20, $21, $22, $21, $22, $21 |
| $446B | | .byte$20, $23, $20, $21, $22, $21, $22, $21 |
| $4473 | | .byte$20, $23, $20, $21, $22, $21, $22, $21 |
| $447B | | .byte$20, $22, $21, $24, $24, $20, $20, $23 |
| $4483 | | .byte$20, $22, $21, $24, $24, $20, $20, $23 |
| $448B | | .byte$20, $22, $21, $24, $24, $20, $20, $23 |
| $4493 | | .byte$20, $22, $21, $24, $24, $20, $20, $23 |
| $449B | | .byte$20, $22, $21, $24, $24, $20, $20, $23 |
| $44A3 | | .byte$23, $24, $24, $20, $22, $21, $25, $24 |
| $44AB | | .byte$23, $24, $24, $20, $22, $21, $25, $24 |
| $44B3 | | .byte$23, $24, $24, $20, $22, $21, $25, $24 |
| $44BB | | .byte$23, $24, $24, $20, $22, $21, $25, $24 |
| $44C3 | | .byte$23, $24, $24, $20, $22, $21, $25, $24 |
| $44CB | | .byte$25, $21, $23, $21, $20, $25, $21, $25 |
| $44D3 | | .byte$25, $21, $23, $21, $20, $25, $21, $25 |
| $44DB | | .byte$25, $21, $23, $21, $20, $25, $21, $25 |
| $44E3 | | .byte$25, $21, $23, $21, $20, $25, $21, $25 |
| $44EB | | .byte$25, $21, $23, $21, $20, $25, $21, $25 |
| $44F3 | | .byte$30, $31, $32, $33, $33, $32, $31, $30 |
| $44FB | | .byte$30, $31, $32, $33, $33, $32, $31, $30 |
| $4503 | | .byte$30, $31, $32, $33, $33, $32, $31, $30 |
| $450B | | .byte$30, $31, $32, $33, $33, $32, $31, $30 |
| $4513 | | .byte$30, $31, $32, $33, $33, $32, $31, $30 |
| $451B | | .byte$16, $17, $14, $14, $16, $17, $14, $14 |
| $4523 | | .byte$16, $17, $14, $14, $16, $17, $14, $14 |
| $452B | | .byte$16, $17, $14, $14, $16, $17, $14, $14 |
| $4533 | | .byte$16, $17, $14, $14, $16, $17, $14, $14 |
| $453B | | .byte$16, $17, $14, $14, $16, $17, $14, $14 |
| $4543 | | .byte$14, $15, $16, $14, $14, $15, $16, $14 |
| $454B | | .byte$14, $15, $16, $14, $14, $15, $16, $14 |
| $4553 | | .byte$14, $15, $16, $14, $14, $15, $16, $14 |
| $455B | | .byte$14, $15, $16, $14, $14, $15, $16, $14 |
| $4563 | | .byte$14, $15, $16, $14, $14, $15, $16, $14 |
| $456B | | .byte$17, $18, $14, $15, $17, $18, $14, $15 |
| $4573 | | .byte$17, $18, $14, $15, $17, $18, $14, $15 |
| $457B | | .byte$17, $18, $14, $15, $17, $18, $14, $15 |
| $4583 | | .byte$17, $18, $14, $15, $17, $18, $14, $15 |
| $458B | | .byte$17, $18, $14, $15, $17, $18, $14, $15 |
| $4593 | | .byte$15, $15, $16, $15, $15, $15, $16, $15 |
| $459B | | .byte$15, $15, $16, $15, $15, $15, $16, $15 |
| $45A3 | | .byte$15, $15, $16, $15, $15, $15, $16, $15 |
| $45AB | | .byte$15, $15, $16, $15, $15, $15, $16, $15 |
| $45B3 | | .byte$15, $15, $16, $15, $15, $15, $16, $15 |
| $45BB | | .byte$16, $18, $17, $19, $16, $18, $17, $19 |
| $45C3 | | .byte$16, $18, $17, $19, $16, $18, $17, $19 |
| $45CB | | .byte$16, $18, $17, $19, $16, $18, $17, $19 |
| $45D3 | | .byte$16, $18, $17, $19, $16, $18, $17, $19 |
| $45DB | | .byte$16, $18, $17, $19, $16, $18, $17, $19 |
| $45E3 | | .byte$16, $17, $14, $14, $16, $17, $14, $14 |
| $45EB | | .byte$16, $17, $14, $14, $16, $17, $14, $14 |
| $45F3 | | .byte$16, $17, $14, $14, $16, $17, $14, $14 |
| $45FB | | .byte$16, $17, $14, $14, $16, $17, $14, $14 |
| $4603 | | .byte$16, $17, $14, $14, $16, $17, $14, $14 |
| $460B | | .byte$14, $15, $16, $14, $14, $15, $16, $14 |
| $4613 | | .byte$14, $15, $16, $14, $14, $15, $16, $14 |
| $461B | | .byte$14, $15, $16, $14, $14, $15, $16, $14 |
| $4623 | | .byte$14, $15, $16, $14, $14, $15, $16, $14 |
| $462B | | .byte$14, $15, $16, $14, $14, $15, $16, $14 |
| $4633 | | .byte$17, $18, $14, $15, $17, $18, $14, $15 |
| $463B | | .byte$17, $18, $14, $15, $17, $18, $14, $15 |
| $4643 | | .byte$17, $18, $14, $15, $17, $18, $14, $15 |
| $464B | | .byte$17, $18, $14, $15, $17, $18, $14, $15 |
| $4653 | | .byte$17, $18, $14, $15, $17, $18, $14, $15 |
| $465B | | .byte$15, $15, $16, $15, $15, $15, $16, $15 |
| $4663 | | .byte$15, $15, $16, $15, $15, $15, $16, $15 |
| $466B | | .byte$15, $15, $16, $15, $15, $15, $16, $15 |
| $4673 | | .byte$15, $15, $16, $15, $15, $15, $16, $15 |
| $467B | | .byte$15, $15, $16, $15, $15, $15, $16, $15 |
| $4683 | | .byte$16, $18, $17, $19, $16, $18, $17, $19 |
| $468B | | .byte$16, $18, $17, $19, $16, $18, $17, $19 |
| $4693 | | .byte$16, $18, $17, $19, $16, $18, $17, $19 |
| $469B | | .byte$16, $18, $17, $19, $16, $18, $17, $19 |
| $46A3 | | .byte$16, $18, $17, $19, $16, $18, $17, $19 |
| $46AB | | .byte$16, $17, $14, $14, $16, $17, $14, $14 |
| $46B3 | | .byte$16, $17, $14, $14, $16, $17, $14, $14 |
| $46BB | | .byte$16, $17, $14, $14, $16, $17, $14, $14 |
| $46C3 | | .byte$16, $17, $14, $14, $16, $17, $14, $14 |
| $46CB | | .byte$16, $17, $14, $14, $16, $17, $14, $14 |
| $46D3 | | .byte$14, $15, $16, $14, $14, $15, $16, $14 |
| $46DB | | .byte$14, $15, $16, $14, $14, $15, $16, $14 |
| $46E3 | | .byte$14, $15, $16, $14, $14, $15, $16, $14 |
| $46EB | | .byte$14, $15, $16, $14, $14, $15, $16, $14 |
| $46F3 | | .byte$14, $15, $16, $14, $14, $15, $16, $14 |
| $46FB | | .byte$17, $18, $14, $15, $17, $18, $14, $15 |
| $4703 | | .byte$17, $18, $14, $15, $17, $18, $14, $15 |
| $470B | | .byte$17, $18, $14, $15, $17, $18, $14, $15 |
| $4713 | | .byte$17, $18, $14, $15, $17, $18, $14, $15 |
| $471B | | .byte$17, $18, $14, $15, $17, $18, $14, $15 |
| $4723 | | .byte$15, $15, $16, $15, $15, $15, $16, $15 |
| $472B | | .byte$15, $15, $16, $15, $15, $15, $16, $15 |
| $4733 | | .byte$15, $15, $16, $15, $15, $15, $16, $15 |
| $473B | | .byte$15, $15, $16, $15, $15, $15, $16, $15 |
| $4743 | | .byte$15, $15, $16, $15, $15, $15, $16, $15 |
| $474B | | .byte$16, $18, $17, $19, $16, $18, $17, $19 |
| $4753 | | .byte$16, $18, $17, $19, $16, $18, $17, $19 |
| $475B | | .byte$16, $18, $17, $19, $16, $18, $17, $19 |
| $4763 | | .byte$16, $18, $17, $19, $16, $18, $17, $19 |
| $476B | | .byte$16, $18, $17, $19, $16, $18, $17, $19 |
| $4773 | | .byte$16, $17, $14, $14, $16, $17, $14, $14 |
| $477B | | .byte$16, $17, $14, $14, $16, $17, $14, $14 |
| $4783 | | .byte$16, $17, $14, $14, $16, $17, $14, $14 |
| $478B | | .byte$16, $17, $14, $14, $16, $17, $14, $14 |
| $4793 | | .byte$16, $17, $14, $14, $16, $17, $14, $14 |
| $479B | | .byte$b0, $b1, $b2, $b3, $b3, $b2, $b1, $b0 |
| $47A3 | | .byte$b0, $b1, $b2, $b3, $b3, $b2, $b1, $b0 |
| $47AB | | .byte$b0, $b1, $b2, $b3, $b3, $b2, $b1, $b0 |
| $47B3 | | .byte$b0, $b1, $b2, $b3, $b3, $b2, $b1, $b0 |
| $47BB | | .byte$b0, $b1, $b2, $b3, $b3, $b2, $b1, $b0 |
| ; Background/ceiling tile indices, 120 entries (3 rows × 40 cols). Used when no wall above to fill background. |
| $47C3 | | bg_tile_table.byte$00, $07, $01, $06, $01, $00, $06, $01; x-ref: $4F3C, $4F4B, $4F5F |
| $47CB | | .byte$00, $07, $02, $00, $08, $02, $06, $00 |
| $47D3 | | .byte$02, $06, $07, $02, $01, $00, $01, $02 |
| $47DB | | .byte$06, $02, $07, $02, $00, $06, $02, $00 |
| $47E3 | | .byte$02, $06, $00, $00, $08, $01, $00, $06 |
| $47EB | | .byte$03, $05, $04, $03, $03, $04, $04, $05 |
| $47F3 | | .byte$03, $04, $03, $05, $04, $05, $04, $05 |
| $47FB | | .byte$04, $03, $03, $03, $05, $04, $05, $04 |
| $4803 | | .byte$05, $03, $04, $05, $04, $03, $05, $05 |
| $480B | | .byte$03, $03, $04, $05, $04, $03, $05, $04 |
| $4813 | | .byte$da, $db, $dc, $db, $dc, $db, $dc, $dc |
| $481B | | .byte$da, $dc, $da, $da, $dc, $db, $da, $da |
| $4823 | | .byte$dc, $da, $db, $dc, $dc, $db, $db, $dc |
| $482B | | .byte$da, $da, $da, $da, $dc, $db, $db, $da |
| $4833 | | .byte$dc, $db, $db, $da, $db, $db, $da, $dc |
| ; Wall decoration tile indices, 120 entries (3 rows × 40 cols). Drawn below wall edges. |
| $483B | | wall_tile_table.byte$dd, $df, $dd, $df, $dd, $df, $dd, $dd; x-ref: $4F82, $4F8C, $4F9A, $4FA8 |
| $4843 | | .byte$de, $dd, $de, $de, $dd, $df, $de, $de |
| $484B | | .byte$dd, $de, $df, $dd, $dd, $df, $df, $dd |
| $4853 | | .byte$de, $de, $de, $de, $dd, $df, $df, $de |
| $485B | | .byte$dd, $df, $df, $de, $df, $df, $de, $dd |
| $4863 | | .byte$0a, $0b, $09, $09, $0b, $0a, $0b, $0b |
| $486B | | .byte$0a, $0b, $09, $0b, $09, $0a, $0b, $09 |
| $4873 | | .byte$0a, $0b, $0b, $09, $0a, $0a, $0b, $0a |
| $487B | | .byte$09, $0b, $09, $09, $0b, $0a, $09, $09 |
| $4883 | | .byte$0b, $0a, $0b, $09, $09, $0b, $0a, $0b |
| $488B | | .byte$00, $01, $0c, $02, $00, $01, $07, $00 |
| $4893 | | .byte$01, $0c, $00, $02, $00, $01, $0c, $01 |
| $489B | | .byte$00, $01, $00, $08, $01, $0c, $00, $00 |
| $48A3 | | .byte$0c, $01, $07, $08, $00, $01, $0c, $00 |
| $48AB | | .byte$00, $0c, $00, $0c, $01, $0c, $02, $07 |
| $48B3 | | .byte$02, $00, $08, $00, $02, $00, $08, $02 |
| $48BB | | .byte$00, $08, $00, $00, $02, $00, $08, $02 |
| $48C3 | | .byte$00, $08, $01, $00, $00, $02, $00, $00 |
| $48CB | | .byte$08, $00, $08, $01, $00, $07, $08, $01 |
| $48D3 | | .byte$00, $08, $00, $00, $00, $01, $00 |
| ; Outer corner tile indices (15 entries). Values $26-$28 for top-right wall corners. |
| $48DA | | outer_corner_tiles.byte$08, $27, $26, $26, $28, $27, $26, $26; x-ref: $4F06 |
| $48E2 | | .byte$28, $28, $26, $27, $26, $28, $26 |
| ; Inner corner tile indices (16 entries). Values $29-$2B for wall inner corners. |
| $48E9 | | inner_corner_tiles.byte$27, $2a, $29, $2b, $2a, $29, $29, $2a; x-ref: $4F14 |
| $48F1 | | .byte$2a, $2b, $29, $2b, $2a, $29, $2b, $2a |
| ; World color palette (4 entries, one per world). Stored to $3F9F during level decompression. |
| $48F9 | | world_color_0.byteVicIIColors.BROWN; brown ; x-ref: $49FC |
| $48FA | | .byteVicIIColors.GREEN; green |
| $48FB | | .byteVicIIColors.BLUE; blue |
| $48FC | | .byteVicIIColors.GREY; grey |
| ; World color palette (4 entries, one per world). Stored to $3FA0 during level decompression. |
| $48FD | | world_color_1.byteVicIIColors.ORANGE; orange ; x-ref: $4A02 |
| $48FE | | .byteVicIIColors.LIGHT_GREEN; light green |
| $48FF | | .byteVicIIColors.LIGHT_BLUE; light blue |
| $4900 | | .byteVicIIColors.LIGHT_GREY; grey |
| ; World color palette (4 entries, one per world). Stored to $3FA1 during level decompression. |
| $4901 | | world_color_2.byteVicIIColors.GREEN; green ; x-ref: $4A08 |
| $4902 | | .byteVicIIColors.YELLOW; yellow |
| $4903 | | .byteVicIIColors.GREY; grey |
| $4904 | | .byteVicIIColors.LIGHT_GREEN; light green |
| ; World color palette (4 entries, one per world). Stored to $3FA2 during level decompression. |
| $4905 | | world_color_3.byteVicIIColors.BLUE; blue ; x-ref: $4A0E |
| $4906 | | .byteVicIIColors.RED; red |
| $4907 | | .byteVicIIColors.PURPLE; purple |
| $4908 | | .byteVicIIColors.GREEN; green |
| ; Level map row pointer table (low bytes). 96 entries indexed by level row. Points into $E800-$EF00 tile map buffer. Each row offset = 18 ($12) bytes. |
| $4909 | | level_map_ptr_lo.byte$b8, $ca, $dc, $ee, $00, $12, $24, $36; x-ref: $722B, $7772, $85F9, $875D |
| $4911 | | .byte$48, $5a, $6c, $7e, $90, $a2, $b4, $c6 |
| $4919 | | .byte$d8, $ea, $fc, $0e, $20, $32, $44, $56 |
| $4921 | | .byte$68, $7a, $8c, $9e, $b0, $c2, $d4, $e6 |
| $4929 | | .byte$f8, $0a, $1c, $2e, $40, $52, $64, $76 |
| $4931 | | .byte$88, $9a, $ac, $be, $d0, $e2, $f4, $06 |
| $4939 | | .byte$18, $2a, $3c, $4e, $60, $72, $84, $96 |
| $4941 | | .byte$a8, $ba, $cc, $de, $f0, $02, $14, $26 |
| $4949 | | .byte$38, $4a, $5c, $6e, $80, $92, $a4, $b6 |
| $4951 | | .byte$c8, $da, $ec, $fe, $10, $22, $34, $46 |
| $4959 | | .byte$58, $6a, $7c, $8e, $a0, $b2, $c4, $d6 |
| $4961 | | .byte$e8, $fa, $0c, $1e, $30, $42, $54, $66 |
| ; Level map row pointer table (high bytes). 96 entries paired with level_map_ptr_lo. Points into $E800-$EF00 tile map buffer. |
| $4969 | | level_map_ptr_hi.byte$e8, $e8, $e8, $e8; x-ref: $7230, $7777, $85FE, $8762 |
| $496D | | .fill15, $e9 |
| $497C | | .fill14, $ea |
| $498A | | .fill14, $eb |
| $4998 | | .fill14, $ec |
| $49A6 | | .fill15, $ed |
| $49B5 | | .fill14, $ee |
| $49C3 | | .byte$ef, $ef, $ef, $ef, $ef, $ef |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| ; Decompresses the cave/level map data into the tile map buffer. |
| ; Reads compressed tile data from $1300, decodes run-length and skip markers, |
| ; and writes 96 rows x 18 columns of tile indices into the map buffer at $E000. |
| ; Also initializes the row-offset table at $EF78 and sets the level color |
| ; palette from the current world index ($60D9). |
| ; |
| ; Inputs: a_60D9 (current world index, bits 0-1 select color palette) |
| ; Compressed map data at $1300 |
| ; Outputs: Tile map at $E000, row offsets at $EF78, colors at $3F9F-$3FA2 |
| ; Side Effects: Modifies zero-page $02-$05, $1D-$1F, $FB-$FC |
| ; Calls s_4AF0 to post-process the decompressed map |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| $49C9 | a2 5f | decompress_cave_mapldx#$5f; 96 rows to process ; x-ref: $615A |
| $49CB | a9 b8 | lda#$b8; ptr $FB/$FC = $E8B8 (tile map buffer) |
| $49CD | 85 fb | stazp_ptr_src_lo |
| $49CF | a9 e8 | lda#$e8 |
| $49D1 | 85 fc | stazp_ptr_src_hi |
| $49D3 | a0 11 | b_49D3ldy#$11; 18 columns per row ; x-ref: $49EA |
| $49D5 | a9 ff | lda#$ff; $FF = empty/default tile |
| $49D7 | 91 fb | b_49D7sta(zp_ptr_src_lo),y; fill row with $FF ; x-ref: $49DA |
| $49D9 | 88 | dey |
| $49DA | 10 fb | bplb_49D7 |
| $49DC | a5 fb | ldazp_ptr_src_lo; advance ptr by 18 to next row |
| $49DE | 18 | clc |
| $49DF | 69 12 | adc#$12 |
| $49E1 | 85 fb | stazp_ptr_src_lo |
| $49E3 | a5 fc | ldazp_ptr_src_hi |
| $49E5 | 69 00 | adc#$00 |
| $49E7 | 85 fc | stazp_ptr_src_hi |
| $49E9 | ca | dex; loop until all 96 rows cleared |
| $49EA | 10 e7 | bplb_49D3 |
| $49EC | a2 5f | ldx#$5f; clear 96 row-offset entries |
| $49EE | a9 00 | lda#$00; $00 = initial offset |
| $49F0 | 9d 78 ef | b_49F0stascreen_slot_table,x; Clear all 96 room slots to 0 (unvisited) ; x-ref: $49F4 |
| $49F3 | ca | dex |
| $49F4 | 10 fa | bplb_49F0 |
| $49F6 | ad d9 60 | ldacurrent_level; world index (0-3) |
| $49F9 | 29 03 | and#$03; mask to 2 bits (4 worlds) |
| $49FB | aa | tax |
| $49FC | bd f9 48 | ldaworld_color_0,x; Load world color 0 by world index; brown |
| $49FF | 8d 9f 3f | stalevel_color_top; store as level colors $3F9F-$3FA2 |
| $4A02 | bd fd 48 | ldaworld_color_1,x; Load world color 1 by world index; orange |
| $4A05 | 8d a0 3f | stalevel_color_bottom; Color value for the bottom section of the playfield |
| $4A08 | bd 01 49 | ldaworld_color_2,x; Load world color 2 by world index; green |
| $4A0B | 8d a1 3f | stalevel_color_border; Border/background color 3 for the level |
| $4A0E | bd 05 49 | ldaworld_color_3,x; Load world color 3 by world index; blue |
| $4A11 | 8d a2 3f | stalevel_color_multicolor; VIC-II ECM multicolor value ($D023) for the level |
| $4A14 | a9 00 | lda#$00; source ptr $02/$03 = $1300 (compressed data) |
| $4A16 | 85 02 | stazp_work0 |
| $4A18 | a9 13 | lda#$13 |
| $4A1A | 85 03 | stazp_work1 |
| $4A1C | a9 00 | lda#$00; dest ptr $04/$05 = $E000 (tile map) |
| $4A1E | 85 04 | stazp_work2 |
| $4A20 | a9 e0 | lda#$e0 |
| $4A22 | 85 05 | stazp_work3 |
| $4A24 | a9 00 | lda#$00; row counter = 0 |
| $4A26 | 85 1d | stazp_ptr_map_hi |
| $4A28 | a0 00 | ldy#$00 |
| $4A2A | a5 02 | b_4A2Aldazp_work0; -- begin row decompression loop -- ; x-ref: $4A60 |
| $4A2C | 91 04 | sta(zp_work2),y; write low byte of source to dest (tile index) |
| $4A2E | e6 04 | inczp_work2; advance dest pointer |
| $4A30 | d0 02 | bneb_4A34 |
| $4A32 | e6 05 | inczp_work3 |
| $4A34 | a5 03 | b_4A34ldazp_work1; write high byte of source to dest ; x-ref: $4A30 |
| $4A36 | 91 04 | sta(zp_work2),y |
| $4A38 | e6 04 | inczp_work2 |
| $4A3A | d0 02 | bneb_4A3E |
| $4A3C | e6 05 | inczp_work3 |
| $4A3E | b1 02 | b_4A3Elda(zp_work0),y; check for $FF = end-of-row marker ; x-ref: $4A3A |
| $4A40 | c9 ff | cmp#$ff |
| $4A42 | d0 09 | bneb_4A4D |
| $4A44 | e6 02 | inczp_work0 |
| $4A46 | d0 02 | bneb_4A4A |
| $4A48 | e6 03 | inczp_work1 |
| $4A4A | 4c 5a 4a | b_4A4Ajmpj_4A5A; x-ref: $4A46 |
| $4A4D | a9 00 | b_4A4Dlda#$00; column counter = 0 ; x-ref: $4A42 |
| $4A4F | 85 1e | stazp_temp_x |
| $4A51 | 20 70 4a | b_4A51jsrdecode_tile_entry; decode one tile entry ; x-ref: $4A58 |
| $4A54 | a5 1e | ldazp_temp_x; check if 18 columns done |
| $4A56 | c9 11 | cmp#$11 |
| $4A58 | d0 f7 | bneb_4A51 |
| $4A5A | e6 1d | j_4A5Ainczp_ptr_map_hi; next row ; x-ref: $4A4A |
| $4A5C | a5 1d | ldazp_ptr_map_hi; all 96 rows done? |
| $4A5E | c9 60 | cmp#$60 |
| $4A60 | d0 c8 | bneb_4A2A |
| $4A62 | a9 ff | lda#$ff; signal: decompression active |
| $4A64 | 8d a5 3f | stamap_decompressing |
| $4A67 | 20 f0 4a | jsrrender_level_screen; post-process decompressed map |
| $4A6A | a9 00 | lda#$00; signal: decompression done |
| $4A6C | 8d a5 3f | stamap_decompressing |
| $4A6F | 60 | rts |
| ; Decodes one compressed tile entry from the source stream. |
| ; $F5 = end-of-row, $E4+ = multi-skip, $D4+ = single-skip with column advance, |
| ; < $D4 = raw tile data processed by s_4AB6. |
| $4A70 | b1 02 | decode_tile_entrylda(zp_work0),y; Read next byte from map data stream ; x-ref: $4A51 |
| $4A72 | c9 f5 | cmp#$f5; $F5 = end-of-row marker? |
| $4A74 | d0 0b | bneb_4A81 |
| $4A76 | a9 11 | lda#$11; set column = 18 (force row end) |
| $4A78 | 85 1e | stazp_temp_x; Store end-of-row flag in column counter |
| $4A7A | e6 02 | inczp_work0; Advance data pointer low byte |
| $4A7C | d0 02 | bner_4A80; Skip high byte increment if no carry |
| $4A7E | e6 03 | inczp_work1; Advance data pointer high byte |
| $4A80 | 60 | r_4A80rts; x-ref: $4A7C |
| $4A81 | c9 e4 | b_4A81cmp#$e4; >= $E4? multi-column skip ; x-ref: $4A74 |
| $4A83 | 90 0e | bccb_4A93 |
| $4A85 | e9 e3 | sbc#$e3; skip count = value - $E3 |
| $4A87 | 18 | clc |
| $4A88 | 65 1e | adczp_temp_x; add to column counter |
| $4A8A | 85 1e | stazp_temp_x; Update column counter |
| $4A8C | e6 02 | inczp_work0 |
| $4A8E | d0 02 | bner_4A92 |
| $4A90 | e6 03 | inczp_work1 |
| $4A92 | 60 | r_4A92rts; x-ref: $4A8E |
| $4A93 | c9 d4 | b_4A93cmp#$d4; >= $D4? single-column skip ; x-ref: $4A83 |
| $4A95 | 90 09 | bccb_4AA0 |
| $4A97 | e6 1e | inczp_temp_x; advance column by 1 |
| $4A99 | e6 02 | inczp_work0 |
| $4A9B | d0 02 | bner_4A9F |
| $4A9D | e6 03 | inczp_work1 |
| $4A9F | 60 | r_4A9Frts; x-ref: $4A9B |
| $4AA0 | a9 00 | b_4AA0lda#$00; raw tile data: decode via s_4AB6 ; x-ref: $4A95 |
| $4AA2 | 85 1f | stazp_temp_y |
| $4AA4 | 20 b6 4a | b_4AA4jsrdecode_raw_tile_byte; Process tile through width accumulator ; x-ref: $4AB1 |
| $4AA7 | e6 02 | inczp_work0; Advance data pointer past tile byte |
| $4AA9 | d0 02 | bneb_4AAD |
| $4AAB | e6 03 | inczp_work1 |
| $4AAD | a5 1f | b_4AADldazp_temp_y; 40 bytes per tile row? ; x-ref: $4AA9 |
| $4AAF | c9 28 | cmp#$28 |
| $4AB1 | d0 f1 | bneb_4AA4; Loop until row width filled |
| $4AB3 | e6 1e | inczp_temp_x; column done |
| $4AB5 | 60 | rts |
| ; Decodes a raw tile byte from the compressed stream. |
| ; Values $00-$27: add 1 + accumulate into pixel offset. |
| ; Values $28-$4F: add with wrap (subtract $27) into pixel offset. |
| ; Values $50-$77: add with wrap (subtract $4F) into pixel offset. |
| ; Values $78-$C7: set pixel offset = 40 (full row width). |
| ; Value $D3: store current row as special row marker at $3F9E. |
| ; Other >= $C8: increment pixel offset by 1. |
| $4AB6 | b1 02 | decode_raw_tile_bytelda(zp_work0),y; Read byte from RLE data stream ; x-ref: $4AA4 |
| $4AB8 | c9 28 | cmp#$28; < $28? range 0: small offset |
| $4ABA | b0 07 | bcsb_4AC3 |
| $4ABC | 69 01 | adc#$01; offset += value + 1 |
| $4ABE | 65 1f | adczp_temp_y; Add to running column count |
| $4AC0 | 85 1f | stazp_temp_y; Store updated column count |
| $4AC2 | 60 | rts |
| $4AC3 | c9 50 | b_4AC3cmp#$50; < $50? range 1: medium offset ; x-ref: $4ABA |
| $4AC5 | b0 08 | bcsb_4ACF |
| $4AC7 | 65 1f | adczp_temp_y; offset += value - $27 |
| $4AC9 | 38 | sec |
| $4ACA | e9 27 | sbc#$27 |
| $4ACC | 85 1f | stazp_temp_y |
| $4ACE | 60 | rts |
| $4ACF | c9 78 | b_4ACFcmp#$78; < $78? range 2: large offset ; x-ref: $4AC5 |
| $4AD1 | b0 08 | bcsb_4ADB |
| $4AD3 | 65 1f | adczp_temp_y; offset += value - $4F |
| $4AD5 | 38 | sec |
| $4AD6 | e9 4f | sbc#$4f |
| $4AD8 | 85 1f | stazp_temp_y |
| $4ADA | 60 | rts |
| $4ADB | c9 c8 | b_4ADBcmp#$c8; < $C8? set offset = 40 (full width) ; x-ref: $4AD1 |
| $4ADD | b0 05 | bcsb_4AE4 |
| $4ADF | a9 28 | lda#$28; offset = 40 (full row) |
| $4AE1 | 85 1f | stazp_temp_y |
| $4AE3 | 60 | rts |
| $4AE4 | c9 d3 | b_4AE4cmp#$d3; == $D3? special row marker ; x-ref: $4ADD |
| $4AE6 | d0 05 | bneb_4AED |
| $4AE8 | a5 1d | ldazp_ptr_map_hi; store row index as special marker |
| $4AEA | 8d 9e 3f | stacurrent_room_index; Store room index from decompressor |
| $4AED | e6 1f | b_4AEDinczp_temp_y; default: offset += 1 ; x-ref: $4AE6 |
| $4AEF | 60 | rts |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| ; Renders the current level/room screen. |
| ; Uses a_3F9E as the room index, looks up compressed screen data |
| ; from the table at $E000, decompresses RLE tiles into screen RAM |
| ; ($0400-$06A7), copies color data to color RAM ($D800-$DBFE), |
| ; sets up sprite multicolor registers, and enables all sprites. |
| ; If screen data starts with $FF, clears the screen and disables sprites. |
| ; |
| ; Inputs: a_3F9E (room/level index) |
| ; Outputs: Screen RAM ($0400), Color RAM ($D800), sprite config |
| ; Side Effects: Disables then re-enables sprites, calls 8 subsystem |
| ; reset routines, modifies VIC-II registers ($D015, |
| ; $D024, $D025, $D026) |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| $4AF0 | a9 ff | render_level_screenlda#$ff; set rendering-in-progress flag ; x-ref: $4A67, $501B, $502E, $5042, $5052 |
| $4AF2 | 8d a7 3f | starendering_in_progress; Set rendering_in_progress = $FF (lock) |
| $4AF5 | ad c2 77 | ldahazard_active; OR animation flags from 3 subsystems |
| $4AF8 | 0d 73 7a | oratile14_active_flag |
| $4AFB | 0d ab 82 | oratile13_active_flag |
| $4AFE | 8d a8 3f | stasaved_animation_flags; Save combined animation flags snapshot |
| $4B01 | 20 0f 6f | jsrreset_color_flash; reset subsystem 1 |
| $4B04 | 20 0d 72 | jsrreset_animated_tiles; reset subsystem 2 |
| $4B07 | 20 c6 77 | jsrreset_hazard; reset subsystem 3 |
| $4B0A | 20 17 7a | jsrreset_water_animation; reset subsystem 4 |
| $4B0D | 20 78 7a | jsrreset_tile14_state; reset subsystem 5 |
| $4B10 | 20 b0 82 | jsrreset_tile13_scroll; reset subsystem 6 |
| $4B13 | 20 7b 84 | jsrreset_raft; reset subsystem 7 |
| $4B16 | 20 e6 85 | jsrreset_dynamic_tiles; reset subsystem 8 |
| $4B19 | a9 00 | lda#$00; clear the screen-changed flag |
| $4B1B | 8d a6 3f | stascreen_changed_flag |
| $4B1E | ad 9e 3f | ldacurrent_room_index; Clear screen_changed_flag before render |
| $4B21 | 0a | asla |
| $4B22 | aa | tax |
| $4B23 | bd 00 e0 | ldaroom_data_ptrs_lo,x; Load room screen data pointer lo from table; $E000 Reset Code |
| $4B26 | 85 02 | stazp_work0 |
| $4B28 | bd 01 e0 | ldaroom_data_ptrs_hi,x; Load room screen data pointer hi from table |
| $4B2B | 85 03 | stazp_work1 |
| $4B2D | a0 00 | ldy#$00; read first byte of screen data |
| $4B2F | b1 02 | lda(zp_work0),y |
| $4B31 | c9 ff | cmp#$ff; $FF = empty room marker |
| $4B33 | d0 1b | bneb_4B50 |
| $4B35 | a9 00 | lda#$00; disable all sprites for empty room |
| $4B37 | 8d 15 d0 | sta$d015; Sprite display Enable |
| $4B3A | a2 00 | ldx#$00 |
| $4B3C | a9 00 | lda#$00 |
| $4B3E | 9d 00 04 | b_4B3EstaSCREEN_RAM,x; clear 4 pages of screen RAM ($0400-$06A7) ; x-ref: $4B4D |
| $4B41 | 9d aa 04 | staSCREEN_RAM_R4C10,x |
| $4B44 | 9d 54 05 | staSCREEN_RAM_R8C20,x |
| $4B47 | 9d fe 05 | staSCREEN_RAM_R12C30,x |
| $4B4A | e8 | inx |
| $4B4B | e0 aa | cpx#$aa; loop 170 ($AA) bytes per page |
| $4B4D | d0 ef | bneb_4B3E |
| $4B4F | 60 | rts |
| $4B50 | a9 c0 | b_4B50lda#$c0; set dest ptr = $E0C0 (decompressed tile buffer) ; x-ref: $4B33 |
| $4B52 | 85 04 | stazp_work2 |
| $4B54 | a9 e0 | lda#$e0 |
| $4B56 | 85 05 | stazp_work3 |
| $4B58 | a9 11 | lda#$11; 17 rows to decompress |
| $4B5A | 85 1e | stazp_temp_x |
| $4B5C | 20 e1 4c | b_4B5Cjsrdecode_level_row; decompress one row of RLE data ; x-ref: $4B61 |
| $4B5F | a5 1e | ldazp_temp_x |
| $4B61 | d0 f9 | bneb_4B5C |
| $4B63 | 20 17 4e | jsrfill_screen_colors; set up level tile attribute lookups |
| $4B66 | a9 c0 | lda#$c0 |
| $4B68 | 85 02 | stazp_work0 |
| $4B6A | a9 e0 | lda#$e0 |
| $4B6C | 85 03 | stazp_work1 |
| $4B6E | a9 68 | lda#$68 |
| $4B70 | 85 04 | stazp_work2 |
| $4B72 | a9 e3 | lda#$e3 |
| $4B74 | 85 05 | stazp_work3 |
| $4B76 | a9 73 | lda#$73 |
| $4B78 | 85 06 | stazp_ptr_aux1_lo |
| $4B7A | a9 42 | lda#$42 |
| $4B7C | 85 07 | stazp_ptr_aux1_hi |
| $4B7E | a9 1b | lda#$1b |
| $4B80 | 85 08 | stazp_ptr_aux2_lo |
| $4B82 | a9 45 | lda#$45 |
| $4B84 | 85 09 | stazp_ptr_aux2_hi |
| $4B86 | a9 cb | lda#$cb |
| $4B88 | 85 0a | stazp_ptr_aux3_lo |
| $4B8A | a9 3f | lda#$3f |
| $4B8C | 85 0b | stazp_ptr_aux3_hi |
| $4B8E | a9 10 | lda#$10 |
| $4B90 | 85 0c | stazp_ptr_aux4_lo |
| $4B92 | a9 e6 | lda#$e6 |
| $4B94 | 85 0d | stazp_ptr_aux4_hi |
| $4B96 | a2 00 | ldx#$00; process column right-to-left (39 to 0) |
| $4B98 | a0 27 | j_4B98ldy#$27; x-ref: $4C26 |
| $4B9A | b1 02 | b_4B9Alda(zp_work0),y; x-ref: $4BD1 |
| $4B9C | f0 2e | beqb_4BCC; tile=0 → use background char |
| $4B9E | c9 05 | cmp#$05; tile >= 5 → complex tile handler |
| $4BA0 | 90 06 | bccb_4BA8 |
| $4BA2 | 20 b5 4f | jsrdispatch_complex_tile |
| $4BA5 | 4c cc 4b | jmpb_4BCC |
| $4BA8 | c9 01 | b_4BA8cmp#$01; tile=1 → use primary char lookup ; x-ref: $4BA0 |
| $4BAA | d0 05 | bneb_4BB1 |
| $4BAC | b1 06 | lda(zp_ptr_aux1_lo),y |
| $4BAE | 4c ce 4b | jmpj_4BCE |
| $4BB1 | c9 02 | b_4BB1cmp#$02; x-ref: $4BAA |
| $4BB3 | d0 09 | bneb_4BBE |
| $4BB5 | a9 02 | lda#$02 |
| $4BB7 | 91 0c | sta(zp_ptr_aux4_lo),y |
| $4BB9 | b1 08 | lda(zp_ptr_aux2_lo),y |
| $4BBB | 4c ce 4b | jmpj_4BCE |
| $4BBE | c9 03 | b_4BBEcmp#$03; tile=3 → solid block ($80) ; x-ref: $4BB3 |
| $4BC0 | d0 05 | bneb_4BC7 |
| $4BC2 | a9 80 | lda#$80 |
| $4BC4 | 4c ce 4b | jmpj_4BCE |
| $4BC7 | b1 08 | b_4BC7lda(zp_ptr_aux2_lo),y; x-ref: $4BC0 |
| $4BC9 | 4c ce 4b | jmpj_4BCE |
| $4BCC | b1 0a | b_4BCClda(zp_ptr_aux3_lo),y; tile=0: use background fill char ; x-ref: $4B9C, $4BA5 |
| $4BCE | 91 04 | j_4BCEsta(zp_work2),y; store char to dest screen buffer ; x-ref: $4BAE, $4BBB, $4BC4, $4BC9 |
| $4BD0 | 88 | dey |
| $4BD1 | 10 c7 | bplb_4B9A |
| $4BD3 | e8 | inx; advance all 6 source pointers by 40 cols |
| $4BD4 | e0 11 | cpx#$11 |
| $4BD6 | f0 51 | beqb_4C29 |
| $4BD8 | a5 02 | ldazp_work0 |
| $4BDA | 18 | clc |
| $4BDB | 69 28 | adc#$28 |
| $4BDD | 85 02 | stazp_work0 |
| $4BDF | a5 03 | ldazp_work1 |
| $4BE1 | 69 00 | adc#$00 |
| $4BE3 | 85 03 | stazp_work1 |
| $4BE5 | a5 04 | ldazp_work2 |
| $4BE7 | 18 | clc |
| $4BE8 | 69 28 | adc#$28 |
| $4BEA | 85 04 | stazp_work2 |
| $4BEC | a5 05 | ldazp_work3 |
| $4BEE | 69 00 | adc#$00 |
| $4BF0 | 85 05 | stazp_work3 |
| $4BF2 | a5 06 | ldazp_ptr_aux1_lo |
| $4BF4 | 18 | clc |
| $4BF5 | 69 28 | adc#$28 |
| $4BF7 | 85 06 | stazp_ptr_aux1_lo |
| $4BF9 | a5 07 | ldazp_ptr_aux1_hi |
| $4BFB | 69 00 | adc#$00 |
| $4BFD | 85 07 | stazp_ptr_aux1_hi |
| $4BFF | a5 08 | ldazp_ptr_aux2_lo |
| $4C01 | 18 | clc |
| $4C02 | 69 28 | adc#$28 |
| $4C04 | 85 08 | stazp_ptr_aux2_lo |
| $4C06 | a5 09 | ldazp_ptr_aux2_hi |
| $4C08 | 69 00 | adc#$00 |
| $4C0A | 85 09 | stazp_ptr_aux2_hi |
| $4C0C | a5 0a | ldazp_ptr_aux3_lo |
| $4C0E | 18 | clc |
| $4C0F | 69 28 | adc#$28 |
| $4C11 | 85 0a | stazp_ptr_aux3_lo |
| $4C13 | a5 0b | ldazp_ptr_aux3_hi |
| $4C15 | 69 00 | adc#$00 |
| $4C17 | 85 0b | stazp_ptr_aux3_hi |
| $4C19 | a5 0c | ldazp_ptr_aux4_lo |
| $4C1B | 18 | clc |
| $4C1C | 69 28 | adc#$28 |
| $4C1E | 85 0c | stazp_ptr_aux4_lo |
| $4C20 | a5 0d | ldazp_ptr_aux4_hi |
| $4C22 | 69 00 | adc#$00 |
| $4C24 | 85 0d | stazp_ptr_aux4_hi |
| $4C26 | 4c 98 4b | jmpj_4B98 |
| $4C29 | a2 11 | b_4C29ldx#$11; x-ref: $4BD6 |
| $4C2B | a9 ff | lda#$ff |
| $4C2D | 9d 33 00 | b_4C2Dsta@w zp_spr_y_pos,x; x-ref: $4C31 |
| $4C30 | ca | dex |
| $4C31 | 10 fa | bplb_4C2D |
| $4C33 | ae a8 3f | ldxsaved_animation_flags; Restore saved_animation_flags after reset |
| $4C36 | d0 03 | bneb_4C3B; jump back for next row |
| $4C38 | 8d 45 00 | sta@w zp_screen_dirty; conditional: mark screen dirty if no animation |
| $4C3B | a9 90 | b_4C3Blda#$90; x-ref: $4C36 |
| $4C3D | 85 02 | stazp_work0 |
| $4C3F | a9 e3 | lda#$e3 |
| $4C41 | 85 03 | stazp_work1 |
| $4C43 | a2 0f | ldx#$0f; if no animation active, mark all rows dirty |
| $4C45 | a0 27 | b_4C45ldy#$27; x-ref: $4C61 |
| $4C47 | b1 02 | b_4C47lda(zp_work0),y; x-ref: $4C51 |
| $4C49 | c9 0d | cmp#$0d |
| $4C4B | 90 03 | bccb_4C50; set color source ptr = $E390 |
| $4C4D | 20 7a 4e | jsrdraw_wall_autotile |
| $4C50 | 88 | b_4C50dey; x-ref: $4C4B |
| $4C51 | 10 f4 | bplb_4C47; 16 rows of color data to process |
| $4C53 | a5 02 | ldazp_work0 |
| $4C55 | 18 | clc |
| $4C56 | 69 28 | adc#$28 |
| $4C58 | 85 02 | stazp_work0 |
| $4C5A | a5 03 | ldazp_work1 |
| $4C5C | 69 00 | adc#$00 |
| $4C5E | 85 03 | stazp_work1 |
| $4C60 | ca | dex |
| $4C61 | d0 e2 | bneb_4C45 |
| $4C63 | a9 00 | lda#$00; disable all sprites during screen copy |
| $4C65 | 8d 15 d0 | sta$d015; Sprite display Enable |
| $4C68 | a9 ff | lda#$ff |
| $4C6A | 8d 45 00 | sta@w zp_screen_dirty; mark all rows dirty ($FF) |
| $4C6D | a9 02 | lda#VicIIColors.RED |
| $4C6F | 8d 25 d0 | sta$d025; sprite multicolor 0 = dark red; Sprite Multi-Color Register 0 |
| $4C72 | a9 0f | lda#VicIIColors.LIGHT_GREY |
| $4C74 | 8d 26 d0 | sta$d026; sprite multicolor 1 = light gray; Sprite Multi-Color Register 1 |
| $4C77 | a9 06 | lda#VicIIColors.BLUE |
| $4C79 | 8d 7f 00 | sta@w zp_spr_color; set player 1 sprite color = blue |
| $4C7C | a9 07 | lda#VicIIColors.YELLOW |
| $4C7E | 8d 80 00 | sta@w zp_spr_color_p2; set player 2 sprite color = yellow |
| $4C81 | ad a4 3f | ldascreen_slot_status; check if special bg color mode active |
| $4C84 | f0 08 | beqb_4C8E |
| $4C86 | a9 00 | lda#VicIIColors.BLACK; set background color 3 = black |
| $4C88 | 8d 24 d0 | sta$d024; Background Color 3 |
| $4C8B | 20 a4 50 | jsrreset_sprite_colors |
| $4C8E | a2 00 | b_4C8Eldx#$00; x-ref: $4C84 |
| $4C90 | bd 68 e3 | b_4C90ldascreen_buf_q1,x; Copy screen char Q1 to $0400 ; x-ref: $4CC3 |
| $4C93 | 9d 00 04 | staSCREEN_RAM,x |
| $4C96 | bd 10 e6 | ldacolor_buf_q1,x; Copy color Q1 to $D800 |
| $4C99 | 9d 00 d8 | staCOLOR_RAM,x; Copy decompressed color to color RAM (1st quarter) |
| $4C9C | bd 12 e4 | ldascreen_buf_q2,x; Copy screen char Q2 to $04AA |
| $4C9F | 9d aa 04 | staSCREEN_RAM_R4C10,x |
| $4CA2 | bd ba e6 | ldacolor_buf_q2,x; Copy color Q2 to $D8AA |
| $4CA5 | 9d aa d8 | staCOLOR_RAM_R4C10,x; Copy decompressed color (2nd quarter) |
| $4CA8 | bd bc e4 | ldascreen_buf_q3,x; Copy screen char Q3 to $0554 |
| $4CAB | 9d 54 05 | staSCREEN_RAM_R8C20,x |
| $4CAE | bd 64 e7 | ldacolor_buf_q3,x; Copy color Q3 to $D954 |
| $4CB1 | 9d 54 d9 | staCOLOR_RAM_R8C20,x; Copy decompressed color (3rd quarter) |
| $4CB4 | bd 66 e5 | ldascreen_buf_q4,x; Copy screen char Q4 to $05FE |
| $4CB7 | 9d fe 05 | staSCREEN_RAM_R12C30,x |
| $4CBA | bd 0e e8 | ldacolor_buf_q4,x; Copy color Q4 to $D9FE |
| $4CBD | 9d fe d9 | staCOLOR_RAM_R12C30,x; Copy decompressed color (4th quarter) |
| $4CC0 | e8 | inx; loop 170 bytes (one screen quarter) |
| $4CC1 | e0 aa | cpx#$aa |
| $4CC3 | d0 cb | bneb_4C90 |
| $4CC5 | 20 f4 84 | jsrdraw_raft_tiles; init sprite positions and params |
| $4CC8 | 20 4c 86 | jsrdraw_all_dynamic_tiles; init sprite animation state |
| $4CCB | ad a4 3f | ldascreen_slot_status; restore bg color 3 if not special mode |
| $4CCE | d0 06 | bneb_4CD6 |
| $4CD0 | ad a1 3f | ldalevel_color_border; Border/background color 3 for the level |
| $4CD3 | 8d 24 d0 | sta$d024; Background Color 3 |
| $4CD6 | a9 ff | b_4CD6lda#$ff; enable all 8 sprites ($FF) ; x-ref: $4CCE |
| $4CD8 | 8d 15 d0 | sta$d015; Sprite display Enable |
| $4CDB | a9 00 | lda#$00; clear rendering-in-progress flag |
| $4CDD | 8d a7 3f | starendering_in_progress; Clear rendering_in_progress (unlock) |
| $4CE0 | 60 | rts; done |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| ; Decodes one row of RLE-compressed level map data from the source stream |
| ; (zpa_02/03) and writes tile values to the screen buffer (zpa_04/05). |
| ; Handles several command byte ranges: |
| ; $F5 = Clear/init: sets color attributes for row, flags a_3FA6 |
| ; $E4..$F4 = Fill N full rows with tile value $01 (solid) |
| ; $D4..$E3 = Copy a predefined row pattern from the lookup table (f_3FA9/f_3FBA) |
| ; < $D4 = Decode individual tile runs via s_4D75 (RLE sub-decoder) |
| ; Decrements zpa_1E (remaining row counter) for each row consumed. |
| ; |
| ; Inputs: zpa_02/03 = source data pointer, zpa_04/05 = screen dest pointer, |
| ; zpa_1E = remaining rows counter, Y = 0 |
| ; Outputs: zpa_02/03 advanced past consumed bytes, zpa_04/05 advanced by |
| ; row(s), zpa_1E decremented |
| ; Side Effects: Writes tile data to screen buffer at $E0C0+, |
| ; may modify color attributes at f_E318/f_E340 |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| $4CE1 | b1 02 | decode_level_rowlda(zp_work0),y; load command byte from source stream ; x-ref: $4B5C |
| $4CE3 | c9 f5 | cmp#$f5; is it $F5 (clear/init row)? |
| $4CE5 | d0 1f | bneb_4D06; no -> check other commands |
| $4CE7 | a2 27 | ldx#$27; X = 39 (40 columns per row) |
| $4CE9 | bd 18 e3 | b_4CE9ldacolor_attr_row,x; Read color attribute for current column ; x-ref: $4CFB |
| $4CEC | c9 01 | cmp#$01; is it color 1? |
| $4CEE | f0 05 | beqb_4CF5; yes -> remap to color $04 |
| $4CF0 | a9 03 | lda#$03; no -> remap to color $03 |
| $4CF2 | 4c f7 4c | jmpj_4CF7 |
| $4CF5 | a9 04 | b_4CF5lda#$04; x-ref: $4CEE |
| $4CF7 | 9d 40 e3 | j_4CF7stacolor_attr_remapped,x; Write remapped color to attribute buffer ; x-ref: $4CF2 |
| $4CFA | ca | dex |
| $4CFB | 10 ec | bplb_4CE9 |
| $4CFD | e8 | inx; X = 0 after loop |
| $4CFE | 86 1e | stxzp_temp_x; clear remaining rows counter |
| $4D00 | a9 ff | lda#$ff; set init flag = $FF |
| $4D02 | 8d a6 3f | stascreen_changed_flag |
| $4D05 | 60 | rts |
| $4D06 | c9 e4 | b_4D06cmp#$e4; cmd >= $E4? (fill N solid rows) ; x-ref: $4CE5 |
| $4D08 | 90 26 | bccb_4D30 |
| $4D0A | e9 e4 | sbc#$e4; X = number of rows to fill - 1 |
| $4D0C | aa | tax |
| $4D0D | a0 27 | b_4D0Dldy#$27; -- fill one row loop -- ; x-ref: $4D27 |
| $4D0F | a9 01 | lda#$01; fill value = $01 (solid tile) |
| $4D11 | 91 04 | b_4D11sta(zp_work2),y; write to 40 screen columns ; x-ref: $4D14 |
| $4D13 | 88 | dey |
| $4D14 | 10 fb | bplb_4D11 |
| $4D16 | c8 | iny |
| $4D17 | a5 04 | ldazp_work2; advance dest ptr by 40 cols ($28) |
| $4D19 | 18 | clc |
| $4D1A | 69 28 | adc#$28 |
| $4D1C | 85 04 | stazp_work2 |
| $4D1E | a5 05 | ldazp_work3 |
| $4D20 | 69 00 | adc#$00 |
| $4D22 | 85 05 | stazp_work3 |
| $4D24 | c6 1e | deczp_temp_x; decrement remaining rows |
| $4D26 | ca | dex; next row to fill |
| $4D27 | 10 e4 | bplb_4D0D |
| $4D29 | e6 02 | inczp_work0; advance source data pointer |
| $4D2B | d0 02 | bner_4D2F |
| $4D2D | e6 03 | inczp_work1 |
| $4D2F | 60 | r_4D2Frts; x-ref: $4D2B |
| $4D30 | c9 d4 | b_4D30cmp#$d4; cmd >= $D4? (copy predefined row pattern) ; x-ref: $4D08 |
| $4D32 | 90 2d | bccb_4D61 |
| $4D34 | e9 d4 | sbc#$d4; X = row pattern index |
| $4D36 | aa | tax |
| $4D37 | bd a9 3f | ldarow_pattern_ptrs_lo,x; Load row pattern pointer lo |
| $4D3A | 85 06 | stazp_ptr_aux1_lo |
| $4D3C | bd ba 3f | ldarow_pattern_ptrs_hi,x; Load row pattern pointer hi |
| $4D3F | 85 07 | stazp_ptr_aux1_hi |
| $4D41 | a0 27 | ldy#$27; Y = 39 (copy 40 bytes) |
| $4D43 | b1 06 | b_4D43lda(zp_ptr_aux1_lo),y; copy row pattern byte to screen ; x-ref: $4D48 |
| $4D45 | 91 04 | sta(zp_work2),y |
| $4D47 | 88 | dey |
| $4D48 | 10 f9 | bplb_4D43 |
| $4D4A | c8 | iny |
| $4D4B | a5 04 | ldazp_work2; advance dest ptr by 40 cols ($28) |
| $4D4D | 18 | clc |
| $4D4E | 69 28 | adc#$28 |
| $4D50 | 85 04 | stazp_work2 |
| $4D52 | a5 05 | ldazp_work3 |
| $4D54 | 69 00 | adc#$00 |
| $4D56 | 85 05 | stazp_work3 |
| $4D58 | c6 1e | deczp_temp_x; decrement remaining rows |
| $4D5A | e6 02 | inczp_work0; advance source data pointer |
| $4D5C | d0 02 | bner_4D60 |
| $4D5E | e6 03 | inczp_work1 |
| $4D60 | 60 | r_4D60rts; x-ref: $4D5C |
| $4D61 | a9 28 | b_4D61lda#$28; default: decode tile runs within row ; x-ref: $4D32 |
| $4D63 | 85 1f | stazp_temp_y; zpa_1F = 40 columns remaining in row |
| $4D65 | 20 75 4d | b_4D65jsrdecode_rle_byte; decode next tile run via s_4D75 ; x-ref: $4D70 |
| $4D68 | e6 02 | inczp_work0; advance source data pointer |
| $4D6A | d0 02 | bneb_4D6E |
| $4D6C | e6 03 | inczp_work1 |
| $4D6E | a5 1f | b_4D6Eldazp_temp_y; x-ref: $4D6A |
| $4D70 | d0 f3 | bneb_4D65 |
| $4D72 | c6 1e | deczp_temp_x; decrement remaining rows |
| $4D74 | 60 | rts |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| ; Decodes a single RLE-compressed byte from the source stream and writes |
| ; the expanded output to the destination buffer. |
| ; |
| ; Encoding scheme (value ranges of the compressed byte): |
| ; $00-$27: Write $00 repeated (value+1) times |
| ; $28-$4F: Write $01 repeated (value-$27) times |
| ; $50-$77: Write $02 repeated (value-$4F) times |
| ; $78-$9F: Write $00 (value-$77) times, then fill rest with $01 |
| ; $A0-$C7: Write $00 (value-$9F) times, then fill rest with $02 |
| ; $C8+: Write literal (value-$C3) once |
| ; |
| ; Inputs: (zpa_02),Y = source data pointer, (zpa_04),Y = dest pointer, |
| ; zpa_1F = remaining columns in row |
| ; Outputs: Destination buffer filled, zpa_04/05 advanced, zpa_1F decremented |
| ; Side Effects: None |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| $4D75 | b1 02 | decode_rle_bytelda(zp_work0),y; Read compressed byte from source ; x-ref: $4D65 |
| $4D77 | c9 28 | cmp#$28; < $28? Range $00-$27: fill with $00 |
| $4D79 | b0 11 | bcsb_4D8C |
| $4D7B | aa | tax; Count = value + 1 |
| $4D7C | a9 00 | lda#$00; Fill value = $00 |
| $4D7E | 91 04 | b_4D7Esta(zp_work2),y; Write fill value to dest ; x-ref: $4D89 |
| $4D80 | e6 04 | inczp_work2; Advance dest pointer (lo) |
| $4D82 | d0 02 | bneb_4D86 |
| $4D84 | e6 05 | inczp_work3; Advance dest pointer (hi) |
| $4D86 | c6 1f | b_4D86deczp_temp_y; Decrement remaining columns ; x-ref: $4D82 |
| $4D88 | ca | dex |
| $4D89 | 10 f3 | bplb_4D7E |
| $4D8B | 60 | rts |
| $4D8C | c9 50 | b_4D8Ccmp#$50; < $50? Range $28-$4F: fill with $01 ; x-ref: $4D79 |
| $4D8E | b0 13 | bcsb_4DA3 |
| $4D90 | e9 27 | sbc#$27; Count = value - $27 (carry clear) |
| $4D92 | aa | tax |
| $4D93 | a9 01 | lda#$01; Fill value = $01 |
| $4D95 | 91 04 | b_4D95sta(zp_work2),y; Write fill value to dest ; x-ref: $4DA0 |
| $4D97 | e6 04 | inczp_work2 |
| $4D99 | d0 02 | bneb_4D9D |
| $4D9B | e6 05 | inczp_work3 |
| $4D9D | c6 1f | b_4D9Ddeczp_temp_y; x-ref: $4D99 |
| $4D9F | ca | dex |
| $4DA0 | 10 f3 | bplb_4D95 |
| $4DA2 | 60 | rts |
| $4DA3 | c9 78 | b_4DA3cmp#$78; < $78? Range $50-$77: fill with $02 ; x-ref: $4D8E |
| $4DA5 | b0 13 | bcsb_4DBA |
| $4DA7 | e9 4f | sbc#$4f; Count = value - $4F (carry clear) |
| $4DA9 | aa | tax |
| $4DAA | a9 02 | lda#$02; Fill value = $02 |
| $4DAC | 91 04 | b_4DACsta(zp_work2),y; x-ref: $4DB7 |
| $4DAE | e6 04 | inczp_work2 |
| $4DB0 | d0 02 | bneb_4DB4 |
| $4DB2 | e6 05 | inczp_work3 |
| $4DB4 | c6 1f | b_4DB4deczp_temp_y; x-ref: $4DB0 |
| $4DB6 | ca | dex |
| $4DB7 | 10 f3 | bplb_4DAC |
| $4DB9 | 60 | rts |
| $4DBA | c9 a0 | b_4DBAcmp#$a0; < $A0? Range $78-$9F: $00 then $01 ; x-ref: $4DA5 |
| $4DBC | b0 24 | bcsb_4DE2 |
| $4DBE | e9 77 | sbc#$77; Count of $00s = value - $77 (carry clear) |
| $4DC0 | aa | tax |
| $4DC1 | a9 00 | lda#$00; First fill value = $00 |
| $4DC3 | 91 04 | b_4DC3sta(zp_work2),y; x-ref: $4DCE |
| $4DC5 | e6 04 | inczp_work2 |
| $4DC7 | d0 02 | bneb_4DCB |
| $4DC9 | e6 05 | inczp_work3 |
| $4DCB | c6 1f | b_4DCBdeczp_temp_y; x-ref: $4DC7 |
| $4DCD | ca | dex |
| $4DCE | 10 f3 | bplb_4DC3 |
| $4DD0 | a6 1f | ldxzp_temp_y; Remaining cols for second fill |
| $4DD2 | a9 01 | lda#$01; Second fill value = $01 |
| $4DD4 | 91 04 | b_4DD4sta(zp_work2),y; x-ref: $4DDD |
| $4DD6 | e6 04 | inczp_work2 |
| $4DD8 | d0 02 | bneb_4DDC |
| $4DDA | e6 05 | inczp_work3 |
| $4DDC | ca | b_4DDCdex; x-ref: $4DD8 |
| $4DDD | d0 f5 | bneb_4DD4 |
| $4DDF | 86 1f | stxzp_temp_y; Clear remaining columns (done) |
| $4DE1 | 60 | rts |
| $4DE2 | c9 c8 | b_4DE2cmp#$c8; < $C8? Range $A0-$C7: $00 then $02 ; x-ref: $4DBC |
| $4DE4 | b0 24 | bcsb_4E0A |
| $4DE6 | e9 9f | sbc#$9f; Count of $00s = value - $9F (carry clear) |
| $4DE8 | aa | tax |
| $4DE9 | a9 00 | lda#$00; First fill value = $00 |
| $4DEB | 91 04 | b_4DEBsta(zp_work2),y; x-ref: $4DF6 |
| $4DED | e6 04 | inczp_work2 |
| $4DEF | d0 02 | bneb_4DF3 |
| $4DF1 | e6 05 | inczp_work3 |
| $4DF3 | c6 1f | b_4DF3deczp_temp_y; x-ref: $4DEF |
| $4DF5 | ca | dex |
| $4DF6 | 10 f3 | bplb_4DEB |
| $4DF8 | a6 1f | ldxzp_temp_y; Remaining cols for second fill |
| $4DFA | a9 02 | lda#$02; Second fill value = $02 |
| $4DFC | 91 04 | b_4DFCsta(zp_work2),y; x-ref: $4E05 |
| $4DFE | e6 04 | inczp_work2 |
| $4E00 | d0 02 | bneb_4E04 |
| $4E02 | e6 05 | inczp_work3 |
| $4E04 | ca | b_4E04dex; x-ref: $4E00 |
| $4E05 | d0 f5 | bneb_4DFC |
| $4E07 | 86 1f | stxzp_temp_y; Clear remaining columns (done) |
| $4E09 | 60 | rts |
| $4E0A | e9 c3 | b_4E0Asbc#$c3; Range $C8+: literal value - $C3 ; x-ref: $4DE4 |
| $4E0C | 91 04 | sta(zp_work2),y; Write literal to dest |
| $4E0E | e6 04 | inczp_work2 |
| $4E10 | d0 02 | bneb_4E14 |
| $4E12 | e6 05 | inczp_work3 |
| $4E14 | c6 1f | b_4E14deczp_temp_y; Decrement remaining columns ; x-ref: $4E10 |
| $4E16 | 60 | rts |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| ; Fills the screen color buffer based on the current screen index. |
| ; If the screen slot in f_EF78 is empty (zero), fills the entire playfield |
| ; color buffer with the top/bottom color values from a_3F9F/a_3FA0. |
| ; If the slot is non-empty, fills only the first and last rows with color, |
| ; and clears the middle portion of the buffer. |
| ; |
| ; Inputs: a_3F9E (screen index), a_3F9F (top color), a_3FA0 (bottom color), a_3FA1 (border color) |
| ; Outputs: a_3FA3, a_3FA4, a_85E5 (updated as side effects) |
| ; Side Effects: Fills color buffer at $E610-$E88F |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| $4E17 | ae 9e 3f | fill_screen_colorsldxcurrent_room_index; Look up screen data using room index ; x-ref: $4B63 |
| $4E1A | bd 78 ef | ldascreen_slot_table,x; Load slot status for current room (0=empty, $FF=occupied) |
| $4E1D | 8d a4 3f | stascreen_slot_status; Store slot status |
| $4E20 | d0 2c | bneb_4E4E; Branch if slot is occupied |
| $4E22 | ad a1 3f | ldalevel_color_border; --- Empty slot: full fill ---; Border/background color 3 for the level |
| $4E25 | 8d a3 3f | staactive_bg_color; Copy border color to a_3FA3 |
| $4E28 | a9 0f | lda#VicIIColors.LIGHT_GREY; light gray |
| $4E2A | 8d e5 85 | stadtile_color; Set tile color |
| $4E2D | a2 00 | ldx#$00 |
| $4E2F | ad 9f 3f | ldalevel_color_top; A = top color value |
| $4E32 | 9d 10 e6 | b_4E32stacolor_buf_q1,x; Fill color buf Q1 (256 bytes) with top color ; x-ref: $4E36 |
| $4E35 | e8 | inx |
| $4E36 | d0 fa | bneb_4E32 |
| $4E38 | 9d 10 e7 | b_4E38stacolor_buf_0x100,x; Fill color buf mid (184 bytes) with top color ; x-ref: $4E3E |
| $4E3B | e8 | inx |
| $4E3C | e0 b8 | cpx#$b8 |
| $4E3E | d0 f8 | bneb_4E38 |
| $4E40 | a2 00 | ldx#$00 |
| $4E42 | ad a0 3f | ldalevel_color_bottom; A = bottom color value; Color value for the bottom section of the playfield |
| $4E45 | 9d c8 e7 | b_4E45stacolor_buf_0x1b8,x; Fill color buf bottom (240 bytes) with bottom color ; x-ref: $4E4B |
| $4E48 | e8 | inx |
| $4E49 | e0 f0 | cpx#$f0 |
| $4E4B | d0 f8 | bneb_4E45 |
| $4E4D | 60 | rts |
| $4E4E | a2 27 | b_4E4Eldx#$27; --- Occupied slot: partial fill --- ; x-ref: $4E20 |
| $4E50 | ad 9f 3f | b_4E50ldalevel_color_top; Fill first 40 cols with top color ; x-ref: $4E5D |
| $4E53 | 9d 10 e6 | stacolor_buf_q1,x; Fill first 40 cols with top color (occupied slot) |
| $4E56 | ad a0 3f | ldalevel_color_bottom; Fill last 40 cols with bottom color; Color value for the bottom section of the playfield |
| $4E59 | 9d 90 e8 | stacolor_buf_last_row,x; Fill last 40 cols with bottom color (occupied slot) |
| $4E5C | ca | dex |
| $4E5D | 10 f1 | bplb_4E50 |
| $4E5F | e8 | inx |
| $4E60 | a9 00 | lda#VicIIColors.BLACK |
| $4E62 | 8d a3 3f | staactive_bg_color; Clear a_3FA3 |
| $4E65 | 8d e5 85 | stadtile_color; Clear tile color |
| $4E68 | 9d 38 e6 | b_4E68stacolor_buf_0x28,x; Clear mid-screen color buf (256 bytes) ; x-ref: $4E6F |
| $4E6B | 9d 38 e7 | stacolor_buf_mid_clear,x; Clear mid-screen color buf cont. (256 bytes) |
| $4E6E | e8 | inx |
| $4E6F | d0 f7 | bneb_4E68 |
| $4E71 | 9d 38 e8 | b_4E71stacolor_buf_0x228,x; Clear bottom color buf (88 bytes) ; x-ref: $4E77 |
| $4E74 | e8 | inx |
| $4E75 | e0 58 | cpx#$58 |
| $4E77 | d0 f8 | bneb_4E71 |
| $4E79 | 60 | rts |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| ; Selects and draws the correct wall tile at the current screen position |
| ; based on neighboring cells. Builds a 4-bit adjacency mask by sampling |
| ; four diagonal neighbors (above-left, above-right, below-left, below-right) |
| ; and uses the mask to pick the appropriate edge/corner/join tile from |
| ; lookup tables. Also draws background or wall decoration tiles into |
| ; adjacent rows when the top or bottom neighbor is absent. |
| ; |
| ; Inputs: zpa_02/03 = pointer to current screen row, X = tile index, Y = column offset |
| ; Outputs: Tile written to screen via (zpa_02),Y; Y may be adjusted |
| ; Side Effects: Writes to screen memory, modifies color RAM via a_3FA3 |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| $4E7A | 86 fd | draw_wall_autotilestxzp_ptr_dst_lo; Save tile index and column ; x-ref: $4C4D |
| $4E7C | 84 fe | styzp_ptr_dst_hi |
| $4E7E | a5 02 | ldazp_work0; Compute ptr to row above: (zpa_02) - 40 |
| $4E80 | 38 | sec |
| $4E81 | e9 28 | sbc#$28 |
| $4E83 | 85 fb | stazp_ptr_src_lo; Store row-above pointer in a_00FB/FC |
| $4E85 | a5 03 | ldazp_work1 |
| $4E87 | e9 00 | sbc#$00 |
| $4E89 | 85 fc | stazp_ptr_src_hi |
| $4E8B | a2 00 | ldx#$00; Init neighbor mask = 0 |
| $4E8D | b1 fb | lda(zp_ptr_src_lo),y; Read cell above-left |
| $4E8F | c9 0d | cmp#$0d; Is it a wall tile (>= $0D)? |
| $4E91 | 90 02 | bccb_4E95 |
| $4E93 | a2 08 | ldx#$08; Set bit 3: above-left is wall |
| $4E95 | 98 | b_4E95tya; Y += 39 to reach above-right cell ; x-ref: $4E91 |
| $4E96 | 18 | clc |
| $4E97 | 69 27 | adc#$27 |
| $4E99 | a8 | tay |
| $4E9A | b1 fb | lda(zp_ptr_src_lo),y; Read cell above-right |
| $4E9C | c9 0d | cmp#$0d |
| $4E9E | 90 04 | bccb_4EA4; Set bit 2: above-right is wall |
| $4EA0 | 8a | txa |
| $4EA1 | 09 04 | ora#$04 |
| $4EA3 | aa | tax |
| $4EA4 | c8 | b_4EA4iny; Y += 2 to reach below-left cell ; x-ref: $4E9E |
| $4EA5 | c8 | iny |
| $4EA6 | b1 fb | lda(zp_ptr_src_lo),y; Read cell below-left |
| $4EA8 | c9 0d | cmp#$0d |
| $4EAA | 90 04 | bccb_4EB0; Set bit 1: below-left is wall |
| $4EAC | 8a | txa |
| $4EAD | 09 02 | ora#$02 |
| $4EAF | aa | tax |
| $4EB0 | 98 | b_4EB0tya; Y += 39 to reach below-right cell ; x-ref: $4EAA |
| $4EB1 | 18 | clc |
| $4EB2 | 69 27 | adc#$27 |
| $4EB4 | a8 | tay |
| $4EB5 | b1 fb | lda(zp_ptr_src_lo),y; Read cell below-right |
| $4EB7 | c9 0d | cmp#$0d |
| $4EB9 | 90 01 | bccb_4EBC; Set bit 0: below-right is wall |
| $4EBB | e8 | inx |
| $4EBC | 86 ff | b_4EBCstxzp_temp; Store completed 4-bit neighbor mask ; x-ref: $4EB9 |
| $4EBE | a6 fd | ldxzp_ptr_dst_lo; Restore tile index and column |
| $4EC0 | a4 fe | ldyzp_ptr_dst_hi |
| $4EC2 | c0 00 | cpy#$00; Skip if at left edge (col 0) |
| $4EC4 | f0 54 | beqb_4F1A |
| $4EC6 | c0 27 | cpy#$27; Skip if at right edge (col 39) |
| $4EC8 | f0 50 | beqb_4F1A |
| $4ECA | b1 02 | lda(zp_work0),y; Read current cell value |
| $4ECC | c9 1a | cmp#$1a |
| $4ECE | 90 4a | bccb_4F1A; Skip if cell < $1A (not a processable wall) |
| $4ED0 | a5 ff | ldazp_temp; Test bits 2-3 (above neighbors) |
| $4ED2 | 29 0c | and#$0c |
| $4ED4 | d0 07 | bneb_4EDD |
| $4ED6 | a9 2c | lda#$2c; No above neighbors: horizontal edge tile $2C |
| $4ED8 | 91 02 | sta(zp_work0),y; Write tile and adjust Y left by 2 |
| $4EDA | 88 | dey |
| $4EDB | 88 | dey |
| $4EDC | 60 | rts |
| $4EDD | a5 ff | b_4EDDldazp_temp; Test bits 1,3 (left-side neighbors) ; x-ref: $4ED4 |
| $4EDF | 29 0a | and#$0a |
| $4EE1 | d0 05 | bneb_4EE8 |
| $4EE3 | a9 2d | lda#$2d; Left-only neighbors: vertical edge tile $2D |
| $4EE5 | 91 02 | sta(zp_work0),y |
| $4EE7 | 60 | rts |
| $4EE8 | a5 ff | b_4EE8ldazp_temp; Test bits 0,2 (right-side neighbors) ; x-ref: $4EE1 |
| $4EEA | 29 05 | and#$05 |
| $4EEC | d0 07 | bneb_4EF5 |
| $4EEE | a9 2e | lda#$2e; Right-only neighbors: vertical edge tile $2E |
| $4EF0 | 91 02 | sta(zp_work0),y |
| $4EF2 | 88 | dey |
| $4EF3 | 88 | dey; Test bits 0-1 (below neighbors) |
| $4EF4 | 60 | rts |
| $4EF5 | a5 ff | b_4EF5ldazp_temp; x-ref: $4EEC |
| $4EF7 | 29 03 | and#$03 |
| $4EF9 | d0 05 | bneb_4F00 |
| $4EFB | a9 2f | lda#$2f; Bottom-only: use inner corner tile from f_48DA,X |
| $4EFD | 91 02 | sta(zp_work0),y |
| $4EFF | 60 | rts |
| $4F00 | a5 ff | b_4F00ldazp_temp; x-ref: $4EF9 |
| $4F02 | 29 04 | and#$04 |
| $4F04 | d0 08 | bneb_4F0E |
| $4F06 | bd da 48 | ldaouter_corner_tiles,x; Load outer corner tile for top-right |
| $4F09 | 91 02 | sta(zp_work0),y |
| $4F0B | 88 | dey |
| $4F0C | 88 | dey |
| $4F0D | 60 | rts |
| $4F0E | a5 ff | b_4F0Eldazp_temp; x-ref: $4F04 |
| $4F10 | 29 02 | and#$02 |
| $4F12 | d0 06 | bneb_4F1A |
| $4F14 | bd e9 48 | ldainner_corner_tiles,x; Load inner corner tile |
| $4F17 | 91 02 | sta(zp_work0),y |
| $4F19 | 60 | rts |
| $4F1A | a5 ff | b_4F1Aldazp_temp; Bit 3 clear: no wall above — draw background above ; x-ref: $4EC4, $4EC8, $4ECE, $4F12 |
| $4F1C | 29 08 | and#$08 |
| $4F1E | d0 47 | bneb_4F67 |
| $4F20 | 84 ff | styzp_temp |
| $4F22 | a5 02 | ldazp_work0; Compute ptr 2 rows above current row |
| $4F24 | 38 | sec |
| $4F25 | e9 50 | sbc#$50 |
| $4F27 | 85 fb | stazp_ptr_src_lo |
| $4F29 | a5 03 | ldazp_work1 |
| $4F2B | e9 00 | sbc#$00 |
| $4F2D | 85 fc | stazp_ptr_src_hi |
| $4F2F | a5 fb | ldazp_ptr_src_lo |
| $4F31 | 18 | clc |
| $4F32 | 69 a8 | adc#$a8; Compute color RAM ptr (+$02A8 offset) |
| $4F34 | 85 fd | stazp_ptr_dst_lo |
| $4F36 | a5 fc | ldazp_ptr_src_hi |
| $4F38 | 69 02 | adc#$02 |
| $4F3A | 85 fe | stazp_ptr_dst_hi |
| $4F3C | b9 c3 47 | ldabg_tile_table,y; Fill background tile from ceiling table |
| $4F3F | 91 fb | sta(zp_ptr_src_lo),y |
| $4F41 | ad a3 3f | ldaactive_bg_color; Set color from a_3FA3 |
| $4F44 | 91 fd | sta(zp_ptr_dst_lo),y |
| $4F46 | 98 | tya |
| $4F47 | 18 | clc |
| $4F48 | 69 28 | adc#$28; Advance Y by 40 to next row |
| $4F4A | a8 | tay |
| $4F4B | b9 c3 47 | ldabg_tile_table,y; Draw background tile in row above |
| $4F4E | 91 fb | sta(zp_ptr_src_lo),y |
| $4F50 | ad a3 3f | ldaactive_bg_color |
| $4F53 | 91 fd | sta(zp_ptr_dst_lo),y |
| $4F55 | 98 | tya |
| $4F56 | 69 28 | adc#$28 |
| $4F58 | a8 | tay |
| $4F59 | b1 fb | lda(zp_ptr_src_lo),y; Check if 3rd row above has wall tile |
| $4F5B | c9 1a | cmp#$1a |
| $4F5D | 90 05 | bccb_4F64 |
| $4F5F | b9 c3 47 | ldabg_tile_table,y; If not wall, also draw background there |
| $4F62 | 91 fb | sta(zp_ptr_src_lo),y |
| $4F64 | a4 ff | b_4F64ldyzp_temp; x-ref: $4F5D |
| $4F66 | 60 | rts |
| $4F67 | a5 ff | b_4F67ldazp_temp; Bit 0 clear: no wall below — draw wall below ; x-ref: $4F1E |
| $4F69 | 29 01 | and#$01 |
| $4F6B | d0 47 | bner_4FB4 |
| $4F6D | 84 ff | styzp_temp |
| $4F6F | a5 02 | ldazp_work0; Compute color RAM ptr for rows below |
| $4F71 | 18 | clc |
| $4F72 | 69 a8 | adc#$a8 |
| $4F74 | 85 fd | stazp_ptr_dst_lo |
| $4F76 | a5 03 | ldazp_work1 |
| $4F78 | 69 02 | adc#$02 |
| $4F7A | 85 fe | stazp_ptr_dst_hi |
| $4F7C | b1 02 | lda(zp_work0),y; Check if current cell is wall (>= $1A) |
| $4F7E | c9 1a | cmp#$1a |
| $4F80 | 90 05 | bccb_4F87 |
| $4F82 | b9 3b 48 | ldawall_tile_table,y; Draw wall decoration tile below edge |
| $4F85 | 91 02 | sta(zp_work0),y |
| $4F87 | 98 | b_4F87tya; Advance to next row (+40) ; x-ref: $4F80 |
| $4F88 | 18 | clc |
| $4F89 | 69 28 | adc#$28 |
| $4F8B | a8 | tay |
| $4F8C | b9 3b 48 | ldawall_tile_table,y; Draw wall tile in 2nd row below |
| $4F8F | 91 02 | sta(zp_work0),y |
| $4F91 | ad a3 3f | ldaactive_bg_color; Set color for row below |
| $4F94 | 91 fd | sta(zp_ptr_dst_lo),y |
| $4F96 | 98 | tya |
| $4F97 | 69 28 | adc#$28 |
| $4F99 | a8 | tay |
| $4F9A | b9 3b 48 | ldawall_tile_table,y; Draw wall tile in 3rd row below |
| $4F9D | 91 02 | sta(zp_work0),y |
| $4F9F | ad a3 3f | ldaactive_bg_color |
| $4FA2 | 91 fd | sta(zp_ptr_dst_lo),y |
| $4FA4 | 98 | tya |
| $4FA5 | 69 28 | adc#$28 |
| $4FA7 | a8 | tay |
| $4FA8 | b9 3b 48 | ldawall_tile_table,y; Draw wall tile in 4th row below |
| $4FAB | 91 02 | sta(zp_work0),y |
| $4FAD | ad a3 3f | ldaactive_bg_color |
| $4FB0 | 91 fd | sta(zp_ptr_dst_lo),y |
| $4FB2 | a4 ff | ldyzp_temp; Restore column offset and return |
| $4FB4 | 60 | r_4FB4rts; x-ref: $4F6B |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| ; Dispatches complex tile types (ID >= 5) to their rendering handlers. |
| ; Subtracts 5 from the tile ID and branches to the appropriate handler: |
| ; 0 (tile 5) -> j_85EC with A=0 |
| ; 1 (tile 6) -> j_85EC with A=1 |
| ; 7 (tile 12) -> j_77CC |
| ; 8 (tile 13) -> j_82B6 |
| ; 9 (tile 14) -> j_7A7E |
| ; 10 (tile 15) -> j_8481 |
| ; 11 (tile 16) -> j_7B1B (only if a_3FA5 != 0) |
| ; others -> j_7213 (with adjusted tile ID) |
| ; |
| ; Inputs: A = tile ID (>= 5), X/Y = position context |
| ; Outputs: None (tail-calls into specific handlers) |
| ; Side Effects: Jumps to tile-specific rendering routines |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| dispatch_complex_tile |
| $4FB5 | 38 | sec; normalize tile ID: subtract 5 ; x-ref: $4BA2 |
| $4FB6 | e9 05 | sbc#$05 |
| $4FB8 | d0 05 | bneb_4FBF; result 0 → tile 5 |
| $4FBA | a9 00 | lda#$00; handler param A=0 for tile 5 |
| $4FBC | 4c ec 85 | jmpj_85EC; dispatch tile 5 handler |
| $4FBF | c9 01 | b_4FBFcmp#$01; result 1 → tile 6 ; x-ref: $4FB8 |
| $4FC1 | d0 05 | bneb_4FC8 |
| $4FC3 | a9 01 | lda#$01; handler param A=1 for tile 6 |
| $4FC5 | 4c ec 85 | jmpj_85EC; dispatch tile 6 handler |
| $4FC8 | c9 07 | b_4FC8cmp#$07; result 7 → tile 12 ; x-ref: $4FC1 |
| $4FCA | d0 03 | bneb_4FCF |
| $4FCC | 4c cc 77 | jmpsetup_hazard_position; dispatch tile 12 handler |
| $4FCF | c9 08 | b_4FCFcmp#$08; result 8 → tile 13 ; x-ref: $4FCA |
| $4FD1 | d0 03 | bneb_4FD6 |
| $4FD3 | 4c b6 82 | jmpinit_tile13_scroll; dispatch tile 13 handler |
| $4FD6 | c9 09 | b_4FD6cmp#$09; result 9 → tile 14 ; x-ref: $4FD1 |
| $4FD8 | d0 03 | bneb_4FDD |
| $4FDA | 4c 7e 7a | jmpinit_tile14_params; dispatch tile 14 handler |
| $4FDD | c9 0a | b_4FDDcmp#$0a; result 10 → tile 15 ; x-ref: $4FD8 |
| $4FDF | d0 03 | bneb_4FE4 |
| $4FE1 | 4c 81 84 | jmpinit_tile15_anim; dispatch tile 15 handler |
| $4FE4 | c9 0b | b_4FE4cmp#$0b; result 11 → tile 16 ; x-ref: $4FDF |
| $4FE6 | d0 09 | bneb_4FF1 |
| $4FE8 | ad a5 3f | ldamap_decompressing; check if tile 16 handler enabled |
| $4FEB | f0 03 | beqr_4FF0; skip if flag is zero |
| $4FED | 4c 1b 7b | jmpinit_hero_entity; dispatch tile 16 handler |
| $4FF0 | 60 | r_4FF0rts; tile 16 disabled: return ; x-ref: $4FEB |
| $4FF1 | 38 | b_4FF1sec; all other tiles: subtract 2 more ; x-ref: $4FE6 |
| $4FF2 | e9 02 | sbc#$02 |
| $4FF4 | 4c 13 72 | jmpj_7213; dispatch generic animated tile handler |
| $4FF7 | 48 | j_4FF7pha; x-ref: $7DFF, $7E21, $7EC6, $7ED0 |
| $4FF8 | ad 01 6f | ldaexplosion_state |
| $4FFB | c9 01 | cmp#$01 |
| $4FFD | d0 06 | bneb_5005 |
| $4FFF | 20 87 6f | jsrinit_explosion |
| $5002 | 4c 09 50 | jmpj_5009 |
| $5005 | c9 02 | b_5005cmp#$02; x-ref: $4FFD |
| $5007 | d0 03 | bneb_500C |
| $5009 | 20 a2 6f | j_5009jsrcheck_entity_explosion_hit; x-ref: $5002 |
| $500C | 68 | b_500Cpla; x-ref: $5007 |
| $500D | c9 01 | cmp#$01 |
| $500F | d0 0d | bneb_501E |
| $5011 | ad 9e 3f | ldacurrent_room_index |
| $5014 | 29 07 | and#$07 |
| $5016 | f0 3d | beqr_5055 |
| $5018 | ce 9e 3f | deccurrent_room_index |
| $501B | 4c f0 4a | jmprender_level_screen |
| $501E | c9 02 | b_501Ecmp#$02; x-ref: $500F |
| $5020 | d0 0f | bneb_5031 |
| $5022 | ad 9e 3f | ldacurrent_room_index |
| $5025 | 29 07 | and#$07 |
| $5027 | c9 07 | cmp#$07 |
| $5029 | f0 2a | beqr_5055 |
| $502B | ee 9e 3f | inccurrent_room_index |
| $502E | 4c f0 4a | jmprender_level_screen |
| $5031 | c9 03 | b_5031cmp#$03; x-ref: $5020 |
| $5033 | d0 10 | bneb_5045 |
| $5035 | ad 9e 3f | ldacurrent_room_index |
| $5038 | c9 08 | cmp#$08 |
| $503A | 90 19 | bccr_5055 |
| $503C | 38 | sec |
| $503D | e9 08 | sbc#$08 |
| $503F | 8d 9e 3f | stacurrent_room_index |
| $5042 | 4c f0 4a | jmprender_level_screen |
| $5045 | ad 9e 3f | b_5045ldacurrent_room_index; x-ref: $5033 |
| $5048 | c9 58 | cmp#$58 |
| $504A | b0 09 | bcsr_5055 |
| $504C | 18 | clc |
| $504D | 69 08 | adc#$08 |
| $504F | 8d 9e 3f | stacurrent_room_index |
| $5052 | 4c f0 4a | jmprender_level_screen |
| $5055 | 60 | r_5055rts; x-ref: $5016, $5029, $503A, $504A |
| $5056 | a9 ff | j_5056lda#$ff; x-ref: $1EC7, $1ED2, $1F12, $1F1D |
| $5058 | 8d a4 3f | stascreen_slot_status |
| $505B | ae 9e 3f | ldxcurrent_room_index |
| $505E | 9d 78 ef | stascreen_slot_table,x; Mark current room slot as occupied ($FF) |
| $5061 | a9 00 | lda#VicIIColors.BLACK |
| $5063 | 8d a3 3f | staactive_bg_color |
| $5066 | 20 a4 50 | jsrreset_sprite_colors |
| $5069 | ad a3 3f | j_5069ldaactive_bg_color; x-ref: $50C6 |
| $506C | 8d 24 d0 | sta$d024; Background Color 3 |
| $506F | a2 00 | ldx#$00 |
| $5071 | bd 28 d8 | b_5071ldaCOLOR_RAM_R1C0,x; Read color RAM row 1 for color filter ; x-ref: $50A1 |
| $5074 | 29 0f | and#$0f |
| $5076 | c9 02 | cmp#$02 |
| $5078 | f0 06 | beqb_5080 |
| $507A | ad a3 3f | ldaactive_bg_color |
| $507D | 9d 28 d8 | staCOLOR_RAM_R1C0,x; Overwrite non-red colors in row 1 |
| $5080 | bd f0 d8 | b_5080ldaCOLOR_RAM_R6C0,x; Read color RAM row 6 for color filter ; x-ref: $5078 |
| $5083 | 29 0f | and#$0f |
| $5085 | c9 02 | cmp#$02 |
| $5087 | f0 06 | beqb_508F |
| $5089 | ad a3 3f | ldaactive_bg_color |
| $508C | 9d f0 d8 | staCOLOR_RAM_R6C0,x; Overwrite non-red colors in row 6 |
| $508F | bd b8 d9 | b_508FldaCOLOR_RAM_R11C0,x; Read color RAM row 11 for color filter ; x-ref: $5087 |
| $5092 | 29 0f | and#$0f |
| $5094 | c9 02 | cmp#$02 |
| $5096 | f0 06 | beqb_509E |
| $5098 | ad a3 3f | ldaactive_bg_color |
| $509B | 9d b8 d9 | staCOLOR_RAM_R11C0,x; Overwrite non-red colors in row 11 |
| $509E | e8 | b_509Einx; x-ref: $5096 |
| $509F | e0 c8 | cpx#$c8 |
| $50A1 | d0 ce | bneb_5071 |
| $50A3 | 60 | rts |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| ; Resets all sprite colors to dark gray (#$0B). |
| ; Sets both VIC-II sprite multicolor registers, individual sprite color |
| ; variables ($7F, $80, $91), and the 15-entry sprite color table at $710E |
| ; to a uniform value, effectively neutralizing sprite colors. |
| ; |
| ; Inputs: None |
| ; Outputs: None |
| ; Side Effects: VIC-II $D025/$D026 set to #$0B; ZP $7F/$80/$91 and |
| ; f_710E[0..14] filled with #$0B |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| $50A4 | a9 0b | reset_sprite_colorslda#VicIIColors.DARK_GREY; dark gray ; x-ref: $4C8B, $5066 |
| $50A6 | 8d 25 d0 | sta$d025; sprite multicolor 0 = dark gray; Sprite Multi-Color Register 0 |
| $50A9 | 8d 26 d0 | sta$d026; sprite multicolor 1 = dark gray; Sprite Multi-Color Register 1 |
| $50AC | 8d 7f 00 | sta@w zp_spr_color; player 1 sprite color = dark gray |
| $50AF | 8d 80 00 | sta@w zp_spr_color_p2; player 2 sprite color = dark gray |
| $50B2 | 8d 91 00 | sta@w zp_spr_color_extra; extra sprite color = dark gray |
| $50B5 | a2 0e | ldx#$0e; 15 entries (0..14) |
| $50B7 | 9d 0e 71 | b_50B7staentity_anim_speed,x; fill sprite color table with dark gray ; x-ref: $50BB |
| $50BA | ca | dex |
| $50BB | 10 fa | bplb_50B7; loop until all 15 entries filled |
| $50BD | 60 | rts |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| ; Sets the active screen color and applies it to color RAM and background |
| ; color 3. Only takes effect if the color update flag (a_3FA4) is non-zero, |
| ; indicating an active screen slot. When active, stores the color passed in A |
| ; into a_3FA3, then fills color RAM ($D828+) with that color (skipping cells |
| ; with color 2) and sets VIC-II background color 3 ($D024). |
| ; |
| ; Inputs: A = new color value to apply |
| ; Outputs: a_3FA3 updated with the new color |
| ; Side Effects: Background color 3 ($D024) and color RAM ($D828-$DA7F) updated |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| $50BE | ae a4 3f | set_screen_colorldxscreen_slot_status; Check if color updates are active ; x-ref: $6F43, $7066 |
| $50C1 | f0 06 | beqr_50C9; If flag is zero, skip (no active screen) |
| $50C3 | 8d a3 3f | staactive_bg_color; Store new color value |
| $50C6 | 4c 69 50 | jmpj_5069; Apply color to color RAM and $D024 |
| $50C9 | 60 | r_50C9rts; Nothing to do, return ; x-ref: $50C1 |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| ; Reads a tile value from the level map at the given coordinates. |
| ; A = X-position (column * 8 + sub-column), $FD/$FE = Y-position (16-bit). |
| ; Divides A by 8 to select a row pointer from the map_row_ptr tables, |
| ; then combines remaining bits with $FD/$FE to form a column offset. |
| ; Returns the tile ID in A, or $00 if coordinates are out of bounds. |
| ; |
| ; Inputs: A = x-position, zpa_FD/zpa_FE = y-position (lo/hi) |
| ; Outputs: A = tile ID at the given map position (0 if out of bounds) |
| ; Side Effects: Overwrites $FB/$FC (zero-page pointer) |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| $50CA | c9 88 | get_map_tilecmp#$88; X-pos >= 136? Out of bounds ; x-ref: $74EA, $751D, $7D6E, $7D80, $7D92, ... |
| $50CC | b0 23 | bcsb_50F1; Yes -> return 0 |
| $50CE | a4 fe | ldyzp_ptr_dst_hi; Check Y-pos high byte |
| $50D0 | f0 06 | beqb_50D8; High byte = 0 -> skip Y check |
| $50D2 | a4 fd | ldyzp_ptr_dst_lo; Check Y-pos low byte |
| $50D4 | c0 40 | cpy#$40; Y-pos >= 64? Out of bounds |
| $50D6 | b0 19 | bcsb_50F1; Yes -> return 0 |
| $50D8 | 4a | b_50D8lsra; Divide x-pos by 8 to get row index ; x-ref: $50D0 |
| $50D9 | 4a | lsra |
| $50DA | 4a | lsra |
| $50DB | a8 | tay; Y = row index |
| $50DC | b9 17 8c | ldarow_to_screen_lo,y; Row pointer low byte from table |
| $50DF | 85 fb | stazp_ptr_src_lo; Store in ZP pointer |
| $50E1 | b9 28 8c | ldarow_to_screen_hi,y; Row pointer high byte from table |
| $50E4 | 85 fc | stazp_ptr_src_hi; Store in ZP pointer |
| $50E6 | a5 fd | ldazp_ptr_dst_lo; Compute column offset from Y-pos and sub-bits |
| $50E8 | 46 fe | lsrzp_ptr_dst_hi; Combine FE:FD >> 1 with low bits of A |
| $50EA | 6a | rora |
| $50EB | 4a | lsra |
| $50EC | 4a | lsra |
| $50ED | a8 | tay; Y = column offset into row |
| $50EE | b1 fb | lda(zp_ptr_src_lo),y; Read tile ID from map |
| $50F0 | 60 | rts |
| $50F1 | a9 00 | b_50F1lda#$00; Out-of-bounds: return tile 0 (empty) ; x-ref: $50CC, $50D6 |
| $50F3 | 60 | rts |
| ; Player score low byte (BCD). Part of 3-byte score $50F4-$50F6 (range 000000-999999) |
| $50F4 | | score_lo.byte$00; x-ref: $5101, $513C, $5143, $515D, $5193, ... |
| ; Player score mid byte (BCD). Part of 3-byte score $50F4-$50F6 |
| $50F5 | | score_mid.byte$00; x-ref: $5104, $5146, $514C, $5160, $5189, ... |
| ; Player score high byte (BCD). Part of 3-byte score $50F4-$50F6 |
| $50F6 | | score_hi.byte$00; x-ref: $5107, $514F, $5155, $5163, $517F, ... |
| ; Number of remaining lives/dynamite sticks (0-9). Starts at 4, capped at 9 |
| $50F7 | | lives_count.byte$00; x-ref: $510C, $51BD, $51C8, $51D1, $521A, ... |
| ; Pending score delta low byte (BCD). Added to score on next update_score_and_lives call |
| $50F8 | | score_delta_lo.byte$00; x-ref: $5111, $512F, $5140, $5168, $51D9, ... |
| ; Pending score delta mid byte (BCD) |
| $50F9 | | score_delta_mid.byte$00; x-ref: $5114, $5132, $5149, $516B, $51E2, ... |
| ; Pending score delta high byte (BCD) |
| $50FA | | score_delta_hi.byte$00; x-ref: $5117, $5135, $5152, $516E, $51EA, ... |
| ; Extra-life threshold low byte (BCD). Lives awarded every 20000 pts |
| extra_life_threshold_lo |
| $50FB | | .byte$00; x-ref: $511C, $5190, $519C, $51A2 |
| ; Extra-life threshold mid byte (BCD) |
| extra_life_threshold_mid |
| $50FC | | .byte$00; x-ref: $5121, $5186, $51A5, $51AA |
| ; Extra-life threshold high byte (BCD) |
| extra_life_threshold_hi |
| $50FD | | .byte$00; x-ref: $5126, $517C, $51AD, $51B2 |
| ; $FF = extra lives enabled, $00 = disabled (overflows past 999999 disables) |
| $50FE | | extra_life_enabled.byte$00; x-ref: $512B, $5174, $51BA |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| ; Initializes the player's score, dynamite supply, pending score delta, |
| ; and extra-life threshold for the start of a new game. |
| ; |
| ; Score ($50F4–$50F6) is zeroed (BCD 000000). |
| ; Dynamite supply ($50F7) is set to 4. |
| ; Pending score delta ($50F8–$50FA) is zeroed. |
| ; Extra-life threshold ($50FB–$50FD) is set to 20000 (BCD $00/$00/$02). |
| ; Extra-life enabled flag ($50FE) is set to $FF (enabled). |
| ; |
| ; Inputs: None |
| ; Outputs: None (state stored in $50F4–$50FE) |
| ; Side Effects: Resets all score and life-related game state |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| $50FF | a9 00 | init_score_and_liveslda#$00; Score low byte = 0 (BCD) ; x-ref: $611A |
| $5101 | 8d f4 50 | stascore_lo; Clear score low |
| $5104 | 8d f5 50 | stascore_mid; Clear score mid |
| $5107 | 8d f6 50 | stascore_hi; Clear score high |
| $510A | a9 04 | lda#$04; Start with 4 dynamite sticks |
| $510C | 8d f7 50 | stalives_count; Store dynamite count |
| $510F | a9 00 | lda#$00; Pending score delta = 0 |
| $5111 | 8d f8 50 | stascore_delta_lo; Clear delta low |
| $5114 | 8d f9 50 | stascore_delta_mid; Clear delta mid |
| $5117 | 8d fa 50 | stascore_delta_hi; Clear delta high |
| $511A | a9 00 | lda#$00; Extra-life threshold low = 0 |
| $511C | 8d fb 50 | staextra_life_threshold_lo |
| $511F | a9 00 | lda#$00; Extra-life threshold mid = 0 |
| $5121 | 8d fc 50 | staextra_life_threshold_mid |
| $5124 | a9 02 | lda#$02; Threshold high = $02 → BCD 20000 |
| $5126 | 8d fd 50 | staextra_life_threshold_hi |
| $5129 | a9 ff | lda#$ff; $FF = extra lives enabled |
| $512B | 8d fe 50 | staextra_life_enabled |
| $512E | 60 | rts |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| ; Adds pending score delta to the current score (BCD), clamps at 999999, |
| ; redraws the score display, then awards extra lives for every 20000 points |
| ; (up to a maximum of 9 lives) and redraws the lives display. |
| ; |
| ; Inputs: a_50F8-a_50FA (score delta, 3-byte BCD) |
| ; Outputs: a_50F4-a_50F6 (current score), a_50F7 (lives count) |
| ; Side Effects: Redraws score digits and lives icons on screen |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| update_score_and_lives |
| $512F | ad f8 50 | ldascore_delta_lo; Check if score delta is non-zero ; x-ref: $61D1 |
| $5132 | 0d f9 50 | orascore_delta_mid |
| $5135 | 0d fa 50 | orascore_delta_hi |
| $5138 | d0 01 | bneb_513B |
| $513A | 60 | rts; Return if delta is zero (nothing to add) |
| $513B | f8 | b_513Bsed; Enter BCD mode for decimal addition ; x-ref: $5138 |
| $513C | ad f4 50 | ldascore_lo; Add delta low byte to score low byte |
| $513F | 18 | clc |
| $5140 | 6d f8 50 | adcscore_delta_lo |
| $5143 | 8d f4 50 | stascore_lo; Add delta mid byte to score mid byte |
| $5146 | ad f5 50 | ldascore_mid |
| $5149 | 6d f9 50 | adcscore_delta_mid |
| $514C | 8d f5 50 | stascore_mid |
| $514F | ad f6 50 | ldascore_hi |
| $5152 | 6d fa 50 | adcscore_delta_hi |
| $5155 | 8d f6 50 | stascore_hi |
| $5158 | d8 | cld; Exit BCD mode |
| $5159 | 90 0b | bccb_5166; No overflow? Skip clamping |
| $515B | a9 99 | lda#$99; Clamp score to 999999 (BCD $99 per byte) |
| $515D | 8d f4 50 | stascore_lo |
| $5160 | 8d f5 50 | stascore_mid |
| $5163 | 8d f6 50 | stascore_hi |
| $5166 | a9 00 | b_5166lda#$00; Clear score delta after adding ; x-ref: $5159 |
| $5168 | 8d f8 50 | stascore_delta_lo |
| $516B | 8d f9 50 | stascore_delta_mid |
| $516E | 8d fa 50 | stascore_delta_hi |
| $5171 | 20 f4 51 | jsrdraw_score; Render score digits to screen |
| $5174 | ad fe 50 | ldaextra_life_enabled; Check extra life flag |
| $5177 | d0 01 | bneb_517A; Return if extra lives disabled |
| $5179 | 60 | rts |
| $517A | a2 00 | b_517Aldx#$00; X = number of lives to award ; x-ref: $5177 |
| $517C | ad fd 50 | b_517Cldaextra_life_threshold_hi; Compare threshold hi vs score hi ; x-ref: $51B6 |
| $517F | cd f6 50 | cmpscore_hi |
| $5182 | 90 16 | bccb_519A; Score > threshold → award a life |
| $5184 | d0 37 | bneb_51BD; Score < threshold → done awarding |
| $5186 | ad fc 50 | ldaextra_life_threshold_mid; Compare threshold mid vs score mid |
| $5189 | cd f5 50 | cmpscore_mid |
| $518C | 90 0c | bccb_519A |
| $518E | d0 2d | bneb_51BD |
| $5190 | ad fb 50 | ldaextra_life_threshold_lo; Compare threshold lo vs score lo |
| $5193 | cd f4 50 | cmpscore_lo |
| $5196 | 90 02 | bccb_519A |
| $5198 | d0 23 | bneb_51BD |
| $519A | e8 | b_519Ainx; Score >= threshold: count one extra life ; x-ref: $5182, $518C, $5196 |
| $519B | f8 | sed; Advance threshold by 20000 pts (BCD) |
| $519C | ad fb 50 | ldaextra_life_threshold_lo |
| $519F | 18 | clc |
| $51A0 | 69 00 | adc#$00 |
| $51A2 | 8d fb 50 | staextra_life_threshold_lo |
| $51A5 | ad fc 50 | ldaextra_life_threshold_mid |
| $51A8 | 69 00 | adc#$00 |
| $51AA | 8d fc 50 | staextra_life_threshold_mid |
| $51AD | ad fd 50 | ldaextra_life_threshold_hi |
| $51B0 | 69 02 | adc#$02; Add $02 to threshold high byte (= +20000 BCD) |
| $51B2 | 8d fd 50 | staextra_life_threshold_hi |
| $51B5 | d8 | cld; Exit BCD mode |
| $51B6 | 90 c4 | bccb_517C; No overflow? Loop to check again |
| $51B8 | a9 00 | lda#$00; Overflow: disable further extra lives |
| $51BA | 8d fe 50 | staextra_life_enabled |
| $51BD | ad f7 50 | b_51BDldalives_count; Already at max 9 lives? ; x-ref: $5184, $518E, $5198 |
| $51C0 | c9 09 | cmp#$09; Yes → return, no more lives to add |
| $51C2 | f0 13 | beqr_51D7 |
| $51C4 | 8a | txa; X = 0 means no lives earned this time |
| $51C5 | f0 10 | beqr_51D7; No lives earned → return |
| $51C7 | 18 | clc; Add earned lives to current count |
| $51C8 | 6d f7 50 | adclives_count |
| $51CB | c9 0a | cmp#$0a; Cap lives at 9 |
| $51CD | 90 02 | bccb_51D1 |
| $51CF | a9 09 | lda#$09; Clamp to max 9 lives |
| $51D1 | 8d f7 50 | b_51D1stalives_count; Store updated lives count ; x-ref: $51CD |
| $51D4 | 4c 09 52 | jmpj_5209; Tail-jump: redraw lives display on screen |
| $51D7 | 60 | r_51D7rts; x-ref: $51C2, $51C5 |
| $51D8 | f8 | j_51D8sed; x-ref: $623F, $627A, $7618, $8009, $881B |
| $51D9 | ad f8 50 | ldascore_delta_lo |
| $51DC | 18 | clc |
| $51DD | 65 fb | adczp_ptr_src_lo |
| $51DF | 8d f8 50 | stascore_delta_lo |
| $51E2 | ad f9 50 | ldascore_delta_mid |
| $51E5 | 65 fc | adczp_ptr_src_hi |
| $51E7 | 8d f9 50 | stascore_delta_mid |
| $51EA | ad fa 50 | ldascore_delta_hi |
| $51ED | 65 fd | adczp_ptr_dst_lo |
| $51EF | 8d fa 50 | stascore_delta_hi |
| $51F2 | d8 | cld |
| $51F3 | 60 | rts |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| ; Draws the current score on screen by setting up pointers to the BCD score |
| ; data at $50F4 and the screen destination at $0788, then tail-calling the |
| ; BCD-to-screen rendering routine (j_6432) to display 6 score digits. |
| ; |
| ; Inputs: None (reads BCD score from a_50F4..a_50F6) |
| ; Outputs: Screen memory at $0788 updated with score digits |
| ; Side Effects: Modifies zp pointers $FB/$FC, $FD/$FE, $FF |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| $51F4 | a9 f4 | draw_scorelda#$f4; Source ptr lo = $F4 (-> a_50F4, BCD score data) ; x-ref: $5171, $62F7 |
| $51F6 | 85 fb | stazp_ptr_src_lo |
| $51F8 | a9 50 | lda#$50; Source ptr hi = $50 |
| $51FA | 85 fc | stazp_ptr_src_hi |
| $51FC | a9 88 | lda#$88; Dest ptr lo = $88 (-> $0788, screen score area) |
| $51FE | 85 fd | stazp_ptr_dst_lo |
| $5200 | a9 07 | lda#$07; Dest ptr hi = $07 |
| $5202 | 85 fe | stazp_ptr_dst_hi |
| $5204 | a2 06 | ldx#$06; 6 screen chars for 6-digit score |
| $5206 | 4c 32 64 | jmpj_6432; Tail-call BCD-to-screen renderer |
| $5209 | a2 0e | j_5209ldx#$0e; x-ref: $51D4, $617C, $62CF |
| $520B | a9 20 | lda#$20 |
| $520D | 9d fc 06 | b_520DstaSCREEN_RAM_R19C4,x; x-ref: $5218 |
| $5210 | 9d fd 06 | staSCREEN_RAM_R19C5,x |
| $5213 | 9d 25 07 | staSCREEN_RAM_R20C5,x |
| $5216 | ca | dex |
| $5217 | ca | dex |
| $5218 | 10 f3 | bplb_520D |
| $521A | ad f7 50 | ldalives_count |
| $521D | c9 02 | cmp#$02 |
| $521F | 90 17 | bccr_5238 |
| $5221 | e9 02 | sbc#$02 |
| $5223 | 0a | asla |
| $5224 | aa | tax |
| $5225 | a9 5f | b_5225lda#$5f; x-ref: $5236 |
| $5227 | 9d fc 06 | staSCREEN_RAM_R19C4,x |
| $522A | a9 60 | lda#$60 |
| $522C | 9d fd 06 | staSCREEN_RAM_R19C5,x |
| $522F | a9 61 | lda#$61 |
| $5231 | 9d 25 07 | staSCREEN_RAM_R20C5,x |
| $5234 | ca | dex |
| $5235 | ca | dex |
| $5236 | 10 ed | bplb_5225 |
| $5238 | 60 | r_5238rts; x-ref: $521F |
| ; Default high score table template: 10 entries x 7 bytes (3 score + 1 player ID + 3 padding). Copied to $527F buffer on init |
| $5239 | | default_high_scores.byte$00, $00, $01, $02, $01, $0c, $10, $00; x-ref: $5330 |
| $5241 | | .byte$90, $00, $01, $02, $12, $01, $00, $80 |
| $5249 | | .byte$00, $01, $03, $08, $01, $00, $70, $00 |
| $5251 | | .byte$01, $04, $05, $0c, $00, $60, $00, $01 |
| $5259 | | .byte$05, $03, $08, $00, $50, $00, $01, $06 |
| $5261 | | .byte$0f, $18, $00, $40, $00, $00, $07, $0f |
| $5269 | | .byte$0c, $00, $30, $00, $00, $08, $0f, $14 |
| $5271 | | .byte$00, $20, $00, $00, $09, $0e, $04, $00 |
| $5279 | | .byte$10, $00, $00, $0a, $15, $0c |
| $527F | | .fill70, $00 |
| ; Max level unlocked for level-select menu. $FF=none, 0=level 3, 1=level 7, 2=level 11, 3=level 15 |
| $52C5 | | max_unlocked_level.byte$ff, $53, $30, $3a, $48, $45, $52, $2d; x-ref: $63C7, $63D3, $63E1, $63EF, $63FB, ... |
| $52CD | | .byte$54, $4f, $50, $53, $43, $4f, $52, $45 |
| $52D5 | | .byte$53 |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| ; Loads high-score data from the disk file "HER-TOPSCORES" into the |
| ; high-score buffer at $527F. First copies default scores from f_5239, |
| ; then overwrites with saved data from disk (if available). |
| ; Preserves zero page $03-$FA by saving/restoring via the ZP backup area. |
| ; |
| ; Inputs: None |
| ; Outputs: High-score buffer at $527F populated from disk (or defaults) |
| ; Side Effects: Disk I/O; zero page temporarily clobbered then restored |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| $52D6 | 20 26 53 | load_high_scoresjsrinit_default_high_scores; Init high-score buffer with defaults from f_5239 ; x-ref: $6690 |
| $52D9 | 20 c4 5b | jsrrestore_zero_page; Save ZP $03-$FA to backup area |
| $52DC | a9 00 | lda#$00; Bank 0 for both LOAD filename and data |
| $52DE | a2 00 | ldx#$00 |
| $52E0 | 20 68 ff | jsrKERNAL_SETBNK; $FF68 (jmp) setbnk |
| $52E3 | a9 7f | lda#$7f; Load destination = $527F (high-score buffer) |
| $52E5 | 85 fb | stazp_ptr_src_lo |
| $52E7 | a9 52 | lda#$52 |
| $52E9 | 85 fc | stazp_ptr_src_hi |
| $52EB | a9 0d | lda#$0d; Filename = "HER-TOPSCORES" (13 chars at $52C9) |
| $52ED | a2 c9 | ldx#$c9 |
| $52EF | a0 52 | ldy#$52 |
| $52F1 | 20 6a 20 | jsrload_file_to_addr; LOAD file into $527F |
| $52F4 | 4c b7 5b | jmpsave_zero_page; Restore ZP $03-$FA from backup and return |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| ; Saves the high scores table from memory ($527F-$52C5) to disk as |
| ; "HER-TOPSCORES". First scratches (deletes) the existing file, then |
| ; saves the buffer. Preserves and restores zero page via backup buffer. |
| ; |
| ; Inputs: None (scores buffer at $527F-$52C5 must be populated) |
| ; Outputs: None |
| ; Side Effects: Writes "HER-TOPSCORES" file to disk; modifies zero page |
| ; temporarily (restored via j_5BB7) |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| save_high_scores_to_disk |
| $52F7 | 20 c4 5b | jsrrestore_zero_page; Restore zero page from backup buffer ; x-ref: $6ED4, $6EFE |
| $52FA | a9 10 | lda#$10; Filename len=16: "S0:HER-TOPSCORES" |
| $52FC | a2 c6 | ldx#$c6 |
| $52FE | a0 52 | ldy#$52 |
| $5300 | 20 8c 20 | jsrsend_disk_command; Scratch (delete) existing file on disk |
| $5303 | a9 00 | lda#$00; I/O bank=0, filename bank=0 |
| $5305 | a2 00 | ldx#$00 |
| $5307 | 20 68 ff | jsrKERNAL_SETBNK; Set KERNAL banks for C128; $FF68 (jmp) setbnk |
| $530A | a9 7f | lda#$7f; Save start address = $527F (scores buffer) |
| $530C | 85 fb | stazp_ptr_src_lo |
| $530E | a9 52 | lda#$52 |
| $5310 | 85 fc | stazp_ptr_src_hi |
| $5312 | a9 c6 | lda#$c6; Save end address+1 = $52C6 (end of buffer) |
| $5314 | 85 fd | stazp_ptr_dst_lo |
| $5316 | a9 52 | lda#$52 |
| $5318 | 85 fe | stazp_ptr_dst_hi |
| $531A | a9 0d | lda#$0d; Filename len=13: "HER-TOPSCORES" |
| $531C | a2 c9 | ldx#$c9 |
| $531E | a0 52 | ldy#$52 |
| $5320 | 20 7b 20 | jsrsave_memory_to_device; Save $527F-$52C5 to "HER-TOPSCORES" |
| $5323 | 4c b7 5b | jmpsave_zero_page; Backup zero page and return |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| ; Copies the default high score table (10 entries x 7 bytes) from the |
| ; read-only template at f_5239 into the working score buffer at $527F. |
| ; Called before loading saved scores from disk and before saving them. |
| ; |
| ; Inputs: None |
| ; Outputs: None |
| ; Side Effects: Overwrites 70 bytes at $527F-$52C4 with default scores; |
| ; clobbers ZP pointer $FB/$FC and Y register. |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| init_default_high_scores |
| $5326 | a9 7f | lda#$7f; Set up ZP pointer to destination buffer at $527F ; x-ref: $52D6, $6ED1 |
| $5328 | 85 fb | stazp_ptr_src_lo |
| $532A | a9 52 | lda#$52 |
| $532C | 85 fc | stazp_ptr_src_hi |
| $532E | a0 00 | ldy#$00; Y = 0, start of copy loop |
| $5330 | b9 39 52 | b_5330ldadefault_high_scores,y; Load byte from default score template ; x-ref: $5338 |
| $5333 | 91 fb | sta(zp_ptr_src_lo),y; Store to working score buffer at ($FB),Y |
| $5335 | c8 | iny |
| $5336 | c0 46 | cpy#$46; 70 bytes = 10 entries x 7 bytes each |
| $5338 | d0 f6 | bneb_5330 |
| $533A | 60 | rts; Return after copying all 70 bytes |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| ; Inserts the current player's score into the high score table. |
| ; Walks the 10-entry table from bottom to top, shifting entries down |
| ; to make room, then writes the new score and player ID at the |
| ; correct sorted position. |
| ; |
| ; Each table entry is 7 bytes: 3 bytes score (lo/mid/hi) + 1 byte |
| ; player ID + 3 bytes padding (spaces $20). |
| ; |
| ; Inputs: $50F4-$50F6 = player score (3 bytes, lo/mid/hi) |
| ; $60D9 = player identifier byte |
| ; Outputs: A = table position (0-9) if inserted, or $FF if not qualified |
| ; X = same as A |
| ; Side Effects: Modifies high score buffer at $527F, clobbers $FB-$FE |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| $533B | 20 cb 53 | insert_high_scorejsrset_score_buffer_ptr; Point $FB/$FC at score buffer base ($527F) ; x-ref: $62A4 |
| $533E | a2 0a | ldx#$0a; X = 10 entries to check |
| $5340 | a5 fb | ldazp_ptr_src_lo; Advance $FB/$FC by $3F (63) to last entry |
| $5342 | 18 | clc |
| $5343 | 69 3f | adc#$3f |
| $5345 | 85 fb | stazp_ptr_src_lo |
| $5347 | a5 fc | ldazp_ptr_src_hi |
| $5349 | 69 00 | adc#$00 |
| $534B | 85 fc | stazp_ptr_src_hi |
| $534D | a5 fb | ldazp_ptr_src_lo; $FD/$FE = $FB/$FC + 7 (next slot below) |
| $534F | 18 | clc |
| $5350 | 69 07 | adc#$07 |
| $5352 | 85 fd | stazp_ptr_dst_lo |
| $5354 | a5 fc | ldazp_ptr_src_hi |
| $5356 | 69 00 | adc#$00 |
| $5358 | 85 fe | stazp_ptr_dst_hi |
| $535A | a0 02 | b_535Aldy#$02; --- Compare loop: walk table bottom-to-top --- ; x-ref: $539C |
| $535C | ad f6 50 | ldascore_hi; Compare high byte of score |
| $535F | d1 fb | cmp(zp_ptr_src_lo),y |
| $5361 | 90 3b | bccb_539E; Player score < entry: done, don't insert here |
| $5363 | d0 14 | bneb_5379 |
| $5365 | 88 | dey |
| $5366 | ad f5 50 | ldascore_mid; Compare mid byte of score |
| $5369 | d1 fb | cmp(zp_ptr_src_lo),y |
| $536B | 90 31 | bccb_539E |
| $536D | d0 0a | bneb_5379 |
| $536F | 88 | dey |
| $5370 | ad f4 50 | ldascore_lo; Compare low byte of score |
| $5373 | d1 fb | cmp(zp_ptr_src_lo),y |
| $5375 | 90 27 | bccb_539E |
| $5377 | f0 25 | beqb_539E; Score == entry: no insertion needed |
| $5379 | e0 0a | b_5379cpx#$0a; First iteration? Skip copy (no slot below to shift into) ; x-ref: $5363, $536D |
| $537B | f0 09 | beqb_5386 |
| $537D | a0 06 | ldy#$06 |
| $537F | b1 fb | b_537Flda(zp_ptr_src_lo),y; Copy 7-byte entry from ($FB) down to ($FD) ; x-ref: $5384 |
| $5381 | 91 fd | sta(zp_ptr_dst_lo),y |
| $5383 | 88 | dey |
| $5384 | 10 f9 | bplb_537F |
| $5386 | a5 fb | b_5386ldazp_ptr_src_lo; $FD/$FE = current slot (will become target for next shift) ; x-ref: $537B |
| $5388 | 85 fd | stazp_ptr_dst_lo |
| $538A | a5 fc | ldazp_ptr_src_hi |
| $538C | 85 fe | stazp_ptr_dst_hi |
| $538E | a5 fb | ldazp_ptr_src_lo; Move $FB/$FC up 7 bytes to previous entry |
| $5390 | 38 | sec |
| $5391 | e9 07 | sbc#$07 |
| $5393 | 85 fb | stazp_ptr_src_lo |
| $5395 | a5 fc | ldazp_ptr_src_hi |
| $5397 | e9 00 | sbc#$00 |
| $5399 | 85 fc | stazp_ptr_src_hi |
| $539B | ca | dex; Loop until all 10 entries checked |
| $539C | d0 bc | bneb_535A |
| $539E | e0 0a | b_539Ecpx#$0a; X still 10? Score didn't beat any entry ; x-ref: $5361, $536B, $5375, $5377 |
| $53A0 | f0 26 | beqb_53C8 |
| $53A2 | a0 00 | ldy#$00 |
| $53A4 | ad f4 50 | ldascore_lo; Write player score low byte into slot |
| $53A7 | 91 fd | sta(zp_ptr_dst_lo),y |
| $53A9 | c8 | iny |
| $53AA | ad f5 50 | ldascore_mid; Write player score mid byte |
| $53AD | 91 fd | sta(zp_ptr_dst_lo),y |
| $53AF | c8 | iny |
| $53B0 | ad f6 50 | ldascore_hi; Write player score high byte |
| $53B3 | 91 fd | sta(zp_ptr_dst_lo),y |
| $53B5 | c8 | iny |
| $53B6 | ad d9 60 | ldacurrent_level; Write player ID byte |
| $53B9 | 91 fd | sta(zp_ptr_dst_lo),y |
| $53BB | c8 | iny |
| $53BC | a9 20 | lda#$20; Pad remaining 3 bytes with spaces ($20) |
| $53BE | 91 fd | sta(zp_ptr_dst_lo),y |
| $53C0 | c8 | iny |
| $53C1 | 91 fd | sta(zp_ptr_dst_lo),y |
| $53C3 | c8 | iny |
| $53C4 | 91 fd | sta(zp_ptr_dst_lo),y |
| $53C6 | 8a | txa; Return X = insertion position (0-9) |
| $53C7 | 60 | rts |
| $53C8 | a9 ff | b_53C8lda#$ff; Return $FF = score not qualified ; x-ref: $53A0 |
| $53CA | 60 | rts |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| ; Sets the ZP pointer $FB/$FC to the start of the high score buffer ($527F). |
| ; Called before any operation that needs to read/write score entries. |
| ; |
| ; Inputs: None |
| ; Outputs: $FB/$FC = $527F (high score buffer base address) |
| ; Side Effects: Clobbers A register. |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| $53CB | a9 7f | set_score_buffer_ptrlda#$7f; Low byte of $527F (score buffer) ; x-ref: $533B, $6D96, $6E70 |
| $53CD | 85 fb | stazp_ptr_src_lo; ZP pointer low byte |
| $53CF | a9 52 | lda#$52; High byte of $527F (score buffer) |
| $53D1 | 85 fc | stazp_ptr_src_hi; ZP pointer high byte |
| $53D3 | 60 | rts |
| ; Current sprite slot index (0-18) during sprite multiplexer rendering pass |
| $53D4 | | sprite_render_index.byte$00; x-ref: $5616, $563D, $569F, $56A2, $56CF, ... |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| ; Resets all VIC-II sprite registers to zero, effectively disabling all 8 |
| ; sprites and clearing their positions, expand flags, priority, and |
| ; multicolor mode. |
| ; |
| ; Inputs: None |
| ; Outputs: A = $00, X = $FF (from loop underflow) |
| ; Side Effects: All sprite positions zeroed, sprites disabled, all |
| ; sprite attribute registers cleared ($D010–$D01D). |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| $53D5 | a2 0f | reset_all_spritesldx#$0f; 16 sprite registers ($D000–$D00F) ; x-ref: $5F22, $6062, $613F, $6635, $66AF, ... |
| $53D7 | a9 00 | lda#$00; A=0 to clear all registers |
| $53D9 | 9d 00 d0 | b_53D9sta$d000,x; zero sprite X/Y positions ; x-ref: $53DD Sprite 0 X Pos |
| $53DC | ca | dex |
| $53DD | 10 fa | bplb_53D9 |
| $53DF | 8d 10 d0 | sta$d010; clear sprite X MSB bits; Sprites 0-7 MSB of X coordinate |
| $53E2 | 8d 15 d0 | sta$d015; disable all sprites; Sprite display Enable |
| $53E5 | 8d 17 d0 | sta$d017; no Y-expand; Sprites Expand 2x Vertical (Y) |
| $53E8 | 8d 1b d0 | sta$d01b; sprites behind background; Sprite to Background Display Priority |
| $53EB | 8d 1c d0 | sta$d01c; no multicolor; Sprites Multi-Color Mode Select |
| $53EE | 8d 1d d0 | sta$d01d; no X-expand; Sprites Expand 2x Horizontal (X) |
| $53F1 | 60 | rts |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| ; Initializes all 19 sprite/object slots to their default state. |
| ; Sets the sort order table to identity (0..18), moves all sprites offscreen |
| ; (Y = $FF), clears two attribute arrays, and enables multicolor mode for |
| ; all hardware sprites. |
| ; |
| ; Inputs: None |
| ; Outputs: zpf_20[$00..$12] = identity order, f_0033[$00..$12] = $FF, |
| ; zpf_92[$00..$12] = $00, zpf_A5[$00..$12] = $00 |
| ; Side Effects: Sets $D01C (Sprite Multicolor Mode) to $FF (all sprites multicolor) |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| $53F2 | a2 12 | init_spritesldx#$12; 19 sprite slots (0-18) ; x-ref: $6147 |
| $53F4 | 8a | b_53F4txa; use index as initial sort order value ; x-ref: $5402 |
| $53F5 | 95 20 | stazpf_sort_order,x; sort_order[x] = x (identity mapping) |
| $53F7 | a9 ff | lda#$ff |
| $53F9 | 95 33 | stazp_spr_y_pos,x; y_pos[x] = $FF (offscreen) |
| $53FB | a9 00 | lda#$00 |
| $53FD | 95 92 | stazp_spr_expand_x,x; clear attribute table 1 |
| $53FF | 95 a5 | stazp_spr_priority,x; clear attribute table 2 |
| $5401 | ca | dex |
| $5402 | 10 f0 | bplb_53F4 |
| $5404 | a9 ff | lda#$ff; enable multicolor mode for all sprites |
| $5406 | 8d 1c d0 | sta$d01c; Sprites Multi-Color Mode Select |
| $5409 | 60 | rts |
| $540A | a2 00 | j_540Aldx#$00; x-ref: $648F |
| $540C | b4 21 | b_540Cldyzpf_sort_order_1,x; x-ref: $5437 |
| $540E | b9 33 00 | lda@w zp_spr_y_pos,y |
| $5411 | b4 20 | ldyzpf_sort_order,x |
| $5413 | d9 33 00 | cmp@w zp_spr_y_pos,y |
| $5416 | b0 1c | bcsb_5434 |
| $5418 | 8e 33 54 | stxsprite_sort_resume_x |
| $541B | b5 21 | b_541Bldazpf_sort_order_1,x; x-ref: $5430 |
| $541D | 95 20 | stazpf_sort_order,x |
| $541F | 94 21 | styzpf_sort_order_1,x |
| $5421 | e0 00 | cpx#$00 |
| $5423 | f0 0d | beqb_5432 |
| $5425 | ca | dex |
| $5426 | b4 21 | ldyzpf_sort_order_1,x |
| $5428 | b9 33 00 | lda@w zp_spr_y_pos,y |
| $542B | b4 20 | ldyzpf_sort_order,x |
| $542D | d9 33 00 | cmp@w zp_spr_y_pos,y |
| $5430 | 90 e9 | bccb_541B |
| sprite_sort_resume_x =*+$01 ; x-ref: $5418 |
| $5432 | a2 ff | b_5432ldx#$ff; x-ref: $5423 |
| $5434 | e8 | b_5434inx; x-ref: $5416 |
| $5435 | e0 12 | cpx#$12 |
| $5437 | 90 d3 | bccb_540C |
| $5439 | a9 00 | lda#$00 |
| $543B | 8d 10 d0 | sta$d010; Sprites 0-7 MSB of X coordinate |
| $543E | 8d 1d d0 | sta$d01d; Sprites Expand 2x Horizontal (X) |
| $5441 | 8d 1b d0 | sta$d01b; Sprite to Background Display Priority |
| $5444 | a4 20 | ldyzpf_sort_order |
| $5446 | b6 33 | ldxzp_spr_y_pos,y |
| $5448 | 8e 01 d0 | stx$d001; Sprite 0 Y Pos |
| $544B | b6 46 | ldxzp_spr_x_lo,y |
| $544D | 8e 00 d0 | stx$d000; Sprite 0 X Pos |
| $5450 | b6 6c | ldxzp_spr_frame,y |
| $5452 | 8e f8 07 | stxSPRITE_PTR_0 |
| $5455 | b6 7f | ldxzp_spr_color,y |
| $5457 | 8e 27 d0 | stx$d027; Sprite 0 Color |
| $545A | b6 59 | ldxzp_spr_x_hi,y |
| $545C | f0 08 | beqb_5466 |
| $545E | ad 10 d0 | lda$d010; Sprites 0-7 MSB of X coordinate |
| $5461 | 09 01 | ora#$01 |
| $5463 | 8d 10 d0 | sta$d010; Sprites 0-7 MSB of X coordinate |
| $5466 | b6 92 | b_5466ldxzp_spr_expand_x,y; x-ref: $545C |
| $5468 | f0 08 | beqb_5472 |
| $546A | ad 1d d0 | lda$d01d; Sprites Expand 2x Horizontal (X) |
| $546D | 09 01 | ora#$01 |
| $546F | 8d 1d d0 | sta$d01d; Sprites Expand 2x Horizontal (X) |
| $5472 | b6 a5 | b_5472ldxzp_spr_priority,y; x-ref: $5468 |
| $5474 | f0 08 | beqb_547E |
| $5476 | ad 1b d0 | lda$d01b; Sprite to Background Display Priority |
| $5479 | 09 01 | ora#$01 |
| $547B | 8d 1b d0 | sta$d01b; Sprite to Background Display Priority |
| $547E | a4 21 | b_547Eldyzpf_sort_order_1; x-ref: $5474 |
| $5480 | b6 33 | ldxzp_spr_y_pos,y |
| $5482 | 8e 03 d0 | stx$d003; Sprite 1 Y Pos |
| $5485 | b6 46 | ldxzp_spr_x_lo,y |
| $5487 | 8e 02 d0 | stx$d002; Sprite 1 X Pos |
| $548A | b6 6c | ldxzp_spr_frame,y |
| $548C | 8e f9 07 | stxSPRITE_PTR_1 |
| $548F | b6 7f | ldxzp_spr_color,y |
| $5491 | 8e 28 d0 | stx$d028; Sprite 1 Color |
| $5494 | b6 59 | ldxzp_spr_x_hi,y |
| $5496 | f0 08 | beqb_54A0 |
| $5498 | ad 10 d0 | lda$d010; Sprites 0-7 MSB of X coordinate |
| $549B | 09 02 | ora#$02 |
| $549D | 8d 10 d0 | sta$d010; Sprites 0-7 MSB of X coordinate |
| $54A0 | b6 92 | b_54A0ldxzp_spr_expand_x,y; x-ref: $5496 |
| $54A2 | f0 08 | beqb_54AC |
| $54A4 | ad 1d d0 | lda$d01d; Sprites Expand 2x Horizontal (X) |
| $54A7 | 09 02 | ora#$02 |
| $54A9 | 8d 1d d0 | sta$d01d; Sprites Expand 2x Horizontal (X) |
| $54AC | b6 a5 | b_54ACldxzp_spr_priority,y; x-ref: $54A2 |
| $54AE | f0 08 | beqb_54B8 |
| $54B0 | ad 1b d0 | lda$d01b; Sprite to Background Display Priority |
| $54B3 | 09 02 | ora#$02 |
| $54B5 | 8d 1b d0 | sta$d01b; Sprite to Background Display Priority |
| $54B8 | a4 22 | b_54B8ldyzp_sort_order_2; x-ref: $54AE |
| $54BA | b6 33 | ldxzp_spr_y_pos,y |
| $54BC | 8e 05 d0 | stx$d005; Sprite 2 Y Pos |
| $54BF | b6 46 | ldxzp_spr_x_lo,y |
| $54C1 | 8e 04 d0 | stx$d004; Sprite 2 X Pos |
| $54C4 | b6 6c | ldxzp_spr_frame,y |
| $54C6 | 8e fa 07 | stxSPRITE_PTR_2 |
| $54C9 | b6 7f | ldxzp_spr_color,y |
| $54CB | 8e 29 d0 | stx$d029; Sprite 2 Color |
| $54CE | b6 59 | ldxzp_spr_x_hi,y |
| $54D0 | f0 08 | beqb_54DA |
| $54D2 | ad 10 d0 | lda$d010; Sprites 0-7 MSB of X coordinate |
| $54D5 | 09 04 | ora#$04 |
| $54D7 | 8d 10 d0 | sta$d010; Sprites 0-7 MSB of X coordinate |
| $54DA | b6 92 | b_54DAldxzp_spr_expand_x,y; x-ref: $54D0 |
| $54DC | f0 08 | beqb_54E6 |
| $54DE | ad 1d d0 | lda$d01d; Sprites Expand 2x Horizontal (X) |
| $54E1 | 09 04 | ora#$04 |
| $54E3 | 8d 1d d0 | sta$d01d; Sprites Expand 2x Horizontal (X) |
| $54E6 | b6 a5 | b_54E6ldxzp_spr_priority,y; x-ref: $54DC |
| $54E8 | f0 08 | beqb_54F2 |
| $54EA | ad 1b d0 | lda$d01b; Sprite to Background Display Priority |
| $54ED | 09 04 | ora#$04 |
| $54EF | 8d 1b d0 | sta$d01b; Sprite to Background Display Priority |
| $54F2 | a4 23 | b_54F2ldyzp_sort_order_3; x-ref: $54E8 |
| $54F4 | b6 33 | ldxzp_spr_y_pos,y |
| $54F6 | 8e 07 d0 | stx$d007; Sprite 3 Y Pos |
| $54F9 | b6 46 | ldxzp_spr_x_lo,y |
| $54FB | 8e 06 d0 | stx$d006; Sprite 3 X Pos |
| $54FE | b6 6c | ldxzp_spr_frame,y |
| $5500 | 8e fb 07 | stxSPRITE_PTR_3 |
| $5503 | b6 7f | ldxzp_spr_color,y |
| $5505 | 8e 2a d0 | stx$d02a; Sprite 3 Color |
| $5508 | b6 59 | ldxzp_spr_x_hi,y |
| $550A | f0 08 | beqb_5514 |
| $550C | ad 10 d0 | lda$d010; Sprites 0-7 MSB of X coordinate |
| $550F | 09 08 | ora#$08 |
| $5511 | 8d 10 d0 | sta$d010; Sprites 0-7 MSB of X coordinate |
| $5514 | b6 92 | b_5514ldxzp_spr_expand_x,y; x-ref: $550A |
| $5516 | f0 08 | beqb_5520 |
| $5518 | ad 1d d0 | lda$d01d; Sprites Expand 2x Horizontal (X) |
| $551B | 09 08 | ora#$08 |
| $551D | 8d 1d d0 | sta$d01d; Sprites Expand 2x Horizontal (X) |
| $5520 | b6 a5 | b_5520ldxzp_spr_priority,y; x-ref: $5516 |
| $5522 | f0 08 | beqb_552C |
| $5524 | ad 1b d0 | lda$d01b; Sprite to Background Display Priority |
| $5527 | 09 08 | ora#$08 |
| $5529 | 8d 1b d0 | sta$d01b; Sprite to Background Display Priority |
| $552C | a4 24 | b_552Cldyzp_sort_order_4; x-ref: $5522 |
| $552E | b6 33 | ldxzp_spr_y_pos,y |
| $5530 | 8e 09 d0 | stx$d009; Sprite 4 Y Pos |
| $5533 | b6 46 | ldxzp_spr_x_lo,y |
| $5535 | 8e 08 d0 | stx$d008; Sprite 4 X Pos |
| $5538 | b6 6c | ldxzp_spr_frame,y |
| $553A | 8e fc 07 | stxSPRITE_PTR_4 |
| $553D | b6 7f | ldxzp_spr_color,y |
| $553F | 8e 2b d0 | stx$d02b; Sprite 4 Color |
| $5542 | b6 59 | ldxzp_spr_x_hi,y |
| $5544 | f0 08 | beqb_554E |
| $5546 | ad 10 d0 | lda$d010; Sprites 0-7 MSB of X coordinate |
| $5549 | 09 10 | ora#$10 |
| $554B | 8d 10 d0 | sta$d010; Sprites 0-7 MSB of X coordinate |
| $554E | b6 92 | b_554Eldxzp_spr_expand_x,y; x-ref: $5544 |
| $5550 | f0 08 | beqb_555A |
| $5552 | ad 1d d0 | lda$d01d; Sprites Expand 2x Horizontal (X) |
| $5555 | 09 10 | ora#$10 |
| $5557 | 8d 1d d0 | sta$d01d; Sprites Expand 2x Horizontal (X) |
| $555A | b6 a5 | b_555Aldxzp_spr_priority,y; x-ref: $5550 |
| $555C | f0 08 | beqb_5566 |
| $555E | ad 1b d0 | lda$d01b; Sprite to Background Display Priority |
| $5561 | 09 10 | ora#$10 |
| $5563 | 8d 1b d0 | sta$d01b; Sprite to Background Display Priority |
| $5566 | a4 25 | b_5566ldyzp_sort_order_5; x-ref: $555C |
| $5568 | b6 33 | ldxzp_spr_y_pos,y |
| $556A | 8e 0b d0 | stx$d00b; Sprite 5 Y Pos |
| $556D | b6 46 | ldxzp_spr_x_lo,y |
| $556F | 8e 0a d0 | stx$d00a; Sprite 5 X Pos |
| $5572 | b6 6c | ldxzp_spr_frame,y |
| $5574 | 8e fd 07 | stxSPRITE_PTR_5 |
| $5577 | b6 7f | ldxzp_spr_color,y |
| $5579 | 8e 2c d0 | stx$d02c; Sprite 5 Color |
| $557C | b6 59 | ldxzp_spr_x_hi,y |
| $557E | f0 08 | beqb_5588 |
| $5580 | ad 10 d0 | lda$d010; Sprites 0-7 MSB of X coordinate |
| $5583 | 09 20 | ora#$20 |
| $5585 | 8d 10 d0 | sta$d010; Sprites 0-7 MSB of X coordinate |
| $5588 | b6 92 | b_5588ldxzp_spr_expand_x,y; x-ref: $557E |
| $558A | f0 08 | beqb_5594 |
| $558C | ad 1d d0 | lda$d01d; Sprites Expand 2x Horizontal (X) |
| $558F | 09 20 | ora#$20 |
| $5591 | 8d 1d d0 | sta$d01d; Sprites Expand 2x Horizontal (X) |
| $5594 | b6 a5 | b_5594ldxzp_spr_priority,y; x-ref: $558A |
| $5596 | f0 08 | beqb_55A0 |
| $5598 | ad 1b d0 | lda$d01b; Sprite to Background Display Priority |
| $559B | 09 20 | ora#$20 |
| $559D | 8d 1b d0 | sta$d01b; Sprite to Background Display Priority |
| $55A0 | a4 26 | b_55A0ldyzp_sort_order_6; x-ref: $5596 |
| $55A2 | b6 33 | ldxzp_spr_y_pos,y |
| $55A4 | 8e 0d d0 | stx$d00d; Sprite 6 Y Pos |
| $55A7 | b6 46 | ldxzp_spr_x_lo,y |
| $55A9 | 8e 0c d0 | stx$d00c; Sprite 6 X Pos |
| $55AC | b6 6c | ldxzp_spr_frame,y |
| $55AE | 8e fe 07 | stxSPRITE_PTR_6 |
| $55B1 | b6 7f | ldxzp_spr_color,y |
| $55B3 | 8e 2d d0 | stx$d02d; Sprite 6 Color |
| $55B6 | b6 59 | ldxzp_spr_x_hi,y |
| $55B8 | f0 08 | beqb_55C2 |
| $55BA | ad 10 d0 | lda$d010; Sprites 0-7 MSB of X coordinate |
| $55BD | 09 40 | ora#$40 |
| $55BF | 8d 10 d0 | sta$d010; Sprites 0-7 MSB of X coordinate |
| $55C2 | b6 92 | b_55C2ldxzp_spr_expand_x,y; x-ref: $55B8 |
| $55C4 | f0 08 | beqb_55CE |
| $55C6 | ad 1d d0 | lda$d01d; Sprites Expand 2x Horizontal (X) |
| $55C9 | 09 40 | ora#$40 |
| $55CB | 8d 1d d0 | sta$d01d; Sprites Expand 2x Horizontal (X) |
| $55CE | b6 a5 | b_55CEldxzp_spr_priority,y; x-ref: $55C4 |
| $55D0 | f0 08 | beqb_55DA |
| $55D2 | ad 1b d0 | lda$d01b; Sprite to Background Display Priority |
| $55D5 | 09 40 | ora#$40 |
| $55D7 | 8d 1b d0 | sta$d01b; Sprite to Background Display Priority |
| $55DA | a4 27 | b_55DAldyzp_sort_order_7; x-ref: $55D0 |
| $55DC | b6 33 | ldxzp_spr_y_pos,y |
| $55DE | 8e 0f d0 | stx$d00f; Sprite 7 Y Pos |
| $55E1 | b6 46 | ldxzp_spr_x_lo,y |
| $55E3 | 8e 0e d0 | stx$d00e; Sprite 7 X Pos |
| $55E6 | b6 6c | ldxzp_spr_frame,y |
| $55E8 | 8e ff 07 | stxSPRITE_PTR_7 |
| $55EB | b6 7f | ldxzp_spr_color,y |
| $55ED | 8e 2e d0 | stx$d02e; Sprite 7 Color |
| $55F0 | b6 59 | ldxzp_spr_x_hi,y |
| $55F2 | f0 08 | beqb_55FC |
| $55F4 | ad 10 d0 | lda$d010; Sprites 0-7 MSB of X coordinate |
| $55F7 | 09 80 | ora#$80 |
| $55F9 | 8d 10 d0 | sta$d010; Sprites 0-7 MSB of X coordinate |
| $55FC | b6 92 | b_55FCldxzp_spr_expand_x,y; x-ref: $55F2 |
| $55FE | f0 08 | beqb_5608 |
| $5600 | ad 1d d0 | lda$d01d; Sprites Expand 2x Horizontal (X) |
| $5603 | 09 80 | ora#$80 |
| $5605 | 8d 1d d0 | sta$d01d; Sprites Expand 2x Horizontal (X) |
| $5608 | b6 a5 | b_5608ldxzp_spr_priority,y; x-ref: $55FE |
| $560A | f0 08 | beqb_5614 |
| $560C | ad 1b d0 | lda$d01b; Sprite to Background Display Priority |
| $560F | 09 80 | ora#$80 |
| $5611 | 8d 1b d0 | sta$d01b; Sprite to Background Display Priority |
| $5614 | a9 08 | b_5614lda#$08; x-ref: $560A |
| $5616 | 8d d4 53 | stasprite_render_index |
| $5619 | 60 | rts |
| $561A | ad 01 d0 | j_561Alda$d001; x-ref: $5AA7, $64D3 Sprite 0 Y Pos |
| $561D | c9 8c | cmp#$8c |
| $561F | 90 03 | bccb_5624 |
| $5621 | 4c aa 5a | jmpj_5AAA |
| $5624 | 18 | b_5624clc; x-ref: $561F |
| $5625 | 69 17 | adc#$17 |
| $5627 | ed 12 d0 | sbc$d012; Raster Position |
| $562A | 90 11 | bccirq_sprite_mux_0 |
| $562C | c9 03 | cmp#$03 |
| $562E | b0 02 | bcsb_5632 |
| $5630 | a9 03 | lda#$03 |
| $5632 | 18 | b_5632clc; x-ref: $562E |
| $5633 | 6d 12 d0 | adc$d012; Raster Position |
| $5636 | a2 3d | ldx#<irq_sprite_mux_0 |
| $5638 | a0 56 | ldy#>irq_sprite_mux_0 |
| $563A | 4c 7c 21 | jmpirq_chain_next |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| ; Sprite multiplexer raster IRQ handler chain (hardware sprite 0). |
| ; |
| ; The VIC-II has only 8 hardware sprites, but this game displays up to 19 |
| ; logical sprites by reusing hardware sprites across different raster lines. |
| ; Each handler in the chain (irq_sprite_mux_0 through irq_sprite_mux_7) |
| ; configures one hardware sprite from the Y-sorted software sprite tables: |
| ; |
| ; 1. Load sprite_render_index to get the current logical sprite slot. |
| ; 2. Use zpf_sort_order[slot] to get the Y-sorted sprite index. |
| ; 3. If Y position == $FF → sprite is offscreen, skip to j_5AAA (done). |
| ; 4. Write Y pos, X pos lo, X hi bit, frame ptr, color, expand-X, |
| ; and priority to the VIC-II registers for this hardware sprite. |
| ; 5. Increment sprite_render_index. If >= 19 ($13) → done. |
| ; 6. Read the NEXT hardware sprite's current Y register to calculate |
| ; when to fire the next raster split. |
| ; 7. Chain to the next handler via JMP j_217C (set raster + IRQ vector). |
| ; |
| ; After all 8 hardware sprites are assigned, handler 7 loops back to |
| ; irq_sprite_mux_0 (via j_561A) to reuse sprites on lower raster lines. |
| ; |
| ; Inputs: sprite_render_index, zpf_sort_order[], zp_spr_* tables |
| ; Outputs: VIC-II sprite registers ($D000-$D00F, $D010, $D01B, $D01D, |
| ; $D027-$D02E, sprite pointers) |
| ; Side Effects: Configures VIC-II hardware sprites, chains next raster IRQ |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| $563D | ac d4 53 | irq_sprite_mux_0ldysprite_render_index; --- HW sprite 0: VIC $D000/$D001 --- ; x-ref: $562A, $5636, $5638 |
| $5640 | b9 20 00 | lda@w zpf_sort_order,y |
| $5643 | a8 | tay; Get Y-sorted logical sprite index |
| $5644 | b9 33 00 | lda@w zp_spr_y_pos,y |
| $5647 | c9 ff | cmp#$ff; Check if sprite is offscreen ($FF) |
| $5649 | d0 03 | bneb_564E |
| $564B | 4c aa 5a | jmpj_5AAA; No more sprites to render |
| $564E | 8d 01 d0 | b_564Esta$d001; Set HW sprite 0 Y position ; x-ref: $5649 Sprite 0 Y Pos |
| $5651 | b9 46 00 | lda@w zp_spr_x_lo,y |
| $5654 | 8d 00 d0 | sta$d000; Set HW sprite 0 frame pointer; Sprite 0 X Pos |
| $5657 | b9 6c 00 | lda@w zp_spr_frame,y |
| $565A | 8d f8 07 | staSPRITE_PTR_0 |
| $565D | b9 7f 00 | lda@w zp_spr_color,y; Set X MSB bit 0 |
| $5660 | 8d 27 d0 | sta$d027; Sprite 0 Color |
| $5663 | b9 59 00 | lda@w zp_spr_x_hi,y |
| $5666 | f0 07 | beqb_566F |
| $5668 | a9 01 | lda#$01 |
| $566A | 0d 10 d0 | ora$d010; Sprites 0-7 MSB of X coordinate |
| $566D | d0 05 | bneb_5674 |
| $566F | a9 fe | b_566Flda#$fe; Set expand-X bit 0 ; x-ref: $5666 |
| $5671 | 2d 10 d0 | and$d010; Sprites 0-7 MSB of X coordinate |
| $5674 | 8d 10 d0 | b_5674sta$d010; x-ref: $566D Sprites 0-7 MSB of X coordinate |
| $5677 | b9 92 00 | lda@w zp_spr_expand_x,y |
| $567A | f0 07 | beqb_5683 |
| $567C | a9 01 | lda#$01 |
| $567E | 0d 1d d0 | ora$d01d; Sprites Expand 2x Horizontal (X) |
| $5681 | d0 05 | bneb_5688; Set priority bit 0 |
| $5683 | a9 fe | b_5683lda#$fe; x-ref: $567A |
| $5685 | 2d 1d d0 | and$d01d; Sprites Expand 2x Horizontal (X) |
| $5688 | 8d 1d d0 | b_5688sta$d01d; x-ref: $5681 Sprites Expand 2x Horizontal (X) |
| $568B | b9 a5 00 | lda@w zp_spr_priority,y |
| $568E | f0 07 | beqb_5697 |
| $5690 | a9 01 | lda#$01 |
| $5692 | 0d 1b d0 | ora$d01b; Sprite to Background Display Priority |
| $5695 | d0 05 | bneb_569C; All 19 sprites processed? |
| $5697 | a9 fe | b_5697lda#$fe; x-ref: $568E |
| $5699 | 2d 1b d0 | and$d01b; Sprite to Background Display Priority |
| $569C | 8d 1b d0 | b_569Csta$d01b; Read next HW sprite Y to calc raster split ; x-ref: $5695 Sprite to Background Display Priority |
| $569F | ee d4 53 | incsprite_render_index; Past visible area? ($8C = rasterline 140) |
| $56A2 | ad d4 53 | ldasprite_render_index |
| $56A5 | c9 13 | cmp#$13 |
| $56A7 | d0 03 | bneb_56AC |
| $56A9 | 4c aa 5a | jmpj_5AAA |
| $56AC | ad 03 d0 | b_56AClda$d003; x-ref: $56A7 Sprite 1 Y Pos |
| $56AF | c9 8c | cmp#$8c |
| $56B1 | 90 03 | bccb_56B6 |
| $56B3 | 4c aa 5a | jmpj_5AAA |
| $56B6 | 18 | b_56B6clc; x-ref: $56B1 |
| $56B7 | 69 17 | adc#$17 |
| $56B9 | ed 12 d0 | sbc$d012; Raster Position |
| $56BC | 90 11 | bccirq_sprite_mux_1 |
| $56BE | c9 03 | cmp#$03 |
| $56C0 | b0 02 | bcsb_56C4 |
| $56C2 | a9 03 | lda#$03 |
| $56C4 | 18 | b_56C4clc; x-ref: $56C0 |
| $56C5 | 6d 12 d0 | adc$d012; Raster Position |
| $56C8 | a2 cf | ldx#<irq_sprite_mux_1 |
| $56CA | a0 56 | ldy#>irq_sprite_mux_1 |
| $56CC | 4c 7c 21 | jmpirq_chain_next |
| $56CF | ac d4 53 | irq_sprite_mux_1ldysprite_render_index; --- HW sprite 1: VIC $D002/$D003 --- ; x-ref: $56BC, $56C8, $56CA |
| $56D2 | b9 20 00 | lda@w zpf_sort_order,y |
| $56D5 | a8 | tay |
| $56D6 | b9 33 00 | lda@w zp_spr_y_pos,y |
| $56D9 | c9 ff | cmp#$ff |
| $56DB | d0 03 | bneb_56E0 |
| $56DD | 4c aa 5a | jmpj_5AAA |
| $56E0 | 8d 03 d0 | b_56E0sta$d003; x-ref: $56DB Sprite 1 Y Pos |
| $56E3 | b9 46 00 | lda@w zp_spr_x_lo,y |
| $56E6 | 8d 02 d0 | sta$d002; Sprite 1 X Pos |
| $56E9 | b9 6c 00 | lda@w zp_spr_frame,y |
| $56EC | 8d f9 07 | staSPRITE_PTR_1 |
| $56EF | b9 7f 00 | lda@w zp_spr_color,y |
| $56F2 | 8d 28 d0 | sta$d028; Sprite 1 Color |
| $56F5 | b9 59 00 | lda@w zp_spr_x_hi,y |
| $56F8 | f0 07 | beqb_5701 |
| $56FA | a9 02 | lda#$02 |
| $56FC | 0d 10 d0 | ora$d010; Sprites 0-7 MSB of X coordinate |
| $56FF | d0 05 | bneb_5706 |
| $5701 | a9 fd | b_5701lda#$fd; x-ref: $56F8 |
| $5703 | 2d 10 d0 | and$d010; Sprites 0-7 MSB of X coordinate |
| $5706 | 8d 10 d0 | b_5706sta$d010; x-ref: $56FF Sprites 0-7 MSB of X coordinate |
| $5709 | b9 92 00 | lda@w zp_spr_expand_x,y |
| $570C | f0 07 | beqb_5715 |
| $570E | a9 02 | lda#$02 |
| $5710 | 0d 1d d0 | ora$d01d; Sprites Expand 2x Horizontal (X) |
| $5713 | d0 05 | bneb_571A |
| $5715 | a9 fd | b_5715lda#$fd; x-ref: $570C |
| $5717 | 2d 1d d0 | and$d01d; Sprites Expand 2x Horizontal (X) |
| $571A | 8d 1d d0 | b_571Asta$d01d; x-ref: $5713 Sprites Expand 2x Horizontal (X) |
| $571D | b9 a5 00 | lda@w zp_spr_priority,y |
| $5720 | f0 07 | beqb_5729 |
| $5722 | a9 02 | lda#$02 |
| $5724 | 0d 1b d0 | ora$d01b; Sprite to Background Display Priority |
| $5727 | d0 05 | bneb_572E |
| $5729 | a9 fd | b_5729lda#$fd; x-ref: $5720 |
| $572B | 2d 1b d0 | and$d01b; Sprite to Background Display Priority |
| $572E | 8d 1b d0 | b_572Esta$d01b; x-ref: $5727 Sprite to Background Display Priority |
| $5731 | ee d4 53 | incsprite_render_index |
| $5734 | ad d4 53 | ldasprite_render_index |
| $5737 | c9 13 | cmp#$13 |
| $5739 | d0 03 | bneb_573E |
| $573B | 4c aa 5a | jmpj_5AAA |
| $573E | ad 05 d0 | b_573Elda$d005; x-ref: $5739 Sprite 2 Y Pos |
| $5741 | c9 8c | cmp#$8c |
| $5743 | 90 03 | bccb_5748 |
| $5745 | 4c aa 5a | jmpj_5AAA |
| $5748 | 18 | b_5748clc; x-ref: $5743 |
| $5749 | 69 17 | adc#$17 |
| $574B | ed 12 d0 | sbc$d012; Raster Position |
| $574E | 90 11 | bccirq_sprite_mux_2 |
| $5750 | c9 03 | cmp#$03 |
| $5752 | b0 02 | bcsb_5756 |
| $5754 | a9 03 | lda#$03 |
| $5756 | 18 | b_5756clc; x-ref: $5752 |
| $5757 | 6d 12 d0 | adc$d012; Raster Position |
| $575A | a2 61 | ldx#<irq_sprite_mux_2 |
| $575C | a0 57 | ldy#>irq_sprite_mux_2 |
| $575E | 4c 7c 21 | jmpirq_chain_next |
| $5761 | ac d4 53 | irq_sprite_mux_2ldysprite_render_index; --- HW sprite 2: VIC $D004/$D005 --- ; x-ref: $574E, $575A, $575C |
| $5764 | b9 20 00 | lda@w zpf_sort_order,y |
| $5767 | a8 | tay |
| $5768 | b9 33 00 | lda@w zp_spr_y_pos,y |
| $576B | c9 ff | cmp#$ff |
| $576D | d0 03 | bneb_5772 |
| $576F | 4c aa 5a | jmpj_5AAA |
| $5772 | 8d 05 d0 | b_5772sta$d005; x-ref: $576D Sprite 2 Y Pos |
| $5775 | b9 46 00 | lda@w zp_spr_x_lo,y |
| $5778 | 8d 04 d0 | sta$d004; Sprite 2 X Pos |
| $577B | b9 6c 00 | lda@w zp_spr_frame,y |
| $577E | 8d fa 07 | staSPRITE_PTR_2 |
| $5781 | b9 7f 00 | lda@w zp_spr_color,y |
| $5784 | 8d 29 d0 | sta$d029; Sprite 2 Color |
| $5787 | b9 59 00 | lda@w zp_spr_x_hi,y |
| $578A | f0 07 | beqb_5793 |
| $578C | a9 04 | lda#$04 |
| $578E | 0d 10 d0 | ora$d010; Sprites 0-7 MSB of X coordinate |
| $5791 | d0 05 | bneb_5798 |
| $5793 | a9 fb | b_5793lda#$fb; x-ref: $578A |
| $5795 | 2d 10 d0 | and$d010; Sprites 0-7 MSB of X coordinate |
| $5798 | 8d 10 d0 | b_5798sta$d010; x-ref: $5791 Sprites 0-7 MSB of X coordinate |
| $579B | b9 92 00 | lda@w zp_spr_expand_x,y |
| $579E | f0 07 | beqb_57A7 |
| $57A0 | a9 04 | lda#$04 |
| $57A2 | 0d 1d d0 | ora$d01d; Sprites Expand 2x Horizontal (X) |
| $57A5 | d0 05 | bneb_57AC |
| $57A7 | a9 fb | b_57A7lda#$fb; x-ref: $579E |
| $57A9 | 2d 1d d0 | and$d01d; Sprites Expand 2x Horizontal (X) |
| $57AC | 8d 1d d0 | b_57ACsta$d01d; x-ref: $57A5 Sprites Expand 2x Horizontal (X) |
| $57AF | b9 a5 00 | lda@w zp_spr_priority,y |
| $57B2 | f0 07 | beqb_57BB |
| $57B4 | a9 04 | lda#$04 |
| $57B6 | 0d 1b d0 | ora$d01b; Sprite to Background Display Priority |
| $57B9 | d0 05 | bneb_57C0 |
| $57BB | a9 fb | b_57BBlda#$fb; x-ref: $57B2 |
| $57BD | 2d 1b d0 | and$d01b; Sprite to Background Display Priority |
| $57C0 | 8d 1b d0 | b_57C0sta$d01b; x-ref: $57B9 Sprite to Background Display Priority |
| $57C3 | ee d4 53 | incsprite_render_index |
| $57C6 | ad d4 53 | ldasprite_render_index |
| $57C9 | c9 13 | cmp#$13 |
| $57CB | d0 03 | bneb_57D0 |
| $57CD | 4c aa 5a | jmpj_5AAA |
| $57D0 | ad 07 d0 | b_57D0lda$d007; x-ref: $57CB Sprite 3 Y Pos |
| $57D3 | c9 8c | cmp#$8c |
| $57D5 | 90 03 | bccb_57DA |
| $57D7 | 4c aa 5a | jmpj_5AAA |
| $57DA | 18 | b_57DAclc; x-ref: $57D5 |
| $57DB | 69 17 | adc#$17 |
| $57DD | ed 12 d0 | sbc$d012; Raster Position |
| $57E0 | 90 11 | bccirq_sprite_mux_3 |
| $57E2 | c9 03 | cmp#$03 |
| $57E4 | b0 02 | bcsb_57E8 |
| $57E6 | a9 03 | lda#$03 |
| $57E8 | 18 | b_57E8clc; x-ref: $57E4 |
| $57E9 | 6d 12 d0 | adc$d012; Raster Position |
| $57EC | a2 f3 | ldx#<irq_sprite_mux_3 |
| $57EE | a0 57 | ldy#>irq_sprite_mux_3 |
| $57F0 | 4c 7c 21 | jmpirq_chain_next |
| $57F3 | ac d4 53 | irq_sprite_mux_3ldysprite_render_index; --- HW sprite 3: VIC $D006/$D007 --- ; x-ref: $57E0, $57EC, $57EE |
| $57F6 | b9 20 00 | lda@w zpf_sort_order,y |
| $57F9 | a8 | tay |
| $57FA | b9 33 00 | lda@w zp_spr_y_pos,y |
| $57FD | c9 ff | cmp#$ff |
| $57FF | d0 03 | bneb_5804 |
| $5801 | 4c aa 5a | jmpj_5AAA |
| $5804 | 8d 07 d0 | b_5804sta$d007; x-ref: $57FF Sprite 3 Y Pos |
| $5807 | b9 46 00 | lda@w zp_spr_x_lo,y |
| $580A | 8d 06 d0 | sta$d006; Sprite 3 X Pos |
| $580D | b9 6c 00 | lda@w zp_spr_frame,y |
| $5810 | 8d fb 07 | staSPRITE_PTR_3 |
| $5813 | b9 7f 00 | lda@w zp_spr_color,y |
| $5816 | 8d 2a d0 | sta$d02a; Sprite 3 Color |
| $5819 | b9 59 00 | lda@w zp_spr_x_hi,y |
| $581C | f0 07 | beqb_5825 |
| $581E | a9 08 | lda#$08 |
| $5820 | 0d 10 d0 | ora$d010; Sprites 0-7 MSB of X coordinate |
| $5823 | d0 05 | bneb_582A |
| $5825 | a9 f7 | b_5825lda#$f7; x-ref: $581C |
| $5827 | 2d 10 d0 | and$d010; Sprites 0-7 MSB of X coordinate |
| $582A | 8d 10 d0 | b_582Asta$d010; x-ref: $5823 Sprites 0-7 MSB of X coordinate |
| $582D | b9 92 00 | lda@w zp_spr_expand_x,y |
| $5830 | f0 07 | beqb_5839 |
| $5832 | a9 08 | lda#$08 |
| $5834 | 0d 1d d0 | ora$d01d; Sprites Expand 2x Horizontal (X) |
| $5837 | d0 05 | bneb_583E |
| $5839 | a9 f7 | b_5839lda#$f7; x-ref: $5830 |
| $583B | 2d 1d d0 | and$d01d; Sprites Expand 2x Horizontal (X) |
| $583E | 8d 1d d0 | b_583Esta$d01d; x-ref: $5837 Sprites Expand 2x Horizontal (X) |
| $5841 | b9 a5 00 | lda@w zp_spr_priority,y |
| $5844 | f0 07 | beqb_584D |
| $5846 | a9 08 | lda#$08 |
| $5848 | 0d 1b d0 | ora$d01b; Sprite to Background Display Priority |
| $584B | d0 05 | bneb_5852 |
| $584D | a9 f7 | b_584Dlda#$f7; x-ref: $5844 |
| $584F | 2d 1b d0 | and$d01b; Sprite to Background Display Priority |
| $5852 | 8d 1b d0 | b_5852sta$d01b; x-ref: $584B Sprite to Background Display Priority |
| $5855 | ee d4 53 | incsprite_render_index |
| $5858 | ad d4 53 | ldasprite_render_index |
| $585B | c9 13 | cmp#$13 |
| $585D | d0 03 | bneb_5862 |
| $585F | 4c aa 5a | jmpj_5AAA |
| $5862 | ad 09 d0 | b_5862lda$d009; x-ref: $585D Sprite 4 Y Pos |
| $5865 | c9 8c | cmp#$8c |
| $5867 | 90 03 | bccb_586C |
| $5869 | 4c aa 5a | jmpj_5AAA |
| $586C | 18 | b_586Cclc; x-ref: $5867 |
| $586D | 69 17 | adc#$17 |
| $586F | ed 12 d0 | sbc$d012; Raster Position |
| $5872 | 90 11 | bccirq_sprite_mux_4 |
| $5874 | c9 03 | cmp#$03 |
| $5876 | b0 02 | bcsb_587A |
| $5878 | a9 03 | lda#$03 |
| $587A | 18 | b_587Aclc; x-ref: $5876 |
| $587B | 6d 12 d0 | adc$d012; Raster Position |
| $587E | a2 85 | ldx#<irq_sprite_mux_4 |
| $5880 | a0 58 | ldy#>irq_sprite_mux_4 |
| $5882 | 4c 7c 21 | jmpirq_chain_next |
| $5885 | ac d4 53 | irq_sprite_mux_4ldysprite_render_index; --- HW sprite 4: VIC $D008/$D009 --- ; x-ref: $5872, $587E, $5880 |
| $5888 | b9 20 00 | lda@w zpf_sort_order,y |
| $588B | a8 | tay |
| $588C | b9 33 00 | lda@w zp_spr_y_pos,y |
| $588F | c9 ff | cmp#$ff |
| $5891 | d0 03 | bneb_5896 |
| $5893 | 4c aa 5a | jmpj_5AAA |
| $5896 | 8d 09 d0 | b_5896sta$d009; x-ref: $5891 Sprite 4 Y Pos |
| $5899 | b9 46 00 | lda@w zp_spr_x_lo,y |
| $589C | 8d 08 d0 | sta$d008; Sprite 4 X Pos |
| $589F | b9 6c 00 | lda@w zp_spr_frame,y |
| $58A2 | 8d fc 07 | staSPRITE_PTR_4 |
| $58A5 | b9 7f 00 | lda@w zp_spr_color,y |
| $58A8 | 8d 2b d0 | sta$d02b; Sprite 4 Color |
| $58AB | b9 59 00 | lda@w zp_spr_x_hi,y |
| $58AE | f0 07 | beqb_58B7 |
| $58B0 | a9 10 | lda#$10 |
| $58B2 | 0d 10 d0 | ora$d010; Sprites 0-7 MSB of X coordinate |
| $58B5 | d0 05 | bneb_58BC |
| $58B7 | a9 ef | b_58B7lda#$ef; x-ref: $58AE |
| $58B9 | 2d 10 d0 | and$d010; Sprites 0-7 MSB of X coordinate |
| $58BC | 8d 10 d0 | b_58BCsta$d010; x-ref: $58B5 Sprites 0-7 MSB of X coordinate |
| $58BF | b9 92 00 | lda@w zp_spr_expand_x,y |
| $58C2 | f0 07 | beqb_58CB |
| $58C4 | a9 10 | lda#$10 |
| $58C6 | 0d 1d d0 | ora$d01d; Sprites Expand 2x Horizontal (X) |
| $58C9 | d0 05 | bneb_58D0 |
| $58CB | a9 ef | b_58CBlda#$ef; x-ref: $58C2 |
| $58CD | 2d 1d d0 | and$d01d; Sprites Expand 2x Horizontal (X) |
| $58D0 | 8d 1d d0 | b_58D0sta$d01d; x-ref: $58C9 Sprites Expand 2x Horizontal (X) |
| $58D3 | b9 a5 00 | lda@w zp_spr_priority,y |
| $58D6 | f0 07 | beqb_58DF |
| $58D8 | a9 10 | lda#$10 |
| $58DA | 0d 1b d0 | ora$d01b; Sprite to Background Display Priority |
| $58DD | d0 05 | bneb_58E4 |
| $58DF | a9 ef | b_58DFlda#$ef; x-ref: $58D6 |
| $58E1 | 2d 1b d0 | and$d01b; Sprite to Background Display Priority |
| $58E4 | 8d 1b d0 | b_58E4sta$d01b; x-ref: $58DD Sprite to Background Display Priority |
| $58E7 | ee d4 53 | incsprite_render_index |
| $58EA | ad d4 53 | ldasprite_render_index |
| $58ED | c9 13 | cmp#$13 |
| $58EF | d0 03 | bneb_58F4 |
| $58F1 | 4c aa 5a | jmpj_5AAA |
| $58F4 | ad 0b d0 | b_58F4lda$d00b; x-ref: $58EF Sprite 5 Y Pos |
| $58F7 | c9 8c | cmp#$8c |
| $58F9 | 90 03 | bccb_58FE |
| $58FB | 4c aa 5a | jmpj_5AAA |
| $58FE | 18 | b_58FEclc; x-ref: $58F9 |
| $58FF | 69 17 | adc#$17 |
| $5901 | ed 12 d0 | sbc$d012; Raster Position |
| $5904 | 90 11 | bccirq_sprite_mux_5 |
| $5906 | c9 03 | cmp#$03 |
| $5908 | b0 02 | bcsb_590C |
| $590A | a9 03 | lda#$03 |
| $590C | 18 | b_590Cclc; x-ref: $5908 |
| $590D | 6d 12 d0 | adc$d012; Raster Position |
| $5910 | a2 17 | ldx#<irq_sprite_mux_5 |
| $5912 | a0 59 | ldy#>irq_sprite_mux_5 |
| $5914 | 4c 7c 21 | jmpirq_chain_next |
| $5917 | ac d4 53 | irq_sprite_mux_5ldysprite_render_index; --- HW sprite 5: VIC $D00A/$D00B --- ; x-ref: $5904, $5910, $5912 |
| $591A | b9 20 00 | lda@w zpf_sort_order,y |
| $591D | a8 | tay |
| $591E | b9 33 00 | lda@w zp_spr_y_pos,y |
| $5921 | c9 ff | cmp#$ff |
| $5923 | d0 03 | bneb_5928 |
| $5925 | 4c aa 5a | jmpj_5AAA |
| $5928 | 8d 0b d0 | b_5928sta$d00b; x-ref: $5923 Sprite 5 Y Pos |
| $592B | b9 46 00 | lda@w zp_spr_x_lo,y |
| $592E | 8d 0a d0 | sta$d00a; Sprite 5 X Pos |
| $5931 | b9 6c 00 | lda@w zp_spr_frame,y |
| $5934 | 8d fd 07 | staSPRITE_PTR_5 |
| $5937 | b9 7f 00 | lda@w zp_spr_color,y |
| $593A | 8d 2c d0 | sta$d02c; Sprite 5 Color |
| $593D | b9 59 00 | lda@w zp_spr_x_hi,y |
| $5940 | f0 07 | beqb_5949 |
| $5942 | a9 20 | lda#$20 |
| $5944 | 0d 10 d0 | ora$d010; Sprites 0-7 MSB of X coordinate |
| $5947 | d0 05 | bneb_594E |
| $5949 | a9 df | b_5949lda#$df; x-ref: $5940 |
| $594B | 2d 10 d0 | and$d010; Sprites 0-7 MSB of X coordinate |
| $594E | 8d 10 d0 | b_594Esta$d010; x-ref: $5947 Sprites 0-7 MSB of X coordinate |
| $5951 | b9 92 00 | lda@w zp_spr_expand_x,y |
| $5954 | f0 07 | beqb_595D |
| $5956 | a9 20 | lda#$20 |
| $5958 | 0d 1d d0 | ora$d01d; Sprites Expand 2x Horizontal (X) |
| $595B | d0 05 | bneb_5962 |
| $595D | a9 df | b_595Dlda#$df; x-ref: $5954 |
| $595F | 2d 1d d0 | and$d01d; Sprites Expand 2x Horizontal (X) |
| $5962 | 8d 1d d0 | b_5962sta$d01d; x-ref: $595B Sprites Expand 2x Horizontal (X) |
| $5965 | b9 a5 00 | lda@w zp_spr_priority,y |
| $5968 | f0 07 | beqb_5971 |
| $596A | a9 20 | lda#$20 |
| $596C | 0d 1b d0 | ora$d01b; Sprite to Background Display Priority |
| $596F | d0 05 | bneb_5976 |
| $5971 | a9 df | b_5971lda#$df; x-ref: $5968 |
| $5973 | 2d 1b d0 | and$d01b; Sprite to Background Display Priority |
| $5976 | 8d 1b d0 | b_5976sta$d01b; x-ref: $596F Sprite to Background Display Priority |
| $5979 | ee d4 53 | incsprite_render_index |
| $597C | ad d4 53 | ldasprite_render_index |
| $597F | c9 13 | cmp#$13 |
| $5981 | d0 03 | bneb_5986 |
| $5983 | 4c aa 5a | jmpj_5AAA |
| $5986 | ad 0d d0 | b_5986lda$d00d; x-ref: $5981 Sprite 6 Y Pos |
| $5989 | c9 8c | cmp#$8c |
| $598B | 90 03 | bccb_5990 |
| $598D | 4c aa 5a | jmpj_5AAA |
| $5990 | 18 | b_5990clc; x-ref: $598B |
| $5991 | 69 17 | adc#$17 |
| $5993 | ed 12 d0 | sbc$d012; Raster Position |
| $5996 | 90 11 | bccirq_sprite_mux_6 |
| $5998 | c9 03 | cmp#$03 |
| $599A | b0 02 | bcsb_599E |
| $599C | a9 03 | lda#$03 |
| $599E | 18 | b_599Eclc; x-ref: $599A |
| $599F | 6d 12 d0 | adc$d012; Raster Position |
| $59A2 | a2 a9 | ldx#<irq_sprite_mux_6 |
| $59A4 | a0 59 | ldy#>irq_sprite_mux_6 |
| $59A6 | 4c 7c 21 | jmpirq_chain_next |
| $59A9 | ac d4 53 | irq_sprite_mux_6ldysprite_render_index; --- HW sprite 6: VIC $D00C/$D00D --- ; x-ref: $5996, $59A2, $59A4 |
| $59AC | b9 20 00 | lda@w zpf_sort_order,y |
| $59AF | a8 | tay |
| $59B0 | b9 33 00 | lda@w zp_spr_y_pos,y |
| $59B3 | c9 ff | cmp#$ff |
| $59B5 | d0 03 | bneb_59BA |
| $59B7 | 4c aa 5a | jmpj_5AAA |
| $59BA | 8d 0d d0 | b_59BAsta$d00d; x-ref: $59B5 Sprite 6 Y Pos |
| $59BD | b9 46 00 | lda@w zp_spr_x_lo,y |
| $59C0 | 8d 0c d0 | sta$d00c; Sprite 6 X Pos |
| $59C3 | b9 6c 00 | lda@w zp_spr_frame,y |
| $59C6 | 8d fe 07 | staSPRITE_PTR_6 |
| $59C9 | b9 7f 00 | lda@w zp_spr_color,y |
| $59CC | 8d 2d d0 | sta$d02d; Sprite 6 Color |
| $59CF | b9 59 00 | lda@w zp_spr_x_hi,y |
| $59D2 | f0 07 | beqb_59DB |
| $59D4 | a9 40 | lda#$40 |
| $59D6 | 0d 10 d0 | ora$d010; Sprites 0-7 MSB of X coordinate |
| $59D9 | d0 05 | bneb_59E0 |
| $59DB | a9 bf | b_59DBlda#$bf; x-ref: $59D2 |
| $59DD | 2d 10 d0 | and$d010; Sprites 0-7 MSB of X coordinate |
| $59E0 | 8d 10 d0 | b_59E0sta$d010; x-ref: $59D9 Sprites 0-7 MSB of X coordinate |
| $59E3 | b9 92 00 | lda@w zp_spr_expand_x,y |
| $59E6 | f0 07 | beqb_59EF |
| $59E8 | a9 40 | lda#$40 |
| $59EA | 0d 1d d0 | ora$d01d; Sprites Expand 2x Horizontal (X) |
| $59ED | d0 05 | bneb_59F4 |
| $59EF | a9 bf | b_59EFlda#$bf; x-ref: $59E6 |
| $59F1 | 2d 1d d0 | and$d01d; Sprites Expand 2x Horizontal (X) |
| $59F4 | 8d 1d d0 | b_59F4sta$d01d; x-ref: $59ED Sprites Expand 2x Horizontal (X) |
| $59F7 | b9 a5 00 | lda@w zp_spr_priority,y |
| $59FA | f0 07 | beqb_5A03 |
| $59FC | a9 40 | lda#$40 |
| $59FE | 0d 1b d0 | ora$d01b; Sprite to Background Display Priority |
| $5A01 | d0 05 | bneb_5A08 |
| $5A03 | a9 bf | b_5A03lda#$bf; x-ref: $59FA |
| $5A05 | 2d 1b d0 | and$d01b; Sprite to Background Display Priority |
| $5A08 | 8d 1b d0 | b_5A08sta$d01b; x-ref: $5A01 Sprite to Background Display Priority |
| $5A0B | ee d4 53 | incsprite_render_index |
| $5A0E | ad d4 53 | ldasprite_render_index |
| $5A11 | c9 13 | cmp#$13 |
| $5A13 | d0 03 | bneb_5A18 |
| $5A15 | 4c aa 5a | jmpj_5AAA |
| $5A18 | ad 0f d0 | b_5A18lda$d00f; x-ref: $5A13 Sprite 7 Y Pos |
| $5A1B | c9 8c | cmp#$8c |
| $5A1D | 90 03 | bccb_5A22 |
| $5A1F | 4c aa 5a | jmpj_5AAA |
| $5A22 | 18 | b_5A22clc; x-ref: $5A1D |
| $5A23 | 69 17 | adc#$17 |
| $5A25 | ed 12 d0 | sbc$d012; Raster Position |
| $5A28 | 90 11 | bccirq_sprite_mux_7 |
| $5A2A | c9 03 | cmp#$03 |
| $5A2C | b0 02 | bcsb_5A30 |
| $5A2E | a9 03 | lda#$03 |
| $5A30 | 18 | b_5A30clc; x-ref: $5A2C |
| $5A31 | 6d 12 d0 | adc$d012; Raster Position |
| $5A34 | a2 3b | ldx#<irq_sprite_mux_7 |
| $5A36 | a0 5a | ldy#>irq_sprite_mux_7 |
| $5A38 | 4c 7c 21 | jmpirq_chain_next |
| $5A3B | ac d4 53 | irq_sprite_mux_7ldysprite_render_index; --- HW sprite 7: VIC $D00E/$D00F --- ; x-ref: $5A28, $5A34, $5A36 |
| $5A3E | b9 20 00 | lda@w zpf_sort_order,y |
| $5A41 | a8 | tay |
| $5A42 | b9 33 00 | lda@w zp_spr_y_pos,y |
| $5A45 | c9 ff | cmp#$ff |
| $5A47 | d0 03 | bneb_5A4C |
| $5A49 | 4c aa 5a | jmpj_5AAA |
| $5A4C | 8d 0f d0 | b_5A4Csta$d00f; x-ref: $5A47 Sprite 7 Y Pos |
| $5A4F | b9 46 00 | lda@w zp_spr_x_lo,y |
| $5A52 | 8d 0e d0 | sta$d00e; Sprite 7 X Pos |
| $5A55 | b9 6c 00 | lda@w zp_spr_frame,y |
| $5A58 | 8d ff 07 | staSPRITE_PTR_7 |
| $5A5B | b9 7f 00 | lda@w zp_spr_color,y |
| $5A5E | 8d 2e d0 | sta$d02e; Sprite 7 Color |
| $5A61 | b9 59 00 | lda@w zp_spr_x_hi,y |
| $5A64 | f0 07 | beqb_5A6D |
| $5A66 | a9 80 | lda#$80 |
| $5A68 | 0d 10 d0 | ora$d010; Sprites 0-7 MSB of X coordinate |
| $5A6B | d0 05 | bneb_5A72 |
| $5A6D | a9 7f | b_5A6Dlda#$7f; x-ref: $5A64 |
| $5A6F | 2d 10 d0 | and$d010; Sprites 0-7 MSB of X coordinate |
| $5A72 | 8d 10 d0 | b_5A72sta$d010; x-ref: $5A6B Sprites 0-7 MSB of X coordinate |
| $5A75 | b9 92 00 | lda@w zp_spr_expand_x,y |
| $5A78 | f0 07 | beqb_5A81 |
| $5A7A | a9 80 | lda#$80 |
| $5A7C | 0d 1d d0 | ora$d01d; Sprites Expand 2x Horizontal (X) |
| $5A7F | d0 05 | bneb_5A86 |
| $5A81 | a9 7f | b_5A81lda#$7f; x-ref: $5A78 |
| $5A83 | 2d 1d d0 | and$d01d; Sprites Expand 2x Horizontal (X) |
| $5A86 | 8d 1d d0 | b_5A86sta$d01d; x-ref: $5A7F Sprites Expand 2x Horizontal (X) |
| $5A89 | b9 a5 00 | lda@w zp_spr_priority,y |
| $5A8C | f0 07 | beqb_5A95 |
| $5A8E | a9 80 | lda#$80 |
| $5A90 | 0d 1b d0 | ora$d01b; Sprite to Background Display Priority |
| $5A93 | d0 05 | bneb_5A9A |
| $5A95 | a9 7f | b_5A95lda#$7f; x-ref: $5A8C |
| $5A97 | 2d 1b d0 | and$d01b; Sprite to Background Display Priority |
| $5A9A | 8d 1b d0 | b_5A9Asta$d01b; x-ref: $5A93 Sprite to Background Display Priority |
| $5A9D | ee d4 53 | incsprite_render_index |
| $5AA0 | ad d4 53 | ldasprite_render_index |
| $5AA3 | c9 13 | cmp#$13 |
| $5AA5 | f0 03 | beqj_5AAA |
| $5AA7 | 4c 1a 56 | jmpj_561A |
| $5AAA | a9 af | j_5AAAlda#$af; x-ref: $5621, $564B, $56A9, $56B3, $56DD, ... |
| $5AAC | a2 d6 | ldx#<irq_end_sprite_mux |
| $5AAE | a0 64 | ldy#>irq_end_sprite_mux |
| $5AB0 | 4c 7c 21 | jmpirq_chain_next |
| ; 248-byte buffer for saving/restoring zero page locations $03–$FA. |
| ; Used by save_zero_page / restore_zero_page around KERNAL calls. |
| $5AB3 | | zp_save_buffer.fill248, $00; x-ref: $5BBB, $5BC6 |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| ; Disables NMI handling by pointing the NMI vector ($FFFA/$FFFB) to an RTI |
| ; instruction at $5BB6. After this, any NMI (e.g., RESTORE key) immediately |
| ; returns without executing any handler code. |
| ; |
| ; Inputs: None |
| ; Outputs: None |
| ; Side Effects: NMI vector ($FFFA/$FFFB) set to $5BB6 (RTI stub) |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| $5BAB | a9 b6 | disable_nmilda#$b6; low byte of NMI handler address ($5BB6) ; x-ref: $20EC |
| $5BAD | 8d fa ff | sta$fffa; set NMI vector low byte; NMI |
| $5BB0 | a9 5b | lda#$5b; high byte of NMI handler address ($5BB6) |
| $5BB2 | 8d fb ff | sta$fffb; set NMI vector high byte → NMI now points to RTI; NMI |
| $5BB5 | 60 | rts |
| $5BB6 | | .byte$40 |
| $5BB7 | a2 00 | save_zero_pageldx#$00; x-ref: $1CA0, $20E6, $52F4, $5323 |
| $5BB9 | b5 03 | b_5BB9ldazp_work1,x; x-ref: $5BC1 |
| $5BBB | 9d b3 5a | stazp_save_buffer,x |
| $5BBE | e8 | inx |
| $5BBF | e0 f8 | cpx#$f8 |
| $5BC1 | d0 f6 | bneb_5BB9 |
| $5BC3 | 60 | rts |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| ; Restores 248 bytes of zero page ($03–$FA) from the save buffer at f_5AB3. |
| ; This is the inverse of the save routine at j_5BB7 (save_zero_page). |
| ; Used to restore zero page state after disk I/O or KERNAL calls that |
| ; clobber it. |
| ; |
| ; Inputs: f_5AB3 buffer containing previously saved zero page data |
| ; Outputs: Zero page $03–$FA restored from buffer |
| ; Side Effects: Overwrites zero page locations $03–$FA |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| $5BC4 | a2 00 | restore_zero_pageldx#$00; Start index at 0 (first ZP byte = $03) ; x-ref: $1C4D, $52D9, $52F7 |
| $5BC6 | bd b3 5a | b_5BC6ldazp_save_buffer,x; Load saved byte from buffer ; x-ref: $5BCE |
| $5BC9 | 95 03 | stazp_work1,x; Write it back to zero page |
| $5BCB | e8 | inx |
| $5BCC | e0 f8 | cpx#$f8; 248 bytes: covers $03–$FA |
| $5BCE | d0 f6 | bneb_5BC6 |
| $5BD0 | 60 | rts |
| ; Maximum number of characters allowed for text input (set on entry to input_text_string). |
| $5BD1 | | input_max_chars.byte$00; x-ref: $5C72, $5CEA, $5D6B, $5D97 |
| ; Current number of characters entered in the input buffer. Incremented on each accepted char, decremented on backspace. |
| $5BD2 | | input_char_count.byte$00; x-ref: $5C7D, $5CBB, $5CE7, $5CF0, $5CFC, ... |
| ; Input completion flag. $00 = still accepting input, $FF = input complete (Enter pressed or max chars reached). |
| $5BD3 | | input_done_flag.byte$00; x-ref: $5C80, $5C9C, $5CA4, $5CE3, $5D9E |
| ; Last keyboard key state for debounce. Compared against current scan to detect new keypresses. |
| $5BD4 | | input_last_key.byte$00; x-ref: $5C8C, $5CC9, $5CCD, $5CD3 |
| ; Screen column position of the text input cursor. Incremented after each character, decremented on backspace. |
| $5BD5 | | input_cursor_col.byte$00; x-ref: $5C75, $5CF9, $5D8E, $5E1D, $5E2E |
| ; Screen row position of the text input cursor. Set once on entry, used for screen address calculation. |
| $5BD6 | | input_cursor_row.byte$00; x-ref: $5C78, $5E08 |
| ; Joystick character selector index (0–40). Indexes into char_selection_table to select the current character. |
| ; 0 = cursor only (space), 1–26 = A-Z, 27–36 = 0-9, 37–40 = punctuation (+, -, ., ,). |
| $5BD7 | | input_selector_idx.byte$00; x-ref: $5C83, $5D01, $5D7F, $5DA4, $5DB9, ... |
| ; Cursor blink frame counter. Increments each frame, resets at 40 ($28). Phase < 20 shows cursor char, >= 20 shows blank. |
| $5BD8 | | input_blink_counter.byte$00; x-ref: $5C86, $5CA9, $5CAC, $5CB5, $5D04, ... |
| ; 40-byte text input buffer. Stores entered character codes, null-terminated. Used for high-score name entry (3 chars max). |
| $5BD9 | | input_text_buffer.fill40, $00; x-ref: $5CC0, $5CF3, $5D88, $6E83 |
| $5C01 | | .byte$ff, $fe, $00, $00, $00, $00, $00, $00 |
| $5C09 | | .byte$33, $17, $01, $34, $1a, $13, $05, $00 |
| $5C11 | | .byte$35, $12, $04, $36, $03, $06, $14, $18 |
| $5C19 | | .byte$37, $19, $07, $38, $02, $08, $15, $16 |
| $5C21 | | .byte$39, $09, $0a, $30, $0d, $0b, $0f, $0e |
| $5C29 | | .byte$2b, $10, $0c, $2d, $2e, $00, $00, $2c |
| $5C31 | | .fill8, $00 |
| $5C39 | | .byte$31, $00, $00, $32, $20, $00, $11, $00 |
| ; CIA1 keyboard row select masks ($FE, $FD, $FB, $F7, $EF, $DF, $BF, $7F). |
| ; Each byte selects one row of the 8×8 keyboard matrix by pulling one bit low on Port A. |
| $5C41 | | keyboard_row_masks.byte$fe, $fd, $fb, $f7, $ef, $df, $bf, $7f; x-ref: $5D17, $5D2F |
| ; Character selection lookup table for joystick text input (41 entries). |
| ; Index 0 = space ($20), 1-26 = A-Z, 27-36 = 0-9, 37-40 = +, -, ., comma. |
| $5C49 | | char_selection_table.byte$20, $01, $02, $03, $04, $05, $06, $07; x-ref: $5D82, $5DFC |
| $5C51 | | .byte$08, $09, $0a, $0b, $0c, $0d, $0e, $0f |
| $5C59 | | .byte$10, $11, $12, $13, $14, $15, $16, $17 |
| $5C61 | | .byte$18, $19, $1a, $30, $31, $32, $33, $34 |
| $5C69 | | .byte$35, $36, $37, $38, $39, $2b, $2d, $2e |
| $5C71 | | .byte$2c |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| ; Text input routine. Reads characters from keyboard or joystick and writes |
| ; them to screen memory. Supports keyboard scanning via CIA1, joystick-based |
| ; character selection (up/down to cycle, fire to confirm), and backspace ($FF). |
| ; Input terminates when max characters reached or Enter ($FE) is pressed. |
| ; |
| ; Inputs: A = max number of characters, X = screen column, Y = screen row |
| ; Outputs: f_5BD9 = buffer with entered character codes |
| ; Side Effects: Writes characters directly to screen memory at $0400 |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| $5C72 | 8d d1 5b | input_text_stringstainput_max_chars; Store max chars allowed ; x-ref: $6E6D |
| $5C75 | 8e d5 5b | stxinput_cursor_col; Store initial screen column |
| $5C78 | 8c d6 5b | styinput_cursor_row; Store screen row |
| $5C7B | a9 00 | lda#$00; Clear current char count |
| $5C7D | 8d d2 5b | stainput_char_count |
| $5C80 | 8d d3 5b | stainput_done_flag; Clear done flag |
| $5C83 | 8d d7 5b | stainput_selector_idx; Clear joystick char selector index |
| $5C86 | 8d d8 5b | stainput_blink_counter; Clear blink counter |
| $5C89 | 20 08 5d | jsrscan_keyboard; Scan keyboard, get initial key |
| $5C8C | 8d d4 5b | stainput_last_key; Store last key state for debounce |
| $5C8F | 20 ec 5d | b_5C8Fjsrdraw_input_cursor; Draw blinking cursor on screen ; x-ref: $5CB1, $5CB8 |
| $5C92 | a9 fb | lda#$fb |
| $5C94 | cd 12 d0 | b_5C94cmp$d012; Wait for raster line $FB (frame sync) ; x-ref: $5C97 Raster Position |
| $5C97 | d0 fb | bneb_5C94 |
| $5C99 | 20 c4 5c | jsrscan_keyboard_and_process_key; Scan keyboard for new keypress |
| $5C9C | ad d3 5b | ldainput_done_flag; Key accepted? (done flag set) |
| $5C9F | d0 1a | bneb_5CBB |
| $5CA1 | 20 54 5d | jsrhandle_joystick_text_input; Check joystick for char selection |
| $5CA4 | ad d3 5b | ldainput_done_flag |
| $5CA7 | d0 12 | bneb_5CBB |
| $5CA9 | ee d8 5b | incinput_blink_counter; Increment blink counter |
| $5CAC | ad d8 5b | ldainput_blink_counter |
| $5CAF | c9 28 | cmp#$28; Blinked 40 frames? (cursor toggle rate) |
| $5CB1 | d0 dc | bneb_5C8F |
| $5CB3 | a9 00 | lda#$00; Reset blink counter |
| $5CB5 | 8d d8 5b | stainput_blink_counter |
| $5CB8 | 4c 8f 5c | jmpb_5C8F |
| $5CBB | ae d2 5b | b_5CBBldxinput_char_count; Load char count index ; x-ref: $5C9F, $5CA7 |
| $5CBE | a9 00 | lda#$00; Clear char in buffer (null terminate) |
| $5CC0 | 9d d9 5b | stainput_text_buffer,x |
| $5CC3 | 60 | rts |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| ; Scans the keyboard matrix via CIA1 and processes the resulting keypress. |
| ; Debounces held keys, handles special keys ($FF = backspace, $FE = abort/done), |
| ; and appends valid characters to the input buffer if not full. |
| ; |
| ; Inputs: None (reads keyboard hardware and internal state variables) |
| ; Outputs: a_5BD4 (last key state), a_5BD3 (abort flag if $FE pressed) |
| ; Side Effects: Writes character to screen via s_5DFF, updates input buffer |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| scan_keyboard_and_process_key |
| $5CC4 | 20 08 5d | jsrscan_keyboard; Scan keyboard matrix ; x-ref: $5C99 |
| $5CC7 | d0 04 | bneb_5CCD; No key pressed? |
| $5CC9 | 8d d4 5b | stainput_last_key; Clear last key state |
| $5CCC | 60 | rts |
| $5CCD | cd d4 5b | b_5CCDcmpinput_last_key; Same key still held? (debounce) ; x-ref: $5CC7 |
| $5CD0 | d0 01 | bneb_5CD3 |
| $5CD2 | 60 | rts; New key: store as current key state |
| $5CD3 | 8d d4 5b | b_5CD3stainput_last_key; Store new key as last key ; x-ref: $5CD0 |
| $5CD6 | c9 ff | cmp#$ff; $FF = backspace key |
| $5CD8 | d0 03 | bneb_5CDD |
| $5CDA | 4c 24 5e | jmpj_5E24; Handle backspace |
| $5CDD | c9 fe | b_5CDDcmp#$fe; $FE = abort/done key ; x-ref: $5CD8 |
| $5CDF | d0 06 | bneb_5CE7 |
| $5CE1 | a9 ff | lda#$ff; Signal input complete |
| $5CE3 | 8d d3 5b | stainput_done_flag; Set abort/done flag |
| $5CE6 | 60 | rts |
| $5CE7 | ae d2 5b | b_5CE7ldxinput_char_count; Check if buffer is full ; x-ref: $5CDF |
| $5CEA | ec d1 5b | cpxinput_max_chars; Compare index vs max length |
| $5CED | d0 01 | bneb_5CF0 |
| $5CEF | 60 | rts |
| $5CF0 | ae d2 5b | b_5CF0ldxinput_char_count; Store char code in input buffer ; x-ref: $5CED |
| $5CF3 | 9d d9 5b | stainput_text_buffer,x; Store char in input buffer |
| $5CF6 | 20 ff 5d | jsrdraw_char_at_cursor; Display char on screen |
| $5CF9 | ee d5 5b | incinput_cursor_col; Advance screen cursor column |
| $5CFC | ee d2 5b | incinput_char_count; Advance buffer write index |
| $5CFF | a9 00 | lda#$00; Reset cursor blink counters |
| $5D01 | 8d d7 5b | stainput_selector_idx |
| $5D04 | 8d d8 5b | stainput_blink_counter |
| $5D07 | 60 | rts |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| ; Scans the keyboard matrix via CIA1 to detect a key press. |
| ; Loops through all 8 rows of the keyboard matrix, outputting row-select |
| ; masks to CIA1 Port A ($DC00) and reading column results from Port B ($DC01). |
| ; If a key is detected (any column bit low), identifies the exact column and |
| ; looks up the keycode from a decode table at ($FB/$FC). |
| ; |
| ; Inputs: None (uses hardcoded pointer $5C01 and row mask table f_5C41) |
| ; Outputs: A = keycode from decode table (0 = no key pressed), Z flag set if no key |
| ; Side Effects: Temporarily sets CIA1 DDRA ($DC02) to output then back to input |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| $5D08 | a9 01 | scan_keyboardlda#$01; Set up pointer to keyboard decode table (low byte) ; x-ref: $5C89, $5CC4 |
| $5D0A | 85 fb | stazp_ptr_src_lo |
| $5D0C | a9 5c | lda#$5c; Decode table pointer high byte = $5C |
| $5D0E | 85 fc | stazp_ptr_src_hi |
| $5D10 | a2 00 | ldx#$00; X = keyboard row index (0-7) |
| $5D12 | a9 ff | b_5D12lda#$ff; x-ref: $5D4F |
| $5D14 | 8d 02 dc | sta$dc02; Set Port A as all outputs for row select; CIA1: Data Direction Register A |
| $5D17 | bd 41 5c | ldakeyboard_row_masks,x; Output row-select mask (one bit low per row) |
| $5D1A | 8d 00 dc | sta$dc00; CIA1: Data Port Register A |
| $5D1D | ad 01 dc | lda$dc01; Read column result from keyboard matrix; CIA1: Data Port Register B |
| $5D20 | 85 ff | stazp_temp; Save column result temporarily |
| $5D22 | a9 00 | lda#$00; Restore Port A as all inputs |
| $5D24 | 8d 02 dc | sta$dc02; CIA1: Data Direction Register A |
| $5D27 | a5 ff | ldazp_temp |
| $5D29 | c9 ff | cmp#$ff; No key pressed in this row? |
| $5D2B | f0 12 | beqb_5D3F; Yes, skip to next row |
| $5D2D | a0 00 | ldy#$00; Y = column index |
| $5D2F | 19 41 5c | j_5D2Forakeyboard_row_masks,y; OR with column mask to isolate pressed key ; x-ref: $5D39 |
| $5D32 | c9 ff | cmp#$ff; All bits high = this column not pressed |
| $5D34 | d0 06 | bneb_5D3C; Found the pressed column |
| $5D36 | a5 ff | ldazp_temp; Reload column result and try next column |
| $5D38 | c8 | iny |
| $5D39 | 4c 2f 5d | jmpj_5D2F |
| $5D3C | b1 fb | b_5D3Clda(zp_ptr_src_lo),y; Look up keycode from decode table[Y] ; x-ref: $5D34 |
| $5D3E | 60 | rts; Return with keycode in A |
| $5D3F | a5 fb | b_5D3Fldazp_ptr_src_lo; Advance pointer by 8 (next row in table) ; x-ref: $5D2B |
| $5D41 | 18 | clc |
| $5D42 | 69 08 | adc#$08 |
| $5D44 | 85 fb | stazp_ptr_src_lo |
| $5D46 | a5 fc | ldazp_ptr_src_hi; Handle carry into high byte |
| $5D48 | 69 00 | adc#$00 |
| $5D4A | 85 fc | stazp_ptr_src_hi |
| $5D4C | e8 | inx |
| $5D4D | e0 08 | cpx#$08; All 8 rows scanned? |
| $5D4F | d0 c1 | bneb_5D12; No, scan next row |
| $5D51 | a9 00 | lda#$00; No key pressed, return 0 |
| $5D53 | 60 | rts |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| ; Handles joystick input for text entry. Reads joystick and processes: |
| ; - Left: delete last entered character (backspace) |
| ; - Fire: confirm currently selected character, store in buffer, advance cursor |
| ; - Up: cycle character selection backward through allowed characters |
| ; - Down: cycle character selection forward through allowed characters |
| ; Uses f_5C49 as a character lookup table (space, A-Z, 0-9, punctuation). |
| ; Sets a_5BD3 = $FF when input is complete (max length reached after fire). |
| ; |
| ; Inputs: joystick_state, joystick_prev_state, a_5BD1 (max length), |
| ; a_5BD2 (current position), a_5BD7 (char selection index) |
| ; Outputs: a_5BD2 (updated position), a_5BD3 (done flag), a_5BD7 (updated |
| ; char index), a_5BD8 (blink counter reset), f_5BD9 (input buffer) |
| ; Side Effects: Writes selected character to screen via s_5DFF |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| handle_joystick_text_input |
| $5D54 | 20 82 3e | jsrread_joystick; poll joystick ; x-ref: $5CA1 |
| $5D57 | ad 80 3e | ldajoystick_state |
| $5D5A | 29 04 | and#$04; check left direction (bit 2) |
| $5D5C | d0 0a | bneb_5D68 |
| $5D5E | ad 81 3e | ldajoystick_prev_state; was left previously released? |
| $5D61 | 29 04 | and#$04 |
| $5D63 | f0 03 | beqb_5D68 |
| $5D65 | 4c 24 5e | jmpj_5E24; left pressed: backspace |
| $5D68 | ad d2 5b | b_5D68ldainput_char_count; current input position ; x-ref: $5D5C, $5D63 |
| $5D6B | cd d1 5b | cmpinput_max_chars; compare with max length |
| $5D6E | d0 01 | bnehandle_joy_fire_confirm |
| $5D70 | 60 | rts; input buffer full, exit |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| ; Handles joystick fire, up, and down inputs for character selection. |
| ; Fire confirms the selected character and stores it in the buffer. |
| ; Up/Down cycle through the character set (A-Z, 0-9, punctuation). |
| ; Falls through from s_5D54 when buffer is not full. |
| ; |
| ; Inputs: joystick_state, joystick_prev_state, a_5BD7 (selector index) |
| ; Outputs: f_5BD9 (char buffer), a_5BD2 (char count), a_5BD3 (done flag) |
| ; Side Effects: Draws selected character to screen memory |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| handle_joy_fire_confirm |
| $5D71 | ad 80 3e | ldajoystick_state; Fire button pressed? (bit 4) ; x-ref: $5D6E |
| $5D74 | 29 10 | and#$10; check fire button (bit 4) |
| $5D76 | d0 33 | bnehandle_joy_up_prev_char; Fire not pressed, check up/down |
| $5D78 | ad 81 3e | ldajoystick_prev_state; Edge detect: was fire just released? |
| $5D7B | 29 10 | and#$10 |
| $5D7D | f0 2c | beqhandle_joy_up_prev_char; No edge, skip to up/down handler |
| $5D7F | ae d7 5b | ldxinput_selector_idx; Load selector index |
| $5D82 | bd 49 5c | ldachar_selection_table,x; Get char code from selection table |
| $5D85 | ae d2 5b | ldxinput_char_count; Load current buffer position |
| $5D88 | 9d d9 5b | stainput_text_buffer,x; Store confirmed char in buffer |
| $5D8B | 20 ff 5d | jsrdraw_char_at_cursor; Draw char on screen |
| $5D8E | ee d5 5b | incinput_cursor_col; Advance screen column |
| $5D91 | ee d2 5b | incinput_char_count; Advance char count |
| $5D94 | ad d2 5b | ldainput_char_count; Check if buffer full |
| $5D97 | cd d1 5b | cmpinput_max_chars; Compare count to max chars |
| $5D9A | d0 06 | bneb_5DA2 |
| $5D9C | a9 ff | lda#$ff; Set done flag = $FF (input complete) |
| $5D9E | 8d d3 5b | stainput_done_flag; set done flag |
| $5DA1 | 60 | rts |
| $5DA2 | a9 00 | b_5DA2lda#$00; Reset selector to first char (space) ; x-ref: $5D9A |
| $5DA4 | 8d d7 5b | stainput_selector_idx |
| $5DA7 | 8d d8 5b | stainput_blink_counter; Reset blink counter |
| $5DAA | 60 | rts |
| handle_joy_up_prev_char |
| $5DAB | ad 80 3e | ldajoystick_state; Up pressed? (bit 0) ; x-ref: $5D76, $5D7D |
| $5DAE | 29 01 | and#$01; check up direction (bit 0) |
| $5DB0 | d0 17 | bnehandle_joy_down_next_char; Not pressed, check down |
| $5DB2 | ad 81 3e | ldajoystick_prev_state; Edge detect: was up just released? |
| $5DB5 | 29 01 | and#$01 |
| $5DB7 | f0 10 | beqhandle_joy_down_next_char; No edge, check down |
| $5DB9 | ce d7 5b | decinput_selector_idx; Decrement selector index |
| $5DBC | 10 05 | bplb_5DC3 |
| $5DBE | a9 28 | lda#$28; Wrap: 0-1 → 40 ($28) |
| $5DC0 | 8d d7 5b | stainput_selector_idx |
| $5DC3 | a9 00 | b_5DC3lda#$00; Reset blink counter ; x-ref: $5DBC |
| $5DC5 | 8d d8 5b | stainput_blink_counter |
| $5DC8 | 60 | rts |
| handle_joy_down_next_char |
| $5DC9 | ad 80 3e | ldajoystick_state; Down pressed? (bit 1) ; x-ref: $5DB0, $5DB7 |
| $5DCC | 29 02 | and#$02; check down direction (bit 1) |
| $5DCE | d0 1b | bner_5DEB; Not pressed, return |
| $5DD0 | ad 81 3e | ldajoystick_prev_state; Edge detect: was down just released? |
| $5DD3 | 29 02 | and#$02 |
| $5DD5 | f0 14 | beqr_5DEB; No edge, return |
| $5DD7 | ee d7 5b | incinput_selector_idx; Increment selector index |
| $5DDA | ad d7 5b | ldainput_selector_idx; Read back for range check |
| $5DDD | c9 29 | cmp#$29; Wrap: 41 ($29) → 0 |
| $5DDF | d0 05 | bneb_5DE6 |
| $5DE1 | a9 00 | lda#$00 |
| $5DE3 | 8d d7 5b | stainput_selector_idx |
| $5DE6 | a9 00 | b_5DE6lda#$00; Reset blink counter ; x-ref: $5DDF |
| $5DE8 | 8d d8 5b | stainput_blink_counter |
| $5DEB | 60 | r_5DEBrts; x-ref: $5DCE, $5DD5 |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| ; Draws the blinking cursor for the high score name entry. |
| ; If the blink counter is >= 20, it draws a space (blink off). |
| ; Otherwise, it draws the currently selected joystick character, or the default |
| ; cursor character ($1E) if no character is selected (index 0). |
| ; Falls through to `draw_char_at_cursor` to write to screen RAM. |
| ; |
| ; Inputs: input_blink_counter, input_selector_idx |
| ; Outputs: None |
| ; Side Effects: Writes one character to Screen RAM |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| $5DEC | a9 20 | draw_input_cursorlda#$20; Default to space (blink off) ; x-ref: $5C8F |
| $5DEE | ae d8 5b | ldxinput_blink_counter; Load blink counter |
| $5DF1 | e0 14 | cpx#$14; If >= 20, blink is off, draw space |
| $5DF3 | b0 0a | bcsdraw_char_at_cursor |
| $5DF5 | a9 1e | lda#$1e; Otherwise, set char to cursor ($1E) |
| $5DF7 | ae d7 5b | ldxinput_selector_idx; Load joystick selector index |
| $5DFA | f0 03 | beqdraw_char_at_cursor; If 0, draw cursor char |
| $5DFC | bd 49 5c | ldachar_selection_table,x; Else get selected letter |
| ; Draws the character in A at screen position (row=a_5BD6, col=a_5BD5). |
| ; Computes screen address: $0400 + row*40 + col, then stores the character. |
| $5DFF | 48 | draw_char_at_cursorpha; Save char to draw ; x-ref: $5CF6, $5D8B, $5DF3, $5DFA, $5E2B, ... |
| $5E00 | a9 00 | lda#$00; Screen base low = $00 |
| $5E02 | 85 fb | stazp_ptr_src_lo |
| $5E04 | a9 04 | lda#$04; Screen base high = $04 ($0400) |
| $5E06 | 85 fc | stazp_ptr_src_hi |
| $5E08 | ac d6 5b | ldyinput_cursor_row; Y = row number |
| $5E0B | f0 10 | beqb_5E1D; Row 0? Skip multiply |
| $5E0D | a5 fb | b_5E0Dldazp_ptr_src_lo; Add 40 ($28) per row to pointer ; x-ref: $5E1B |
| $5E0F | 18 | clc; Add 40 ($28) per row to base address |
| $5E10 | 69 28 | adc#$28 |
| $5E12 | 85 fb | stazp_ptr_src_lo |
| $5E14 | a5 fc | ldazp_ptr_src_hi |
| $5E16 | 69 00 | adc#$00 |
| $5E18 | 85 fc | stazp_ptr_src_hi |
| $5E1A | 88 | dey; Loop for each row |
| $5E1B | d0 f0 | bneb_5E0D |
| $5E1D | ac d5 5b | b_5E1Dldyinput_cursor_col; Y = column offset ; x-ref: $5E0B |
| $5E20 | 68 | pla; Restore char |
| $5E21 | 91 fb | sta(zp_ptr_src_lo),y; Write char to screen |
| $5E23 | 60 | rts |
| $5E24 | ad d2 5b | j_5E24ldainput_char_count; x-ref: $5CDA, $5D65 |
| $5E27 | f0 16 | beqr_5E3F |
| $5E29 | a9 20 | lda#$20 |
| $5E2B | 20 ff 5d | jsrdraw_char_at_cursor |
| $5E2E | ce d5 5b | decinput_cursor_col |
| $5E31 | 20 ff 5d | jsrdraw_char_at_cursor |
| $5E34 | ce d2 5b | decinput_char_count |
| $5E37 | a9 00 | lda#$00 |
| $5E39 | 8d d7 5b | stainput_selector_idx |
| $5E3C | 8d d8 5b | stainput_blink_counter |
| $5E3F | 60 | r_5E3Frts; x-ref: $5E27 |
| | .encode |
| | .enc"screen" |
| ; Credits screen: role labels ("PROGRAMMING, GRAPHICS, SOUND" / "TESTING" / "EMAIL") |
| $5E40 | | txt_credits_roles.text"PROGRAMMING, GRAPHICS, SOUND", $ff, $ff, $ff, $ff, "TESTING", $ff; x-ref: $5ECE, $5ED2 |
| $5E68 | | .text$ff, $ff, $ff, $ff, $ff, "EMAIL@" |
| ; Credits screen: programmer/tester name "LUCA CARMINATI" |
| $5E73 | | txt_credits_luca.text"LUCA CARMINATI@"; x-ref: $5EE3, $5EE7, $5EF8, $5EFC |
| ; Credits screen: additional names "STEFANO CARMINATI" / "PAOLO CARMINATI" |
| $5E82 | | txt_credits_testers.text"STEFANO CARMINATI", $ff, "PAOLO CARMINATI", $ff, $ff, $ff, $ff, "LUC"; x-ref: $5F0D, $5F11 |
| $5EAA | | .text"ACARMINATI1967$GMAIL.COM@" |
| | .endencode |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| ; Displays the credits/about screen showing programmer, tester, and contact |
| ; information for the Carminati family. Blanks the screen, clears it, then |
| ; draws four text blocks with color: the role labels (cyan) and name strings |
| ; (white). Resets all sprites and re-enables the display via j_3667. |
| ; |
| ; Inputs: None |
| ; Outputs: None |
| ; Side Effects: Screen blanked and cleared, credits text drawn, sprites reset, display re-enabled |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| $5EC3 | a9 05 | show_credits_screenlda#GameState.CREDITS; Set game state = 5 (credits screen) ; x-ref: $1DDF, $6AC1 |
| $5EC5 | 8d d3 20 | stagame_state; game_state = 5 (credits screen) |
| $5EC8 | 20 7e 36 | jsrblank_screen; Blank display before drawing |
| $5ECB | 20 44 36 | jsrclear_screen; Clear screen RAM |
| $5ECE | a9 40 | lda#<txt_credits_roles; Pointer to role labels text at $5E40 |
| $5ED0 | 85 fb | stazp_ptr_src_lo |
| $5ED2 | a9 5e | lda#>txt_credits_roles; Text ptr hi = $5E |
| $5ED4 | 85 fc | stazp_ptr_src_hi |
| $5ED6 | a9 1e | lda#<SCREEN_RAM_R7C6; Screen dest $051E (row 7, col 6) |
| $5ED8 | 85 fd | stazp_ptr_dst_lo |
| $5EDA | a9 05 | lda#>SCREEN_RAM_R7C6; Screen offset hi = $05 -> offset $051E (row 16, col 30) |
| $5EDC | 85 fe | stazp_ptr_dst_hi |
| $5EDE | a9 03 | lda#VicIIColors.CYAN; Color = cyan |
| $5EE0 | 20 a8 36 | jsrdraw_text_with_color; Draw "PROGRAMMING, GRAPHICS, SOUND / TESTING / EMAIL" |
| $5EE3 | a9 73 | lda#<txt_credits_luca; Pointer to "LUCA CARMINATI" text at $5E73 |
| $5EE5 | 85 fb | stazp_ptr_src_lo |
| $5EE7 | a9 5e | lda#>txt_credits_luca; text ptr hi = $5E |
| $5EE9 | 85 fc | stazp_ptr_src_hi |
| $5EEB | a9 46 | lda#<SCREEN_RAM_R8C6; Screen dest $0546 (row 8, col 6) |
| $5EED | 85 fd | stazp_ptr_dst_lo |
| $5EEF | a9 05 | lda#>SCREEN_RAM_R8C6; screen pos hi = $05 → $0546 |
| $5EF1 | 85 fe | stazp_ptr_dst_hi |
| $5EF3 | a9 01 | lda#VicIIColors.WHITE; Color = white |
| $5EF5 | 20 a8 36 | jsrdraw_text_with_color; Draw programmer name |
| $5EF8 | a9 73 | lda#<txt_credits_luca; Reuse "LUCA CARMINATI" pointer |
| $5EFA | 85 fb | stazp_ptr_src_lo |
| $5EFC | a9 5e | lda#>txt_credits_luca; text ptr hi = $5E |
| $5EFE | 85 fc | stazp_ptr_src_hi |
| $5F00 | a9 e6 | lda#<SCREEN_RAM_R12C6; Screen dest $05E6 (row 12, col 6) |
| $5F02 | 85 fd | stazp_ptr_dst_lo |
| $5F04 | a9 05 | lda#>SCREEN_RAM_R12C6; screen pos hi = $05 → $05E6 |
| $5F06 | 85 fe | stazp_ptr_dst_hi; Color = 1 (white) |
| $5F08 | a9 01 | lda#VicIIColors.WHITE; color = 1 (white) |
| $5F0A | 20 a8 36 | jsrdraw_text_with_color; Draw tester name (same person) |
| $5F0D | a9 82 | lda#<txt_credits_testers; Pointer to testers/email text at $5E82 |
| $5F0F | 85 fb | stazp_ptr_src_lo |
| $5F11 | a9 5e | lda#>txt_credits_testers; text ptr hi = $5E |
| $5F13 | 85 fc | stazp_ptr_src_hi |
| $5F15 | a9 0e | lda#<SCREEN_RAM_R13C6; Screen dest $060E (row 13, col 6) |
| $5F17 | 85 fd | stazp_ptr_dst_lo |
| $5F19 | a9 06 | lda#>SCREEN_RAM_R13C6; screen pos hi = $06 → $060E |
| $5F1B | 85 fe | stazp_ptr_dst_hi |
| $5F1D | a9 01 | lda#VicIIColors.WHITE; color = 1 (white) |
| $5F1F | 20 a8 36 | jsrdraw_text_with_color; Draw "STEFANO/PAOLO CARMINATI" + email |
| $5F22 | 20 d5 53 | jsrreset_all_sprites; Clear all sprite positions and enable bits |
| $5F25 | 4c 67 36 | jmpenable_screen; Re-enable screen display |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| ; Polls the joystick port on the credits/game-complete screens to check for a new |
| ; fire button click. |
| ; Ensures the click is a fresh transition (active-low logic: currently pressed (0) |
| ; and previously released ($10)) to filter out button-holding. |
| ; When a new click is registered, transitions back to show_main_menu. |
| ; |
| ; Inputs: joystick_state ($3E80), joystick_prev_state ($3E81) |
| ; Outputs: None |
| ; Side Effects: Jumps to show_main_menu if new fire click is detected |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| wait_for_credits_fire_click |
| $5F28 | ad 80 3e | ldajoystick_state; Read current joystick state ; x-ref: $2137 |
| $5F2B | 29 10 | and#$10; Isolate fire button bit (bit 4) |
| $5F2D | d0 0a | bner_5F39; Active-low: fire released -> abort tick (RTS) |
| $5F2F | ad 81 3e | ldajoystick_prev_state; Read previous frame joystick state |
| $5F32 | 29 10 | and#$10; Isolate previous fire button bit |
| $5F34 | f0 03 | beqr_5F39; Zero = already pressed last frame (hold check), abort |
| $5F36 | 4c 5e 69 | jmpshow_main_menu; New fire click! Return back to main menu |
| $5F39 | 60 | r_5F39rts; Return from screen wait tick ; x-ref: $5F2D, $5F34 |
| | .encode |
| | .enc"screen" |
| ; Congratulations typewriter text: "GREAT JOB!" ... "YOUR FINAL SCORE IS" ... "000000" |
| $5F3A | | game_complete_text.text"^^^^^^^^GREAT JOB!^^^^^^^^", $fe, $ff, $ff; Great job |
| $5F57 | | .text"^WITH YOUR HELP, RODERICK^", $ff; with your help, roderick |
| $5F72 | | .text"^HAS SAVED ALL THE MINERS^", $ff; has saved all the miners |
| $5F8D | | .text"^^^TRAPPED IN THE MOUNT^^^", $ff; trapped in the mount |
| $5FA8 | | .text"^^^^^^^LEONE MINES.^^^^^^^", $fe, $ff, $ff, $ff; leone mines. |
| $5FC6 | | .text"YOU GET 10000 EXTRA POINTS", $ff; you get 10000 extra points |
| $5FE1 | | .text"^^^FOR EACH LIFE LEFT.^^^^", $fe, $ff, $ff, $ff; for each life left |
| $5FFF | | .text"^^^YOUR FINAL SCORE IS^^^^", $fe, $ff, $ff; your final score is |
| $601C | | .text"^^^^^^^^^^000000^^^^^^^^^^@"; 000000 |
| | .endencode |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| ; Displays the game completion screen when all miners have been rescued. |
| ; Adds 10000 bonus points (BCD) per remaining life to the player's score, |
| ; shows a congratulatory typewriter-scrolled message, and prints the final |
| ; score. The text congratulates the player for saving all miners in the |
| ; mount Leone mines. |
| ; |
| ; Inputs: a_50F7 (remaining lives count), score at $50F4-$50F6 (BCD) |
| ; Outputs: Updated score at $50F4-$50F6, screen display |
| ; Side Effects: Blanks and redraws screen, sets color RAM, resets sprites, |
| ; starts typewriter text animation, re-enables display |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| show_game_complete_screen |
| $6037 | a9 06 | lda#GameState.GAME_COMPLETE; game phase = 6 (game complete) ; x-ref: $640A |
| $6039 | 8d d3 20 | stagame_state; game_state = 6 (game complete) |
| $603C | 20 7e 36 | jsrblank_screen |
| $603F | a0 01 | ldy#$01; color index 1 (white) |
| $6041 | 20 44 36 | jsrclear_screen |
| $6044 | a2 27 | show_level_completeldx#$27; 40 columns (0-$27) |
| $6046 | a9 07 | lda#VicIIColors.YELLOW; yellow |
| $6048 | 9d c8 d8 | b_6048staCOLOR_RAM_R5C0,x; Color row 5 = yellow (level complete header) ; x-ref: $604C |
| $604B | ca | dex |
| $604C | 10 fa | bplb_6048 |
| $604E | a2 4f | ldx#$4f; 80 chars (rows 13-14) |
| $6050 | a9 07 | lda#VicIIColors.YELLOW; Yellow |
| $6052 | 9d 08 da | b_6052staCOLOR_RAM_R13C0,x; Color rows 13-14 = yellow (level complete body) ; x-ref: $6056 |
| $6055 | ca | dex |
| $6056 | 10 fa | bplb_6052 |
| $6058 | a2 27 | ldx#$27; Fill 40 chars (1 row) |
| $605A | a9 03 | lda#VicIIColors.CYAN; cyan |
| $605C | 9d a8 da | b_605CstaCOLOR_RAM_R17C0,x; Color row 17 = cyan (score line) ; x-ref: $6060 |
| $605F | ca | dex |
| $6060 | 10 fa | bplb_605C |
| $6062 | 20 d5 53 | jsrreset_all_sprites; Hide all sprites |
| $6065 | ae f7 50 | ldxlives_count; X = remaining lives count |
| $6068 | f8 | b_6068sed; enable BCD mode for score addition ; x-ref: $6084 |
| $6069 | ad f4 50 | ldascore_lo; Score low byte |
| $606C | 18 | clc |
| $606D | 69 00 | adc#$00; Add 100 points (BCD) per dynamite |
| $606F | 8d f4 50 | stascore_lo |
| $6072 | ad f5 50 | ldascore_mid; Score mid byte |
| $6075 | 69 00 | adc#$00; Add 0 (carry propagation) |
| $6077 | 8d f5 50 | stascore_mid |
| $607A | ad f6 50 | ldascore_hi; Score high byte |
| $607D | 69 01 | adc#$01; add $01 to high byte = +10000 BCD per life |
| $607F | 8d f6 50 | stascore_hi |
| $6082 | d8 | cld; back to binary mode |
| $6083 | ca | dex; Loop for each dynamite stick |
| $6084 | d0 e2 | bneb_6068; Loop done; now set up score print pointers |
| $6086 | a9 f4 | lda#$f4; source = score bytes at $50F4 |
| $6088 | 85 fb | stazp_ptr_src_lo |
| $608A | a9 50 | lda#$50; Source ptr hi = $50 |
| $608C | 85 fc | stazp_ptr_src_hi; Ptr to screen score position ($6026) |
| $608E | a9 26 | lda#$26; dest = screen at $6026 (score display area) |
| $6090 | 85 fd | stazp_ptr_dst_lo |
| $6092 | a9 60 | lda#$60 |
| $6094 | 85 fe | stazp_ptr_dst_hi; Dest ptr hi = $60 |
| $6096 | a2 06 | ldx#$06; 6 BCD digits to print |
| $6098 | 20 0e 37 | jsrprint_bcd_number; Render score to screen-code buffer at $6026 |
| $609B | a9 3a | lda#$3a; text ptr = $5F3A (congratulations message) |
| $609D | 85 f5 | stazp_ptr_text_lo |
| $609F | a9 5f | lda#$5f; Text ptr hi = $5F |
| $60A1 | 85 f6 | stazp_ptr_text_hi |
| $60A3 | a9 cf | lda#$cf; screen dest = $04CF (row 5, centered) |
| $60A5 | 85 f7 | stazp_ptr_screen_lo |
| $60A7 | a9 04 | lda#$04; Screen dest hi = $04 |
| $60A9 | 85 f8 | stazp_ptr_screen_hi |
| $60AB | 20 5b 37 | jsrinit_typewriter; Start typewriter text effect |
| $60AE | a2 3c | ldx#$3c; wait 60 frames (~1 second) before starting |
| $60B0 | 20 98 36 | jsrwait_raster_frames |
| $60B3 | 4c 67 36 | jmpenable_screen; re-enable the display |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| ; Updates the typewriter text effect or skips it on fire-button press. |
| ; While the typewriter animation is still running, delegates to update_typewriter. |
| ; Once the typewriter is finished, polls for a fire-button press (rising edge); |
| ; when detected, silences the SID and transitions to the next game phase via j_62A4. |
| ; |
| ; Inputs: joystick_state, joystick_prev_state, typewriter_done_flag |
| ; Outputs: None |
| ; Side Effects: Calls update_all_sfx every frame; may call sid_init and jump to j_62A4 |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| update_typewriter_or_skip |
| $60B6 | 20 3a 1e | jsrupdate_all_sfx; always update sound effects first ; x-ref: $213A |
| $60B9 | ad 58 37 | ldatypewriter_done_flag |
| $60BC | f0 15 | beqb_60D3; 0 = typewriter still running |
| $60BE | ad 80 3e | ldajoystick_state; check joystick fire button (bit 4) |
| $60C1 | 29 10 | and#$10; isolate fire button bit |
| $60C3 | d0 0d | bner_60D2; fire not pressed this frame → wait |
| $60C5 | ad 81 3e | ldajoystick_prev_state; check previous frame's fire state |
| $60C8 | 29 10 | and#$10 |
| $60CA | f0 06 | beqr_60D2; fire was already held → wait (need rising edge) |
| $60CC | 20 15 1e | jsrsid_init; silence all SID voices |
| $60CF | 4c a4 62 | jmpj_62A4; transition to next game phase |
| $60D2 | 60 | r_60D2rts; x-ref: $60C3, $60CA |
| $60D3 | 4c 69 37 | b_60D3jmpupdate_typewriter; continue typewriter animation ; x-ref: $60BC |
| ; Flag: 0 = setup/menu phase, 1 = gameplay active. Guards keyboard input handling. |
| $60D6 | | game_active.byte$00; x-ref: $611F, $6173, $619C, $61B6 |
| ; Menu input mode index (0-3). Cycles through menu options; selects 30-byte option block from f_677D table. |
| $60D7 | | input_mode.byte$00; x-ref: $6A8C, $6A8F, $6A98, $6B58, $802F |
| ; Difficulty mode: 0 = normal (20 levels), 4 = easy (7), 8 = medium (11), 12 = hard (15). Set from menu, determines final level threshold. |
| $60D8 | | difficulty_mode.byte$00; x-ref: $1DB8, $610C, $6169, $6387, $6A82, ... |
| ; Current cave/level index (0-19). Used for cave data lookup, palette selection, enemy speed scaling, and score entries. |
| $60D9 | | current_level.byte$00; x-ref: $1CA3, $49F6, $53B6, $610F, $6379, ... |
| ; Flag: non-zero when a game session is active. Set to $FF on dynamite bonus award. Checked on RUN/STOP to decide whether to save high scores. |
| $60DA | | game_in_progress.byte$00; x-ref: $6114, $6191, $62A9, $63F8 |
| ; Raster synchronization flag. Main loop clears to 0, then busy-waits until the IRQ handler sets it to $FF, ensuring one frame per game tick. |
| $60DB | | frame_sync_flag.byte$00; x-ref: $61C3, $61C6, $64BB |
| ; Level-complete bonus sequence phase counter. 0 = normal play, 1 = energy bonus, 2 = life bonus, 3 = delay before next level. |
| $60DC | | bonus_phase.byte$00; x-ref: $6127, $61F2, $6218, $6221, $6242, ... |
| ; Index (0-7) of the first free VIC-II sprite slot found during sprite sorting. Used to assign sprite pointers. |
| $60DD | | active_sprite_slot.byte$00; x-ref: $64C8, $64D8 |
| ; Multi-purpose: hero Y start position during init ($78/$F0), frame counter during bonus phase 2, delay timer during bonus phase 3, death anim countdown. |
| $60DE | | hero_y_or_timer.byte$00; x-ref: $612C, $6178, $6247, $6259, $625C, ... |
| ; SFX mute toggle. 0 = sound on, $FF = muted. Toggled by F7 key (EOR #$FF). When set, SID volume is zeroed and SFX updates are skipped. |
| $60DF | | sfx_muted.byte$00; x-ref: $6117, $61A7, $61AC, $61CB, $64CB |
| ; HUD tile indices for fuel bar icons (7 bytes, null-terminated) |
| $60E0 | | hud_tiles_fuel_bar.byte$54, $55, $56, $57, $58, $59, $00; x-ref: $62B7, $62BB |
| ; HUD tile indices for status icons row (8 bytes, null-terminated) |
| hud_tiles_status_icons |
| $60E7 | | .byte$64, $65, $66, $67, $68, $69, $6a, $6b; x-ref: $62DF, $62E3 |
| $60EF | | .byte$00 |
| ; HUD tile indices for top status row (dynamite/lives icons) |
| $60F0 | | hud_tiles_row1.byte$6c, $6d, $6e, $6f, $70, $00; x-ref: $6304, $6308 |
| ; HUD tile indices for bottom status row (fuel bar icons) |
| $60F6 | | hud_tiles_row2.byte$71, $72, $73, $74, $75, $76, $77, $78; x-ref: $6319, $631D |
| $60FE | | .byte$00 |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| ; Initializes a new cave/level for gameplay. Blanks the screen, resets the |
| ; score and lives display, loads and decompresses cave map data from banked |
| ; RAM, sets up sprites, clears the screen, configures the raster IRQ for |
| ; the gameplay handler, and re-enables the display. |
| ; j_611D is a re-entry point used when restarting the same cave (e.g. after |
| ; losing a life) — it skips the score/lives reset. |
| ; |
| ; Inputs: a_60D8 = cave/level index to initialize |
| ; Outputs: None |
| ; Side Effects: Screen blanked then re-enabled, sprites configured, cave map |
| ; decompressed, raster IRQ set to gameplay handler at $6492, |
| ; MMU set to $3E (RAM+I/O) |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| $60FF | a9 00 | init_cave_levellda#GameState.GAMEPLAY; clear transition state ; x-ref: $1DBB, $6A85, $6ABB |
| $6101 | 8d d3 20 | stagame_state; game_state = 0 (playing cave) |
| $6104 | 20 7e 36 | jsrblank_screen; turn off VIC-II display |
| $6107 | a9 ff | lda#$ff; mark all cave blocks dirty |
| $6109 | 8d 38 36 | stazero_suppress_disable; Mark all blocks dirty (force full redraw) |
| $610C | ad d8 60 | ldadifficulty_mode; Copy difficulty_mode to current_level as starting level |
| $610F | 8d d9 60 | stacurrent_level |
| $6112 | a9 00 | lda#$00; clear continue flag |
| $6114 | 8d da 60 | stagame_in_progress; Clear game_in_progress flag at level init |
| $6117 | 8d df 60 | stasfx_muted; Clear sfx_muted (sound enabled) |
| $611A | 20 ff 50 | jsrinit_score_and_lives; init score/lives display |
| $611D | a9 00 | j_611Dlda#$00; clear game-active flag (setup phase) ; x-ref: $620B, $6410 |
| $611F | 8d d6 60 | stagame_active; Clear game_active (setup phase) |
| $6122 | 20 7e 36 | jsrblank_screen; blank screen for level setup |
| $6125 | a9 00 | lda#$00; clear scroll counter |
| $6127 | 8d dc 60 | stabonus_phase; Clear bonus_phase (normal play) |
| $612A | a9 78 | lda#$78; init hero Y start position = 120 |
| $612C | 8d de 60 | stahero_y_or_timer; Init hero_y_or_timer to 120 (hero start Y) |
| $612F | a9 06 | lda#$06; set initial fuel/energy = 6 |
| $6131 | 8d 06 7b | stahero_dynamite_count |
| $6134 | 20 3d 78 | jsrinit_dynamite_state; setup cave tilemap renderer |
| $6137 | 20 48 82 | jsrinit_energy; init animation tables |
| $613A | a9 02 | lda#VicIIColors.RED; set multicolor bg1 = red |
| $613C | 8d 22 d0 | sta$d022; Background Color 1, Multi-Color Register 0 |
| $613F | 20 d5 53 | jsrreset_all_sprites; clear all sprite positions/data |
| $6142 | a9 ff | lda#$ff; enable all 8 sprites |
| $6144 | 8d 15 d0 | sta$d015; Sprite display Enable |
| $6147 | 20 f2 53 | jsrinit_sprites; configure sprite frames/colors |
| $614A | a0 0f | ldy#$0f; fill color = light grey |
| $614C | 20 44 36 | jsrclear_screen; clear screen RAM |
| $614F | 20 b7 62 | jsrdraw_hud; draw cave border/HUD layout |
| $6152 | 20 a3 1c | jsrload_cave_data; load compressed cave data from banked RAM |
| $6155 | a9 3e | lda#$3e; MMU = $3E: RAM+I/O (restore after bank switch) |
| $6157 | 8d 00 ff | staMMU_CONFIG; Restore MMU after bank switch; C128: MMU Configuration Register |
| $615A | 20 c9 49 | jsrdecompress_cave_map; expand cave map into screen tiles |
| $615D | a9 05 | lda#$05; raster line 5 for gameplay IRQ |
| $615F | a2 92 | ldx#<irq_gameplay_raster |
| $6161 | a0 64 | ldy#>irq_gameplay_raster; handler at $6492 |
| $6163 | 20 4c 21 | jsrsetup_raster_irq; install gameplay raster IRQ |
| $6166 | 4c 67 36 | jmpenable_screen; enable VIC-II display and return |
| $6169 | ad d8 60 | j_6169ldadifficulty_mode; x-ref: $6211 |
| $616C | f0 03 | beqb_6171 |
| $616E | 4c 5e 69 | jmpshow_main_menu |
| $6171 | a9 01 | b_6171lda#$01; x-ref: $616C |
| $6173 | 8d d6 60 | stagame_active; Set game_active = 1 (gameplay begins) |
| $6176 | a9 f0 | lda#$f0 |
| $6178 | 8d de 60 | stahero_y_or_timer |
| $617B | 60 | rts |
| $617C | 20 09 52 | j_617Cjsrj_5209; x-ref: $620E |
| $617F | 4c 5f 7b | jmpj_7B5F |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| ; The primary game engine loop, executed once per frame. Coordinates keyboard |
| ; checks (RUN/STOP to exit, F7 to toggle audio mute), busy-waits on the |
| ; frame_sync_flag set by the raster IRQ for vertical sync, and updates all gameplay |
| ; systems (physics, hero movement, collisions, energy drain, scrolling, animations). |
| ; Manages transitions on hero death (lives decrement, level restart or game over |
| ; transition) and triggers the step-by-step level complete bonus sequence when the |
| ; hero successfully completes the cave. |
| ; |
| ; Inputs: None |
| ; Outputs: None |
| ; Side Effects: Performs BCD score additions, updates SID registers for SFX, reads |
| ; keyboard row 0, processes transitions to restarts/gameover screens |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| $6182 | ad 0c 3f | game_engine_loopldakb_row0_cur; Read keyboard matrix row 0 ; x-ref: $2114 |
| $6185 | cd 0d 3f | cmpkb_row0_prev; Check if keys changed |
| $6188 | f0 2c | beqb_61B6 |
| $618A | c9 ef | cmp#$ef; RUN/STOP key pressed? |
| $618C | d0 0e | bneb_619C |
| $618E | 20 52 1e | jsrstop_all_music; Silence SID voices before quitting |
| $6191 | ad da 60 | ldagame_in_progress; Check if a game is actively running |
| $6194 | f0 03 | beqjump_to_title_screen |
| $6196 | 20 dd 6e | jsrshow_saving_and_save_scores |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| ; Trampoline to title screen. |
| ; Reached when RUN/STOP is pressed and no game is in progress (a_60DA == 0), |
| ; skipping the high-score save performed by s_6EDD. |
| ; |
| ; Inputs: None |
| ; Outputs: None (does not return) |
| ; Side Effects: Transfers control to j_695E which blanks the screen and |
| ; shows the title/menu. |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| $6199 | 4c 5e 69 | jump_to_title_screenjmpshow_main_menu; Go straight back to title screen menu ; x-ref: $6194 |
| $619C | ae d6 60 | b_619Cldxgame_active; Check if gameplay is active (vs menu/demo) ; x-ref: $618C |
| $619F | d0 15 | bneb_61B6 |
| $61A1 | c9 f7 | cmp#$f7; F7 key pressed (toggle audio)? |
| $61A3 | d0 11 | bneb_61B6 |
| $61A5 | a2 00 | ldx#$00 |
| $61A7 | ad df 60 | ldasfx_muted; Toggle audio mute flag |
| $61AA | 49 ff | eor#$ff |
| $61AC | 8d df 60 | stasfx_muted |
| $61AF | d0 02 | bneb_61B3 |
| $61B1 | a2 0f | ldx#$0f |
| $61B3 | 8e 18 d4 | b_61B3stx$d418; x-ref: $61AF Select Filter Mode and Volume |
| $61B6 | ad d6 60 | b_61B6ldagame_active; Check if gameplay is active ; x-ref: $6188, $619F, $61A3 |
| $61B9 | d0 03 | bneb_61BE; Demo/Game-Over mode active -> JMP to animation |
| $61BB | 4c c1 61 | jmpj_61C1 |
| $61BE | 4c 95 62 | b_61BEjmpupdate_game_over_or_demo; x-ref: $61B9 |
| $61C1 | a9 00 | j_61C1lda#$00; Gameplay active: clear IRQ sync flag ; x-ref: $61BB |
| $61C3 | 8d db 60 | staframe_sync_flag; Clear frame_sync_flag (wait for next IRQ) |
| $61C6 | ad db 60 | b_61C6ldaframe_sync_flag; Busy-wait for raster IRQ to set frame_sync_flag ; x-ref: $61C9 |
| $61C9 | f0 fb | beqb_61C6 |
| $61CB | ad df 60 | ldasfx_muted |
| $61CE | f0 01 | beqb_61D1; Update player scores and level stats |
| $61D0 | 60 | rts |
| $61D1 | 20 2f 51 | b_61D1jsrupdate_score_and_lives; Animate water characters ; x-ref: $61CE |
| $61D4 | 20 20 7a | jsrupdate_water_animation; Tick player character physics & inputs |
| $61D7 | 20 9b 7b | jsrupdate_hero_state_machine; Check player-placed dynamite collisions |
| $61DA | 20 4b 78 | jsrupdate_dynamite_collision; Process active explosion animations |
| $61DD | 20 19 6f | jsrupdate_explosion; Tick global animated level elements |
| $61E0 | 20 a5 73 | jsrupdate_all_tiles; Scroll specific level backgrounds |
| $61E3 | 20 fa 82 | jsrupdate_tile13_scroll; Animate interactive raft structures |
| $61E6 | 20 c8 84 | jsrupdate_raft_animation; Drain player energy meter over time |
| $61E9 | 20 67 82 | jsrupdate_energy_drain; Check if player touched enemies/hazards |
| $61EC | 20 70 1e | jsrcheck_hero_collisions; Assign updated player sprite pointers |
| $61EF | 20 42 81 | jsrselect_hero_sprite_ptr; Is the level complete bonus sequence active? |
| $61F2 | ad dc 60 | ldabonus_phase; Phase 0: evaluate player/game status |
| $61F5 | f0 03 | beqb_61FA; Phase 0: check game status |
| $61F7 | 4c 21 62 | jmpupdate_level_complete_bonus; Get hero current status flag |
| $61FA | ad fa 7a | b_61FAldahero_state; Did the hero die? ; x-ref: $61F5 |
| $61FD | c9 05 | cmp#$05; Status $05 = hero died? |
| $61FF | d0 13 | bneb_6214 |
| $6201 | ce f7 50 | declives_count; No lives left -> trigger Game Over |
| $6204 | f0 0b | beqb_6211; No lives left -> game over |
| $6206 | ad 1b 82 | ldaenergy_level; Check remaining energy after death |
| $6209 | d0 03 | bneb_620E; Energy > 0: restart with score bonus |
| $620B | 4c 1d 61 | jmpj_611D; Restart cave with score compensation |
| $620E | 4c 7c 61 | b_620Ejmpj_617C; Trigger Game Over sequence ; x-ref: $6209 |
| $6211 | 4c 69 61 | b_6211jmpj_6169; Is the cave successfully completed? ; x-ref: $6204 |
| $6214 | c9 03 | b_6214cmp#$03; x-ref: $61FF |
| $6216 | d0 08 | bner_6220; Status $03 = level complete? |
| $6218 | ee dc 60 | incbonus_phase; Begin death/bonus phase 1 |
| $621B | a9 01 | lda#$01 |
| $621D | 8d 9d 8a | stasfx_ch5_state; Set SFX trigger flag |
| $6220 | 60 | r_6220rts; x-ref: $6216 |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| ; Processes the three-phase level completion bonus sequence. |
| ; Phase 1 drains the remaining player energy, adding BCD score points per tick and |
| ; playing a sound chime. |
| ; Phase 2 drains the remaining dynamite stock, adding larger BCD score bonuses per |
| ; unit. |
| ; Phase 3 introduces a short delay timer before transitioning to the next cave layout |
| ; via advance_level. |
| ; |
| ; Inputs: None |
| ; Outputs: None |
| ; Side Effects: Modifies energy_level, hero_dynamite_count, and adds BCD bonuses |
| ; to score. Modifies SID voice registers |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| update_level_complete_bonus |
| $6221 | ad dc 60 | ldabonus_phase; Phase 1: check current phase ; x-ref: $61F7 |
| $6224 | c9 01 | cmp#$01 |
| $6226 | d0 25 | bneb_624D; Phase != 1: skip to phase 2 check |
| $6228 | ad 1b 82 | ldaenergy_level; Check energy for level-complete bonus |
| $622B | f0 15 | beqb_6242; Energy depleted -> advance phase |
| $622D | ce 1b 82 | decenergy_level; Convert remaining energy to score bonus |
| $6230 | 20 8e 82 | jsrupdate_energy_bar_display |
| $6233 | a9 40 | lda#$40; Score += $0040 (energy bonus) |
| $6235 | 85 fb | stazp_ptr_src_lo |
| $6237 | a9 00 | lda#$00 |
| $6239 | 85 fc | stazp_ptr_src_hi |
| $623B | a9 00 | lda#$00 |
| $623D | 85 fd | stazp_ptr_dst_lo |
| $623F | 4c d8 51 | jmpj_51D8; Add to BCD score |
| $6242 | ee dc 60 | b_6242incbonus_phase; Phase 2: advance phase counter ; x-ref: $622B |
| $6245 | a9 00 | lda#$00; Clear animation frame counter |
| $6247 | 8d de 60 | stahero_y_or_timer |
| $624A | 4c e7 8a | jmpstop_sfx_ch5; Stop SFX (SID voice 1 off) |
| $624D | ad dc 60 | b_624Dldabonus_phase; Phase 2: check current phase ; x-ref: $6226 |
| $6250 | c9 02 | cmp#$02 |
| $6252 | d0 38 | bneb_628C; Phase != 2: skip to phase 3 |
| $6254 | ad 06 7b | ldahero_dynamite_count; Check remaining lives for bonus |
| $6257 | f0 2a | beqb_6283; No lives left -> advance phase |
| $6259 | ee de 60 | inchero_y_or_timer; Increment frame counter |
| $625C | ad de 60 | ldahero_y_or_timer |
| $625F | c9 0d | cmp#$0d; Every 13 frames: award one life bonus |
| $6261 | d0 1f | bner_6282 |
| $6263 | a9 00 | lda#$00 |
| $6265 | 8d de 60 | stahero_y_or_timer |
| $6268 | 20 5f 63 | jsrclear_last_dynamite_icon; Erase life icon from status bar |
| $626B | ce 06 7b | dechero_dynamite_count; Decrement remaining lives display |
| $626E | a9 50 | lda#$50; Score += $0050 (life bonus) |
| $6270 | 85 fb | stazp_ptr_src_lo |
| $6272 | a9 00 | lda#$00 |
| $6274 | 85 fc | stazp_ptr_src_hi |
| $6276 | a9 00 | lda#$00 |
| $6278 | 85 fd | stazp_ptr_dst_lo |
| $627A | 20 d8 51 | jsrj_51D8; Add to BCD score |
| $627D | a9 01 | lda#$01; Set score-changed flag |
| $627F | 8d ec 88 | stasfx_hit_state; Trigger hit SFX on Voice 3 |
| $6282 | 60 | r_6282rts; x-ref: $6261 |
| $6283 | ee dc 60 | b_6283incbonus_phase; Advance to phase 3 ; x-ref: $6257 |
| $6286 | a9 5a | lda#$5a; Set phase 3 delay timer ($5A frames) |
| $6288 | 8d de 60 | stahero_y_or_timer |
| $628B | 60 | rts |
| $628C | ce de 60 | b_628Cdechero_y_or_timer; Phase 3: decrement delay timer ; x-ref: $6252 |
| $628F | d0 03 | bner_6294 |
| $6291 | 4c 87 63 | jmpadvance_level; Timer done -> advance to next level |
| $6294 | 60 | r_6294rts; x-ref: $628F |
| update_game_over_or_demo |
| $6295 | 20 20 7a | jsrupdate_water_animation; x-ref: $61BE |
| $6298 | 20 a5 73 | jsrupdate_all_tiles |
| $629B | 20 c8 84 | jsrupdate_raft_animation |
| $629E | ce de 60 | dechero_y_or_timer |
| $62A1 | f0 01 | beqj_62A4 |
| $62A3 | 60 | rts |
| $62A4 | 20 3b 53 | j_62A4jsrinsert_high_score; x-ref: $60CF, $62A1 |
| $62A7 | 10 0b | bplb_62B4 |
| $62A9 | ad da 60 | ldagame_in_progress |
| $62AC | f0 03 | beqb_62B1 |
| $62AE | 20 dd 6e | jsrshow_saving_and_save_scores |
| $62B1 | 4c 5e 69 | b_62B1jmpshow_main_menu; x-ref: $62AC |
| $62B4 | 4c 3e 6d | b_62B4jmpinit_high_score_screen; x-ref: $62A7 |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| ; Draws the static HUD (Heads-Up Display) layout onto the screen. |
| ; Sets up the text, icons (dynamite, fuel bar, year/logo), and their colors. |
| ; Calls subroutines to draw dynamic HUD elements like score, lives, and dynamite counts. |
| ; |
| ; Inputs: None |
| ; Outputs: None |
| ; Side Effects: Extensively modifies Screen RAM and Color RAM |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| $62B7 | a9 e0 | draw_hudlda#<hud_tiles_fuel_bar; Source = $60E0 ; x-ref: $614F |
| $62B9 | 85 fb | stazp_ptr_src_lo |
| $62BB | a9 60 | lda#>hud_tiles_fuel_bar |
| $62BD | 85 fc | stazp_ptr_src_hi |
| $62BF | a9 d1 | lda#<SCREEN_RAM_R18C1; Destination = $06D1 |
| $62C1 | 85 fd | stazp_ptr_dst_lo |
| $62C3 | a9 06 | lda#>SCREEN_RAM_R18C1 |
| $62C5 | 85 fe | stazp_ptr_dst_hi |
| $62C7 | a9 01 | lda#VicIIColors.WHITE; Draw text in White (1) |
| $62C9 | 20 a8 36 | jsrdraw_text_with_color |
| $62CC | 20 a0 82 | jsrfill_energy_bar; Draw player score |
| $62CF | 20 09 52 | jsrj_5209; Draw player lives |
| $62D2 | a2 0e | ldx#$0e; Set Color RAM for row 20 to White |
| $62D4 | a9 01 | lda#VicIIColors.WHITE |
| $62D6 | 9d 25 db | b_62D6staCOLOR_RAM_R20C5,x; Set HUD color row 20 = white ; x-ref: $62DA |
| $62D9 | ca | dex |
| $62DA | 10 fa | bplb_62D6 |
| $62DC | 20 49 63 | jsrdraw_dynamite_stock; Draw dynamite stock |
| $62DF | a9 e7 | lda#<hud_tiles_status_icons; Source = $60E7 |
| $62E1 | 85 fb | stazp_ptr_src_lo |
| $62E3 | a9 60 | lda#>hud_tiles_status_icons |
| $62E5 | 85 fc | stazp_ptr_src_hi |
| $62E7 | a9 74 | lda#<SCREEN_RAM_R22C4; Destination = $0774 |
| $62E9 | 85 fd | stazp_ptr_dst_lo |
| $62EB | a9 07 | lda#>SCREEN_RAM_R22C4 |
| $62ED | 85 fe | stazp_ptr_dst_hi |
| $62EF | a9 07 | lda#VicIIColors.YELLOW; Draw text in Yellow (7) |
| $62F1 | 20 a8 36 | jsrdraw_text_with_color |
| $62F4 | 20 6f 63 | jsrdraw_level_number |
| $62F7 | 20 f4 51 | jsrdraw_score; Update score display |
| $62FA | a2 0b | ldx#$0b |
| $62FC | a9 01 | lda#VicIIColors.WHITE; Set Color RAM for row 22 to White |
| $62FE | 9d 88 db | b_62FEstaCOLOR_RAM_R22C24,x; Set HUD color row 22 = white ; x-ref: $6302 |
| $6301 | ca | dex |
| $6302 | 10 fa | bplb_62FE |
| $6304 | a9 f0 | lda#<hud_tiles_row1; Draw dynamite icons (row 1) |
| $6306 | 85 fb | stazp_ptr_src_lo |
| $6308 | a9 60 | lda#>hud_tiles_row1 |
| $630A | 85 fc | stazp_ptr_src_hi |
| $630C | a9 c1 | lda#<SCREEN_RAM_R24C1 |
| $630E | 85 fd | stazp_ptr_dst_lo |
| $6310 | a9 07 | lda#>SCREEN_RAM_R24C1 |
| $6312 | 85 fe | stazp_ptr_dst_hi |
| $6314 | a9 01 | lda#VicIIColors.WHITE |
| $6316 | 20 a8 36 | jsrdraw_text_with_color |
| $6319 | a9 f6 | lda#<hud_tiles_row2; Draw fuel bar (row 2) |
| $631B | 85 fb | stazp_ptr_src_lo |
| $631D | a9 60 | lda#>hud_tiles_row2 |
| $631F | 85 fc | stazp_ptr_src_hi |
| $6321 | a9 d0 | lda#<SCREEN_RAM_R24C16 |
| $6323 | 85 fd | stazp_ptr_dst_lo |
| $6325 | a9 07 | lda#>SCREEN_RAM_R24C16 |
| $6327 | 85 fe | stazp_ptr_dst_hi |
| $6329 | a9 01 | lda#VicIIColors.WHITE |
| $632B | 20 a8 36 | jsrdraw_text_with_color |
| $632E | a9 09 | lda#<hud_year_and_logo; Draw copyright year and logo |
| $6330 | 85 fb | stazp_ptr_src_lo |
| $6332 | a9 68 | lda#>hud_year_and_logo |
| $6334 | 85 fc | stazp_ptr_src_hi |
| $6336 | a9 e3 | lda#<SCREEN_RAM_R24C35 |
| $6338 | 85 fd | stazp_ptr_dst_lo |
| $633A | a9 07 | lda#>SCREEN_RAM_R24C35 |
| $633C | 85 fe | stazp_ptr_dst_hi |
| $633E | a9 01 | lda#VicIIColors.WHITE |
| $6340 | 20 a8 36 | jsrdraw_text_with_color |
| $6343 | a9 03 | lda#VicIIColors.CYAN; Set color of logo/year to Cyan (3) |
| $6345 | 8d c1 db | staCOLOR_RAM_R24C1; Set single color cell row 24 col 1 = cyan |
| $6348 | 60 | rts |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| ; Draws the player's current stock of dynamite onto the HUD. |
| ; The icons are constructed using two characters ($62 top, $63 bottom). |
| ; Loops from `hero_dynamite_count * 2 - 2` down to 0, writing to screen RAM. |
| ; |
| ; Inputs: hero_dynamite_count |
| ; Outputs: None |
| ; Side Effects: Modifies Screen RAM (dynamite icon area) |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| $6349 | ad 06 7b | draw_dynamite_stockldahero_dynamite_count; Load number of dynamites ; x-ref: $62DC |
| $634C | 0a | asla; Multiply by 2 (2 bytes per icon width) |
| $634D | aa | tax |
| $634E | ca | dex; Adjust for 0-based index |
| $634F | ca | dex |
| $6350 | a9 62 | b_6350lda#$62; Top half character ($62) ; x-ref: $635C |
| $6352 | 9d 11 07 | staSCREEN_RAM_R19C25,x |
| $6355 | a9 63 | lda#$63; Bottom half character ($63) |
| $6357 | 9d 39 07 | staSCREEN_RAM_R20C25,x |
| $635A | ca | dex; Move left to next icon slot |
| $635B | ca | dex |
| $635C | 10 f2 | bplb_6350; Loop until all icons drawn |
| $635E | 60 | rts |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| ; Erases the right-most dynamite icon on the HUD by overwriting both its top |
| ; and bottom halves with spaces ($20). Called when the player uses a dynamite. |
| ; |
| ; Inputs: hero_dynamite_count (before decrement) |
| ; Outputs: None |
| ; Side Effects: Modifies Screen RAM to clear one icon |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| clear_last_dynamite_icon |
| $635F | ad 06 7b | ldahero_dynamite_count; Load current dynamite count ; x-ref: $6268, $7C45 |
| $6362 | 0a | asla |
| $6363 | aa | tax |
| $6364 | ca | dex |
| $6365 | ca | dex |
| $6366 | a9 20 | lda#$20; Space character ($20) |
| $6368 | 9d 11 07 | staSCREEN_RAM_R19C25,x; Clear top half of icon |
| $636B | 9d 39 07 | staSCREEN_RAM_R20C25,x; Clear bottom half of icon |
| $636E | 60 | rts |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| ; Draws the current level number onto the HUD. |
| ; The level is stored 0-based internally, so it adds 1 before displaying. |
| ; Determines if the level is 1 or 2 digits and passes this count in X to |
| ; the binary-to-decimal rendering routine at $6413. |
| ; |
| ; Inputs: current_level |
| ; Outputs: None |
| ; Side Effects: Modifies Screen RAM via the draw routine at $6413 |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| $636F | a9 7c | draw_level_numberlda#<SCREEN_RAM_R22C12; Set destination = $077C (after \"LEVEL \" text) ; x-ref: $62F4 |
| $6371 | 85 fd | stazp_ptr_dst_lo |
| $6373 | a9 07 | lda#>SCREEN_RAM_R22C12 |
| $6375 | 85 fe | stazp_ptr_dst_hi |
| $6377 | a2 01 | ldx#$01; Default to 1 digit |
| $6379 | ad d9 60 | ldacurrent_level; Load current level (0-based) |
| $637C | 18 | clc |
| $637D | 69 01 | adc#$01; Add 1 for display |
| $637F | c9 0a | cmp#$0a; Is it >= 10? |
| $6381 | 90 01 | bccb_6384; If < 10, skip to draw |
| $6383 | e8 | inx; Set to 2 digits |
| $6384 | 4c 13 64 | b_6384jmpj_6413; Jump to binary-to-decimal draw routine ; x-ref: $6381 |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| ; Advances to the next level after completing the current one. |
| ; Checks difficulty mode (a_60D8) to determine the final level threshold: |
| ; mode 4 → ends at level 7, mode 8 → level 11, mode 12 → level 15, default → level 19. |
| ; If the threshold is reached, jumps to the game-over/completion screen (j_695E). |
| ; In mode 0, awards an extra dynamite (a_52C5) at levels 3, 7, 11, and 15 if |
| ; the player has not yet reached the corresponding bonus count. |
| ; At level 19 in mode 0, wraps the level counter and jumps to bonus scoring (j_6037). |
| ; Otherwise increments the level counter and continues to level initialization (j_611D). |
| ; |
| ; Inputs: a_60D8 (difficulty mode), a_60D9 (current level), a_52C5 (dynamite bonus count) |
| ; Outputs: a_60D9 (updated level), a_60DA (extra-dynamite flag), a_52C5 (updated bonus count) |
| ; Side Effects: May transition to completion screen, bonus screen, or next level init |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| $6387 | ad d8 60 | advance_levelldadifficulty_mode; load difficulty mode ; x-ref: $6291 |
| $638A | f0 34 | beqb_63C0; mode 0 → check dynamite bonuses |
| $638C | c9 04 | cmp#$04; mode == 4? |
| $638E | d0 0a | bneb_639A |
| $6390 | ad d9 60 | ldacurrent_level; load current level |
| $6393 | c9 07 | cmp#$07; reached level 7? (final for mode 4) |
| $6395 | d0 76 | bneb_640D |
| $6397 | 4c 5e 69 | jmpshow_main_menu; all levels done → completion screen |
| $639A | c9 08 | b_639Acmp#$08; mode == 8? ; x-ref: $638E |
| $639C | d0 0a | bneb_63A8 |
| $639E | ad d9 60 | ldacurrent_level; load current level |
| $63A1 | c9 0b | cmp#$0b; reached level 11? (final for mode 8) |
| $63A3 | d0 68 | bneb_640D |
| $63A5 | 4c 5e 69 | jmpshow_main_menu |
| $63A8 | c9 0c | b_63A8cmp#$0c; mode == 12? ; x-ref: $639C |
| $63AA | d0 0a | bneb_63B6 |
| $63AC | ad d9 60 | ldacurrent_level; load current level |
| $63AF | c9 0f | cmp#$0f; reached level 15? (final for mode 12) |
| $63B1 | d0 5a | bneb_640D |
| $63B3 | 4c 5e 69 | jmpshow_main_menu |
| $63B6 | ad d9 60 | b_63B6ldacurrent_level; default: load current level ; x-ref: $63AA |
| $63B9 | c9 13 | cmp#$13; reached level 19? (final for default) |
| $63BB | d0 50 | bneb_640D |
| $63BD | 4c 5e 69 | jmpshow_main_menu |
| $63C0 | ad d9 60 | b_63C0ldacurrent_level; mode 0: load current level ; x-ref: $638A |
| $63C3 | c9 03 | cmp#$03; level 3? |
| $63C5 | d0 08 | bneb_63CF |
| $63C7 | ad c5 52 | ldamax_unlocked_level; check dynamite bonus count |
| $63CA | 30 2a | bmib_63F6; count < 0 → award extra dynamite |
| $63CC | 4c 0d 64 | jmpb_640D |
| $63CF | c9 07 | b_63CFcmp#$07; level 7? ; x-ref: $63C5 |
| $63D1 | d0 0a | bneb_63DD |
| $63D3 | ad c5 52 | ldamax_unlocked_level; check dynamite bonus count |
| $63D6 | c9 01 | cmp#$01; count < 1 → award extra |
| $63D8 | 30 1c | bmib_63F6 |
| $63DA | 4c 0d 64 | jmpb_640D |
| $63DD | c9 0b | b_63DDcmp#$0b; level 11? ; x-ref: $63D1 |
| $63DF | d0 0a | bneb_63EB |
| $63E1 | ad c5 52 | ldamax_unlocked_level; check dynamite bonus count |
| $63E4 | c9 02 | cmp#$02; count < 2 → award extra |
| $63E6 | 30 0e | bmib_63F6 |
| $63E8 | 4c 0d 64 | jmpb_640D |
| $63EB | c9 0f | b_63EBcmp#$0f; level 15? ; x-ref: $63DF |
| $63ED | d0 12 | bneb_6401 |
| $63EF | ad c5 52 | ldamax_unlocked_level; check dynamite bonus count |
| $63F2 | c9 03 | cmp#$03; count >= 3 → skip award |
| $63F4 | 10 17 | bplb_640D |
| $63F6 | a9 ff | b_63F6lda#$ff; flag: extra dynamite awarded this level ; x-ref: $63CA, $63D8, $63E6 |
| $63F8 | 8d da 60 | stagame_in_progress; set extra-dynamite flag |
| $63FB | ee c5 52 | incmax_unlocked_level; increment dynamite bonus count |
| $63FE | 4c 0d 64 | jmpb_640D |
| $6401 | c9 13 | b_6401cmp#$13; level 19? ; x-ref: $63ED |
| $6403 | d0 08 | bneb_640D |
| $6405 | a9 ff | lda#$ff; wrap level counter to $FF (→ 0 after inc) |
| $6407 | 8d d9 60 | stacurrent_level; store wrapped level |
| $640A | 4c 37 60 | jmpshow_game_complete_screen; go to bonus/score display |
| $640D | ee d9 60 | b_640Dinccurrent_level; advance to next level number ; x-ref: $6395, $63A3, $63B1, $63BB, $63CC, ... |
| $6410 | 4c 1d 61 | jmpj_611D; continue to level initialization |
| $6413 | 86 ff | j_6413stxzp_temp; x-ref: $6384 |
| $6415 | a0 3f | ldy#$3f |
| $6417 | a2 4a | ldx#$4a |
| $6419 | 38 | sec |
| $641A | c8 | b_641Ainy; x-ref: $641D |
| $641B | e9 64 | sbc#$64 |
| $641D | b0 fb | bcsb_641A |
| $641F | ca | b_641Fdex; x-ref: $6422 |
| $6420 | 69 0a | adc#$0a |
| $6422 | 30 fb | bmib_641F |
| $6424 | 69 3f | adc#$3f |
| $6426 | 8d 30 36 | stabcd_digit_buffer |
| $6429 | 8e 31 36 | stxbcd_digit_tens; Tens digit of BCD conversion result (ASCII) |
| $642C | 8c 32 36 | stybcd_digit_hundreds; Hundreds digit of BCD conversion result (ASCII) |
| $642F | 4c 57 64 | jmpj_6457 |
| $6432 | 86 ff | j_6432stxzp_temp; x-ref: $5206 |
| $6434 | a0 00 | ldy#$00 |
| $6436 | a2 00 | ldx#$00 |
| $6438 | b1 fb | b_6438lda(zp_ptr_src_lo),y; x-ref: $6455 |
| $643A | 29 0f | and#$0f |
| $643C | 09 40 | ora#$40 |
| $643E | 9d 30 36 | stabcd_digit_buffer,x |
| $6441 | e8 | inx |
| $6442 | e4 ff | cpxzp_temp |
| $6444 | f0 11 | beqj_6457 |
| $6446 | b1 fb | lda(zp_ptr_src_lo),y |
| $6448 | 4a | lsra |
| $6449 | 4a | lsra |
| $644A | 4a | lsra |
| $644B | 4a | lsra |
| $644C | 09 40 | ora#$40 |
| $644E | 9d 30 36 | stabcd_digit_buffer,x |
| $6451 | c8 | iny |
| $6452 | e8 | inx |
| $6453 | e4 ff | cpxzp_temp |
| $6455 | d0 e1 | bneb_6438 |
| $6457 | a0 00 | j_6457ldy#$00; x-ref: $642F, $6444 |
| $6459 | a6 ff | ldxzp_temp |
| $645B | ca | dex |
| $645C | f0 0c | beqb_646A |
| $645E | bd 30 36 | b_645Eldabcd_digit_buffer,x; x-ref: $6468 |
| $6461 | c9 40 | cmp#$40 |
| $6463 | d0 08 | bneb_646D |
| $6465 | c8 | iny |
| $6466 | c8 | iny |
| $6467 | ca | dex |
| $6468 | d0 f4 | bneb_645E |
| $646A | bd 30 36 | b_646Aldabcd_digit_buffer,x; x-ref: $645C, $6477 |
| $646D | 91 fd | b_646Dsta(zp_ptr_dst_lo),y; x-ref: $6463 |
| $646F | c8 | iny |
| $6470 | 18 | clc |
| $6471 | 69 0a | adc#$0a |
| $6473 | 91 fd | sta(zp_ptr_dst_lo),y |
| $6475 | c8 | iny |
| $6476 | ca | dex |
| $6477 | 10 f1 | bplb_646A |
| $6479 | 60 | rts |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| ; Collects sprite data for all game objects (hero, creatures, projectile, |
| ; bomb, and hazard sprites) by calling each object's sprite setup routine, |
| ; then jumps to the sprite sort-and-render multiplexer at j_540A. |
| ; |
| ; Each sub-call populates zero-page arrays ($33-$36 visibility flags, |
| ; $46-$49 Y positions, $59-$5C Y hi-bytes, $6F-$70 sprite frames, |
| ; $7E-$83 sprite colors, $91 sprite width) used by the multiplexer. |
| ; |
| ; Inputs: None (reads game state from each object module) |
| ; Outputs: None (sprite data written to zero-page arrays) |
| ; Side Effects: VIC-II sprite registers programmed via j_540A |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| update_and_sort_sprites |
| $647A | 20 6f 70 | jsrsetup_explosion_sprite; Setup hero sprite position and frame ; x-ref: $64B6 |
| $647D | 20 83 77 | jsrsetup_entity_sprites; Setup creature sprites (up to N enemies) |
| $6480 | 20 fd 77 | jsrsetup_hazard_sprite; Setup projectile/laser sprite |
| $6483 | 20 cf 7a | jsrsetup_tile14_sprite; Setup hazard/obstacle sprite |
| $6486 | 20 a8 81 | jsrsetup_bomb_sprite; Setup bomb/dynamite sprite |
| $6489 | 20 20 79 | jsrsetup_fire_sprite; Setup secondary enemy sprite |
| $648C | 20 78 83 | jsrsetup_tile13_sprite; Setup extra game object sprite |
| $648F | 4c 0a 54 | jmpj_540A; Sort sprites by Y and program VIC-II |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| ; Gameplay raster IRQ handler (triggered at raster line 5). Configures the |
| ; VIC-II display for the game viewport: sets background/multicolor colors |
| ; (with explosion flash override), selects character memory at $3800 and |
| ; screen at $0400, enables ECM mode. Then updates all sprite data, finds |
| ; a free sprite slot for the score overlay, conditionally ticks SFX, and |
| ; jumps into the sprite multiplexer chain. |
| ; |
| ; Inputs: explosion_state, explosion_color, a_3FA2 (multicolor), a_60DF (sfx mute flag) |
| ; Outputs: a_60DB (set to $FF), a_60DD (free sprite slot index) |
| ; Side Effects: VIC-II registers ($D011, $D018, $D021, $D023) programmed; |
| ; sprites updated; sound effects ticked |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| $6492 | a9 00 | irq_gameplay_rasterlda#$00; default bg = black ; x-ref: $615F, $6161, $654B, $654D |
| $6494 | ae 01 6f | ldxexplosion_state; check if explosion active |
| $6497 | e0 02 | cpx#$02; State 2 = exploding? |
| $6499 | d0 03 | bneb_649E; skip: use explosion flash color |
| $649B | ad 06 6f | ldaexplosion_color; load explosion flash color |
| $649E | 8d 21 d0 | b_649Esta$d021; set screen background color ; x-ref: $6499 Background Color 0 |
| $64A1 | a9 1e | lda#$1e; char mem=$3800, screen=$0400 |
| $64A3 | 8d 18 d0 | sta$d018; VIC Memory Control Register |
| $64A6 | ad 11 d0 | lda$d011; read current VIC control; VIC Control Register 1 |
| $64A9 | 29 f8 | and#$f8; clear YSCROLL bits 0-2 |
| $64AB | 09 40 | ora#$40; enable ECM (bit 6) |
| $64AD | 8d 11 d0 | sta$d011; apply display mode; VIC Control Register 1 |
| $64B0 | ad a2 3f | ldalevel_color_multicolor; load multicolor value; VIC-II ECM multicolor value ($D023) for the level |
| $64B3 | 8d 23 d0 | sta$d023; set multicolor register 1; Background Color 2, Multi-Color Register 1 |
| $64B6 | 20 7a 64 | jsrupdate_and_sort_sprites; Collect & sort all game sprites |
| $64B9 | a9 ff | lda#$ff; mark all sprite slots as used |
| $64BB | 8d db 60 | staframe_sync_flag; IRQ: signal frame complete to main loop |
| $64BE | a2 13 | ldx#$13; start from slot 19 |
| $64C0 | ca | b_64C0dex; Scan zp array backward for active sprite ; x-ref: $64C3 |
| $64C1 | b5 20 | ldazpf_sort_order,x; search downward for free slot |
| $64C3 | d0 fb | bneb_64C0; Loop until non-zero (active) found |
| $64C5 | 8a | txa; keep low 3 bits (VIC sprite index 0-7) |
| $64C6 | 29 07 | and#$07; Mask to 0-7 (sprite slot) |
| $64C8 | 8d dd 60 | staactive_sprite_slot; Load active_sprite_slot for pointer assignment |
| $64CB | ad df 60 | ldasfx_muted; check if SFX muted |
| $64CE | d0 03 | bneb_64D3; skip SFX update if muted |
| $64D0 | 20 3a 1e | jsrupdate_all_sfx; tick all sound effects |
| $64D3 | 4c 1a 56 | b_64D3jmpj_561A; continue to sprite multiplexer chain ; x-ref: $64CE |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| ; End-of-sprite-mux raster IRQ handler. |
| ; Called when all multiplexed sprites have been displayed. Sets the HUD |
| ; sprite pointer for the last active sprite slot, then chains to |
| ; irq_raster_set_bg_colors at raster line $B6 to apply the gameplay |
| ; color split. |
| ; |
| ; Inputs: active_sprite_slot = index of the current sprite slot |
| ; Outputs: None |
| ; Side Effects: Sets sprite pointer for active slot, chains IRQ to $64E7 |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| $64D6 | a9 89 | irq_end_sprite_muxlda#$89; HUD sprite pointer value ($89) ; x-ref: $5AAC, $5AAE |
| $64D8 | ae dd 60 | ldxactive_sprite_slot; Get current multiplexer slot index |
| $64DB | 9d f8 07 | staSPRITE_PTR_0,x; Set sprite pointer for this slot |
| $64DE | a9 b6 | lda#$b6; Next raster at $B6 |
| $64E0 | a2 e7 | ldx#<irq_raster_set_bg_colors; Load high byte of raster color-set handler |
| $64E2 | a0 64 | ldy#>irq_raster_set_bg_colors; Chain to next raster IRQ (color-set handler) |
| $64E4 | 4c 7c 21 | jmpirq_chain_next; Chain to irq_raster_set_bg_colors |
| ; Raster IRQ handler: waits with NOPs for stable raster, then sets |
| ; background color 0 and multicolor register 1 to dark grey ($0B). |
| ; Chained from gameplay IRQ at raster line $B6. |
| irq_raster_set_bg_colors |
| $64E7 | ea | nop; x-ref: $64E0, $64E2 |
| $64E8 | ea | nop |
| $64E9 | ea | nop |
| $64EA | ea | nop |
| $64EB | ea | nop |
| $64EC | ea | nop |
| $64ED | ea | nop |
| $64EE | ea | nop |
| $64EF | ea | nop |
| $64F0 | ea | nop |
| $64F1 | ea | nop |
| $64F2 | ea | nop |
| $64F3 | a9 0b | lda#VicIIColors.DARK_GREY |
| $64F5 | 8d 21 d0 | sta$d021; Background Color 0 |
| $64F8 | 8d 23 d0 | sta$d023; Background Color 2, Multi-Color Register 1 |
| $64FB | ea | nop |
| $64FC | ea | nop |
| $64FD | ea | nop |
| $64FE | ea | nop |
| $64FF | ea | nop |
| $6500 | ea | nop |
| $6501 | ea | nop |
| $6502 | ea | nop |
| $6503 | ea | nop |
| $6504 | ea | nop |
| $6505 | ea | nop |
| $6506 | ea | nop |
| $6507 | ea | nop |
| $6508 | ea | nop |
| $6509 | ea | nop |
| $650A | ea | nop |
| $650B | ea | nop |
| $650C | ea | nop |
| $650D | a9 1c | lda#$1c |
| $650F | 8d 18 d0 | sta$d018; VIC Memory Control Register |
| $6512 | ad 11 d0 | lda$d011; VIC Control Register 1 |
| $6515 | 29 bf | and#$bf |
| $6517 | 8d 11 d0 | sta$d011; VIC Control Register 1 |
| $651A | ad 16 d0 | lda$d016; VIC Control Register 2 |
| $651D | 09 10 | ora#$10 |
| $651F | 8d 16 d0 | sta$d016; VIC Control Register 2 |
| $6522 | a9 06 | lda#VicIIColors.BLUE |
| $6524 | 8d 23 d0 | sta$d023; Background Color 2, Multi-Color Register 1 |
| $6527 | a9 ed | lda#$ed |
| $6529 | a2 30 | ldx#<irq_raster_clear_bg; Load low byte of raster bg-clear handler |
| $652B | a0 65 | ldy#>irq_raster_clear_bg; Load high byte of raster bg-clear handler |
| $652D | 4c 7c 21 | jmpirq_chain_next; Chain to next raster IRQ (bg-clear handler) |
| ; Raster IRQ handler: waits with NOPs for stable raster, then clears |
| ; background color 0 to black, disables multicolor mode in $D016, |
| ; and chains to the gameplay raster IRQ. |
| $6530 | ea | irq_raster_clear_bgnop; x-ref: $6529, $652B |
| $6531 | ea | nop |
| $6532 | ea | nop |
| $6533 | ea | nop |
| $6534 | ea | nop |
| $6535 | ea | nop |
| $6536 | ea | nop |
| $6537 | ea | nop |
| $6538 | ea | nop |
| $6539 | ea | nop |
| $653A | ea | nop |
| $653B | ea | nop |
| $653C | a9 00 | lda#VicIIColors.BLACK |
| $653E | 8d 21 d0 | sta$d021; Background Color 0 |
| $6541 | ad 16 d0 | lda$d016; VIC Control Register 2 |
| $6544 | 29 ef | and#$ef |
| $6546 | 8d 16 d0 | sta$d016; VIC Control Register 2 |
| $6549 | a9 05 | lda#$05 |
| $654B | a2 92 | ldx#<irq_gameplay_raster |
| $654D | a0 64 | ldy#>irq_gameplay_raster |
| $654F | 4c 7c 21 | jmpirq_chain_next |
| | .encode |
| | .enc"screen" |
| ; Homage screen: "THIS GAME IS A HOMAGE TO H.E.R.O. FROM JOHN VAN RYZIN..." |
| $6552 | | txt_homage_message.text"THIS GAME IS A HOMAGE TO H.E.R.O.", $ff, $ff, "FROM "; x-ref: $660B, $660F |
| $657A | | .text"JOHN VAN RYZIN, PUBLISHED", $ff, $ff, "BY ACTIVISION" |
| $65A2 | | .text" IN 1984.", $ff, $ff, $ff, "THIS VERSION CONTAINS COMPLE" |
| $65CA | | .text"TELY", $ff, $ff, "NEW LEVELS.@" |
| ; Homage screen prompt: "PRESS FIRE TO CONTINUE" |
| $65DC | | txt_press_fire.text"PRESS FIRE TO CONTINUE@"; x-ref: $6620, $6624 |
| | .endencode |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| ; Initializes and displays the intro/about screen. Sets the game state to INTRO, |
| ; blanks the screen, sets border and background to black, configures VIC-II |
| ; memory registers, clears the screen, draws the homage text (white) and the |
| ; "press fire" prompt (green), resets all sprites, and re-enables the VIC-II display. |
| ; |
| ; Inputs: None |
| ; Outputs: None |
| ; Side Effects: Screen blanked then re-enabled, border/bg set to black, sprites |
| ; disabled, screen RAM written with intro text |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| $65F3 | a9 01 | init_intro_screenlda#GameState.INTRO; x-ref: $20F2 |
| $65F5 | 8d d3 20 | stagame_state |
| $65F8 | 20 7e 36 | jsrblank_screen; Blank screen during setup |
| $65FB | a9 00 | lda#VicIIColors.BLACK; Load black color index |
| $65FD | 8d 20 d0 | sta$d020; Set border color to black; Border Color |
| $6600 | 8d 21 d0 | sta$d021; Set background color to black; Background Color 0 |
| $6603 | a9 1c | lda#$1c; VIC memory value for default charsets |
| $6605 | 8d 18 d0 | sta$d018; Set VIC-II screen and character pointers; VIC Memory Control Register |
| $6608 | 20 44 36 | jsrclear_screen; Wipe screen RAM clean |
| $660B | a9 52 | lda#<txt_homage_message |
| $660D | 85 fb | stazp_ptr_src_lo |
| $660F | a9 65 | lda#>txt_homage_message |
| $6611 | 85 fc | stazp_ptr_src_hi |
| $6613 | a9 f4 | lda#<SCREEN_RAM_R6C4 |
| $6615 | 85 fd | stazp_ptr_dst_lo |
| $6617 | a9 04 | lda#>SCREEN_RAM_R6C4 |
| $6619 | 85 fe | stazp_ptr_dst_hi |
| $661B | a9 01 | lda#VicIIColors.WHITE; Use white color for homage text |
| $661D | 20 a8 36 | jsrdraw_text_with_color |
| $6620 | a9 dc | lda#<txt_press_fire |
| $6622 | 85 fb | stazp_ptr_src_lo |
| $6624 | a9 65 | lda#>txt_press_fire |
| $6626 | 85 fc | stazp_ptr_src_hi |
| $6628 | a9 d9 | lda#<SCREEN_RAM_R18C9 |
| $662A | 85 fd | stazp_ptr_dst_lo |
| $662C | a9 06 | lda#>SCREEN_RAM_R18C9 |
| $662E | 85 fe | stazp_ptr_dst_hi |
| $6630 | a9 05 | lda#VicIIColors.GREEN; Use green color for fire prompt |
| $6632 | 20 a8 36 | jsrdraw_text_with_color |
| $6635 | 20 d5 53 | jsrreset_all_sprites; Disable all hardware sprites |
| $6638 | 4c 67 36 | jmpenable_screen; Enable VIC-II display and return |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| ; Polls the joystick port to check for a new fire button click on the intro screen. |
| ; Ensures the button is newly pressed (active-low logic: currently pressed (0) |
| ; and previously released ($10)) to prevent click-holding. |
| ; If a new click is detected, transitions to load_assets_and_init_title. |
| ; |
| ; Inputs: joystick_state ($3E80), joystick_prev_state ($3E81) |
| ; Outputs: None |
| ; Side Effects: Jumps to load_assets_and_init_title if new click occurs |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| wait_for_intro_fire_click |
| $663B | ad 80 3e | ldajoystick_state; Read current joystick state ; x-ref: $211B |
| $663E | 29 10 | and#$10; Isolate fire button bit (bit 4) |
| $6640 | d0 0a | bner_664C; Active-low: nonzero = released, abort tick |
| $6642 | ad 81 3e | ldajoystick_prev_state; Read previous frame joystick state |
| $6645 | 29 10 | and#$10; Isolate previous fire button bit |
| $6647 | f0 03 | beqr_664C; Zero = already pressed last frame (hold check), abort |
| $6649 | 4c 6d 66 | jmpload_assets_and_init_title; New fire click! Advance to loading sequence |
| $664C | 60 | r_664Crts; x-ref: $6640, $6647 |
| $664D | | title_sprite_y_pos.byte$00; x-ref: $66A1, $66FA, $6704, $6708, $671D |
| $664E | | title_anim_counter.byte$00; x-ref: $66A6, $66EC, $66F7 |
| | .encode |
| | .enc"screen" |
| $664F | | txt_loading_data.text"LOADING DATA...@"; x-ref: $6678, $667C |
| | .endencode |
| ; X positions for 7 title screen sprites (indices 0-6). |
| title_sprite_x_positions |
| $665F | | .byte$9b, $9b, $c7, $c7, $96, $ae, $c6; x-ref: $66B9 |
| ; Color values for 7 title screen sprites (indices 0-6). |
| $6666 | | title_sprite_colors.byteVicIIColors.BLUE; blue ; x-ref: $66CC |
| $6667 | | .byteVicIIColors.LIGHT_BLUE; light blue |
| $6668 | | .byteVicIIColors.BLUE; blue |
| $6669 | | .byteVicIIColors.BLUE; blue |
| $666A | | .byteVicIIColors.ORANGE; orange |
| $666B | | .byteVicIIColors.ORANGE; orange |
| $666C | | .byteVicIIColors.ORANGE; orange |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| ; Displays the "LOADING DATA..." message, then loads high scores and cave data |
| ; from disk. Once assets are loaded, resets the title screen sprite animation Y |
| ; position and frame counter, initializes the title screen sprites via |
| ; init_title_sprites, and re-enables the display to begin the curtain animation. |
| ; |
| ; Inputs: None |
| ; Outputs: None |
| ; Side Effects: Displays loading text, loads disk data, initializes title sprites |
| ; (VIC-II registers), resets animation variables, screen enabled |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| load_assets_and_init_title |
| $666D | a9 02 | lda#GameState.CURTAIN_ANIMATION; x-ref: $6649 |
| $666F | 8d d3 20 | stagame_state; game_state = GameState.CURTAIN_ANIMATION |
| $6672 | 20 7e 36 | jsrblank_screen; Blank display for loading message |
| $6675 | 20 44 36 | jsrclear_screen |
| $6678 | a9 4f | lda#<txt_loading_data; Source pointer to 'LOADING DATA...' text |
| $667A | 85 fb | stazp_ptr_src_lo |
| $667C | a9 66 | lda#>txt_loading_data |
| $667E | 85 fc | stazp_ptr_src_hi |
| $6680 | a9 ed | lda#<SCREEN_RAM_R12C13; Destination pointer to screen RAM ($05ED) |
| $6682 | 85 fd | stazp_ptr_dst_lo |
| $6684 | a9 05 | lda#>SCREEN_RAM_R12C13 |
| $6686 | 85 fe | stazp_ptr_dst_hi |
| $6688 | a9 01 | lda#VicIIColors.WHITE; White color for loading text |
| $668A | 20 a8 36 | jsrdraw_text_with_color |
| $668D | 20 67 36 | jsrenable_screen; Enable display to show message |
| $6690 | 20 d6 52 | jsrload_high_scores; Load high scores from disk |
| $6693 | 20 4d 1c | jsrload_all_cave_data; Load level/cave data from disk |
| $6696 | 20 9f 20 | jsrread_disk_status_channel; Clear drive error status channel |
| $6699 | 20 7e 36 | jsrblank_screen; Blank display to hide asset setup |
| $669C | 20 44 36 | jsrclear_screen; Wipe screen RAM |
| $669F | a9 00 | lda#$00 |
| $66A1 | 8d 4d 66 | statitle_sprite_y_pos; Reset animation curtain Y offset to 0 |
| $66A4 | a9 f0 | lda#$f0 |
| $66A6 | 8d 4e 66 | statitle_anim_counter; Reset animation countdown (240 frames) |
| $66A9 | 20 af 66 | jsrinit_title_sprites; Build & scale title screen sprites |
| $66AC | 4c 67 36 | jmpenable_screen; Enable VIC display to start animation |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| ; Initializes the 7 hardware sprites used for the title screen curtain animation. |
| ; Sets their X positions, colors, and sprite data pointers (starting at $E8). |
| ; Also expands sprites 0 and 1 by 2x both horizontally and vertically. |
| ; |
| ; Inputs: None |
| ; Outputs: None |
| ; Side Effects: Modifies VIC-II sprite registers ($D000-$D02D) and screen pointers |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| $66AF | 20 d5 53 | init_title_spritesjsrreset_all_sprites; x-ref: $66A9 |
| $66B2 | a9 7f | lda#$7f; Enable sprites 0-6 (%01111111) |
| $66B4 | 8d 15 d0 | sta$d015; Sprite display Enable |
| $66B7 | a2 06 | ldx#$06; Loop for 7 sprites (X=6 down to 0) |
| $66B9 | bc 5f 66 | b_66B9ldytitle_sprite_x_positions,x; Load X position from table ; x-ref: $66D3 |
| $66BC | 8a | txa; Double X for VIC-II register offset |
| $66BD | 0a | asla |
| $66BE | aa | tax |
| $66BF | 98 | tya |
| $66C0 | 9d 00 d0 | sta$d000,x; Store X position; Sprite 0 X Pos |
| $66C3 | 8a | txa; Restore original X index |
| $66C4 | 4a | lsra |
| $66C5 | aa | tax |
| $66C6 | 18 | clc; Base sprite pointer is $E8 |
| $66C7 | 69 e8 | adc#$e8 |
| $66C9 | 9d f8 07 | staSPRITE_PTR_0,x; Store sprite pointer |
| $66CC | bd 66 66 | ldatitle_sprite_colors,x; Load color from table; blue |
| $66CF | 9d 27 d0 | sta$d027,x; Store sprite color; Sprite 0 Color |
| $66D2 | ca | dex; Next sprite |
| $66D3 | 10 e4 | bplb_66B9 |
| $66D5 | a9 03 | lda#$03; Bitmask %00000011 (Sprites 0 and 1) |
| $66D7 | 8d 1d d0 | sta$d01d; Expand Sprites 0 & 1 Horizontally; Sprites Expand 2x Horizontal (X) |
| $66DA | 8d 17 d0 | sta$d017; Expand Sprites 0 & 1 Vertically; Sprites Expand 2x Vertical (Y) |
| $66DD | 60 | rts |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| ; Ticks the title screen curtain opening animation once per frame. |
| ; Checks the joystick port to allow skipping the animation with a fire button click |
| ; (instantly transitioning to show_main_menu). |
| ; If not skipped, decrements the frame counter title_anim_counter and increases the |
| ; vertical offset title_sprite_y_pos by 2 pixels per frame (capping at 120 pixels). |
| ; Triggers set_title_sprite_y_positions to write positions into VIC-II registers. |
| ; Once the animation counter expires, automatically transitions to the main menu. |
| ; |
| ; Inputs: joystick_state ($3E80), joystick_prev_state ($3E81), |
| ; title_anim_counter ($664E), title_sprite_y_pos ($664D) |
| ; Outputs: title_anim_counter, title_sprite_y_pos |
| ; Side Effects: Jumps to show_main_menu on skip or completion, modifies VIC-II |
| ; sprite registers via set_title_sprite_y_positions |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| update_title_curtain_animation |
| $66DE | ad 80 3e | ldajoystick_state; Read current joystick state ; x-ref: $2122 |
| $66E1 | 29 10 | and#$10; Isolate fire button bit (bit 4) |
| $66E3 | d0 07 | bneanimate_title_sprite_curtain; Active-low: fire released -> tick animation |
| $66E5 | ad 81 3e | ldajoystick_prev_state; Read previous frame joystick state |
| $66E8 | 29 10 | and#$10; Isolate previous fire button bit |
| $66EA | d0 05 | bneb_66F1; Zero = already pressed (hold), continue anim. Nonzero = new click -> skip! |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| ; Animates the title screen sprite curtain effect. Each frame, moves the |
| ; top sprite group (0-2) downward and the bottom sprite group (4-6) upward, |
| ; creating a "curtain opening" reveal. Runs until the animation counter |
| ; reaches zero, then transitions to the score/gameplay screen. |
| ; |
| ; Inputs: title_anim_counter ($664E) — frames remaining |
| ; title_sprite_y_pos ($664D) — current Y offset |
| ; Outputs: title_anim_counter decremented, title_sprite_y_pos increased |
| ; Side Effects: Updates VIC-II sprite Y position registers ($D001-$D00D) |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| animate_title_sprite_curtain |
| $66EC | ad 4e 66 | ldatitle_anim_counter; Load remaining animation frames ; x-ref: $66E3 |
| $66EF | d0 03 | bneb_66F4; Counter > 0: continue animation tick |
| $66F1 | 4c 5e 69 | b_66F1jmpshow_main_menu; Skip or finish animation: transition to main menu ; x-ref: $66EA |
| $66F4 | 20 08 67 | b_66F4jsrset_title_sprite_y_positions; Update VIC-II sprite registers with new Y offsets ; x-ref: $66EF |
| $66F7 | ce 4e 66 | dectitle_anim_counter; Decrement animation frame counter |
| $66FA | ad 4d 66 | ldatitle_sprite_y_pos; Load current Y offset |
| $66FD | c9 78 | cmp#$78; Reached max curtain offset (120 pixels)? |
| $66FF | f0 06 | beqr_6707; Yes: stop scrolling curtain |
| $6701 | 18 | clc; move sprites 2 pixels per frame |
| $6702 | 69 02 | adc#$02; No: move curtain 2 pixels per frame |
| $6704 | 8d 4d 66 | statitle_sprite_y_pos; Store updated Y offset |
| $6707 | 60 | r_6707rts; Return from frame update tick ; x-ref: $66FF |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| ; Sets the Y positions of all 7 title sprites based on title_sprite_y_pos. |
| ; Sprites 0-2 use the position directly (top group), sprite 3 is offset |
| ; +$15 below them, and sprites 4-6 use $1C minus the position (bottom |
| ; group moving upward as the curtain opens). |
| ; |
| ; Inputs: title_sprite_y_pos ($664D) |
| ; Outputs: None |
| ; Side Effects: Writes VIC-II registers $D001, $D003, $D005, $D007, |
| ; $D009, $D00B, $D00D |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| set_title_sprite_y_positions |
| $6708 | ad 4d 66 | ldatitle_sprite_y_pos; load current Y offset ; x-ref: $66F4 |
| $670B | 8d 01 d0 | sta$d001; sprite 0 Y = Y offset (top group); Sprite 0 Y Pos |
| $670E | 8d 03 d0 | sta$d003; sprite 1 Y = Y offset (top group); Sprite 1 Y Pos |
| $6711 | 8d 05 d0 | sta$d005; sprite 2 Y = Y offset (top group); Sprite 2 Y Pos |
| $6714 | 18 | clc |
| $6715 | 69 15 | adc#$15; add 21 pixels offset for sprite 3 |
| $6717 | 8d 07 d0 | sta$d007; sprite 3 Y = Y offset + $15 (below top group); Sprite 3 Y Pos |
| $671A | a9 1c | lda#$1c; $1C is the base for the bottom group |
| $671C | 38 | sec |
| $671D | ed 4d 66 | sbctitle_sprite_y_pos; bottom Y = $1C - Y offset (moves up as curtain opens) |
| $6720 | 8d 09 d0 | sta$d009; sprite 4 Y (bottom group); Sprite 4 Y Pos |
| $6723 | 8d 0b d0 | sta$d00b; sprite 5 Y (bottom group); Sprite 5 Y Pos |
| $6726 | 8d 0d d0 | sta$d00d; sprite 6 Y (bottom group); Sprite 6 Y Pos |
| $6729 | 60 | rts |
| ; Current selected menu option on the title screen. |
| ; 0=START, 1=DYNAMITE, 2=BEST HEROES, 3=PLAY LEVELS, 4=CREDITS. |
| $672A | | menu_cursor_index.byte$00; x-ref: $6A78, $6AC4, $6B10, $6B13, $6B1F, ... |
| ; Selected level index in the PLAY LEVELS menu option. |
| ; Incremented/decremented with joystick up/down when menu_cursor_index=3. |
| ; Used to index into level_select_strings. |
| menu_level_select_index |
| $672B | | .byte$00; x-ref: $6AB1, $6AD9, $6ADE, $6AF3, $6AFB, ... |
| ; Title screen icon tile indices (3 bytes + null terminator) |
| menu_title_icon_tiles |
| $672C | | .byte$1b, $1c, $1d, $00; x-ref: $696F, $6973 |
| | .encode |
| | .enc"screen" |
| ; Menu option text strings: START, BEST HEROES, etc. (screen codes, $FF-terminated) |
| $6730 | | menu_option_strings.text" START ", $ff, $ff, $ff, $ff; start ; x-ref: $6984, $6988 |
| $6745 | | .text" BEST HEROES ", $ff, $ff; best heroes |
| $6758 | | .text"PLAY LEVELS XXXXX", $ff, $ff; play levels |
| $676B | | .text" CREDITS @"; credits |
| ; Control/dynamite description strings for the menu, 30 bytes each. |
| ; 4 entries indexed by a_60D7 via multiply_a_by_30. |
| ; Displayed on the title screen below the menu options. |
| dynamite_desc_strings |
| $677D | | .text" DYNAMITE: JOYSTICK DOWN "; joystick down ; x-ref: $6B61 |
| $679B | | .text"DYNAMITE: DOUBLE JOYSTICK DOWN"; double joy down |
| $67B9 | | .text" DYNAMITE: SPACE BAR "; space |
| $67D7 | | .text" DYNAMITE: 2ND FIRE BUTTON "; 2nd fire button |
| ; Level selection display strings, 5 bytes each (null-terminated). |
| ; E.g. "05-08", "09-12", etc. Indexed by menu_level_select_index. |
| $67F5 | | level_select_strings.text"05-08"; 05-08 ; x-ref: $6B77 |
| $67FA | | .text"09-12"; 09-12 |
| $67FF | | .text"13-16"; 13-16 |
| $6804 | | .text"17-20"; 17-20 |
| | .endencode |
| ; HUD: copyright year "2025" + H.E.R.O. logo tile indices for bottom screen rows |
| $6809 | | hud_year_and_logo.byte$32, $30, $32, $35, $00; x-ref: $632E, $6332, $69B2, $69B6 |
| ; Title logo character data (24 columns x 8 rows) |
| $680E | | title_logo_chars.byte$79, $20, $7a, $7b, $20, $20, $7c, $7d; x-ref: $69DE, $69E2 |
| $6816 | | .byte$7e, $20, $20, $20, $7f, $80, $81, $82 |
| $681E | | .byte$20, $20, $20, $83, $84, $85, $86, $20 |
| $6826 | | .byte$87, $88, $89, $8a, $20, $20, $8b, $8c |
| $682E | | .byte$8d, $20, $20, $20, $8e, $8f, $90, $91 |
| $6836 | | .byte$20, $20, $92, $93, $20, $94, $95, $20 |
| $683E | | .byte$96, $97, $98, $99, $20, $20, $9a, $9b |
| $6846 | | .byte$9c, $20, $20, $20, $9a, $9d, $9e, $9f |
| $684E | | .byte$20, $20, $a0, $20, $20, $a1, $a2, $20 |
| $6856 | | .byte$a3, $a4, $a5, $a6, $20, $20, $a7, $20 |
| $685E | | .byte$20, $20, $20, $20, $a7, $a8, $a9, $20 |
| $6866 | | .byte$20, $20, $ab, $ac, $a1, $ad, $ae, $20 |
| $686E | | .byte$af, $b0, $b1, $b2, $bd, $20, $b3, $b4 |
| $6876 | | .byte$b4, $b5, $bd, $20, $af, $20, $b6, $b7 |
| $687E | | .byte$bd, $20, $b8, $b9, $ba, $bb, $bc, $bd |
| $6886 | | .fill24, $20 |
| $689E | | .byte$c4, $c4, $c4, $c4, $c4, $c4, $c4, $c5 |
| $68A6 | | .byte$be, $bf, $20, $c0, $c1, $c2, $c3, $20 |
| $68AE | | .fill8, $c4 |
| ; Title logo color data (24 columns x 8 rows, matches title_logo_chars) |
| $68B6 | | title_logo_colors.byte$05, $05, $05, $05, $05, $0d, $0a, $0a; x-ref: $69E6, $69EA |
| $68BE | | .byte$0a, $0a, $0a, $0d, $0e, $0e, $0e, $0e |
| $68C6 | | .byte$0e, $0d, $04, $04, $04, $04, $04, $04 |
| $68CE | | .byte$05, $05, $05, $05, $05, $0d, $0a, $0a |
| $68D6 | | .byte$0a, $0a, $0a, $0d, $0e, $0e, $0e, $0e |
| $68DE | | .byte$0e, $0d, $04, $04, $04, $04, $04, $04 |
| $68E6 | | .byte$05, $05, $05, $05, $05, $05, $0a, $0a |
| $68EE | | .byte$0a, $0a, $0a, $05, $0e, $0e, $0e, $0e |
| $68F6 | | .byte$0e, $05, $04, $04, $04, $04, $04, $04 |
| $68FE | | .byte$05, $05, $05, $05, $05, $05, $0a, $0a |
| $6906 | | .byte$0a, $0a, $0a, $05, $0e, $0e, $0e, $0e |
| $690E | | .byte$0e, $05, $04, $04, $04, $04, $04, $04 |
| $6916 | | .byte$05, $05, $05, $05, $05, $05, $0a, $0a |
| $691E | | .byte$0a, $0a, $0a, $05, $0e, $0e, $0e, $0e |
| $6926 | | .byte$0e, $05, $04, $04, $04, $04, $04, $04 |
| $692E | | .fill24, $01 |
| $6946 | | .byte$0b, $0b, $0c, $0c, $0c, $0f, $0f, $0f |
| $694E | | .fill8, $01 |
| $6956 | | .byte$0f, $0f, $0f, $0c, $0c, $0c, $0b, $0b |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| ; Sets up and displays the main menu screen. |
| ; Clears the screen, draws the menu layout with title artwork, renders |
| ; menu option text (START, BEST HEROES, PLAY LEVELS, CREDITS), loads |
| ; the current dynamite/control description, highlights the selected |
| ; menu item, enables menu sprites, and installs the menu raster IRQ. |
| ; |
| ; Inputs: None |
| ; Outputs: None |
| ; Side Effects: Blanks and redraws screen, sets a_20D3 to #$03 (menu state), |
| ; enables 6 sprites ($D015=$3F), installs raster IRQ at $6B84 |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| $695E | a9 03 | show_main_menulda#GameState.MAIN_MENU; Set game state to menu mode ; x-ref: $1D6A, $1DE2, $5F36, $616E, $6199, ... |
| $6960 | 8d d3 20 | stagame_state; game_state = 3 (main menu) |
| $6963 | 20 7e 36 | jsrblank_screen; Clear screen and prepare for menu |
| $6966 | 20 39 36 | jsrset_vic_scroll_and_rows |
| $6969 | 20 44 36 | jsrclear_screen |
| $696C | 20 de 69 | jsrdraw_title_artwork; Copy title artwork to screen/color RAM |
| $696F | a9 2c | lda#<menu_title_icon_tiles |
| $6971 | 85 fb | stazp_ptr_src_lo; Source: menu text at $672C |
| $6973 | a9 67 | lda#>menu_title_icon_tiles |
| $6975 | 85 fc | stazp_ptr_src_hi; Dest: screen RAM $0538 (row 3, col 16) |
| $6977 | a9 38 | lda#<SCREEN_RAM_R7C32 |
| $6979 | 85 fd | stazp_ptr_dst_lo |
| $697B | a9 05 | lda#>SCREEN_RAM_R7C32 |
| $697D | 85 fe | stazp_ptr_dst_hi |
| $697F | a9 0b | lda#VicIIColors.DARK_GREY |
| $6981 | 20 a8 36 | jsrdraw_text_with_color; Color: dark grey |
| $6984 | a9 30 | lda#<menu_option_strings; Source: second text block at $6730 |
| $6986 | 85 fb | stazp_ptr_src_lo |
| $6988 | a9 67 | lda#>menu_option_strings; Dest: screen RAM $05C3 (row 6, col 3) |
| $698A | 85 fc | stazp_ptr_src_hi |
| $698C | a9 c3 | lda#<SCREEN_RAM_R11C11 |
| $698E | 85 fd | stazp_ptr_dst_lo |
| $6990 | a9 05 | lda#>SCREEN_RAM_R11C11 |
| $6992 | 85 fe | stazp_ptr_dst_hi |
| $6994 | a9 01 | lda#VicIIColors.WHITE; Color: white |
| $6996 | 20 a8 36 | jsrdraw_text_with_color; Draw title text |
| $6999 | 20 58 6b | jsrupdate_dynamite_desc; Load current dynamite description text |
| $699C | a2 01 | ldx#$01; X=row 1, Y=row 1: highlight selected option |
| $699E | a0 01 | ldy#$01 |
| $69A0 | 20 45 6a | jsrfill_color_row; Set color bar on selected item |
| $69A3 | 20 6e 6b | jsrupdate_level_select_text; Load level selection string |
| $69A6 | ad c5 52 | ldamax_unlocked_level; Check if level select is available |
| $69A9 | 10 07 | bplb_69B2; Skip level bar if not unlocked |
| $69AB | a2 0b | ldx#$0b |
| $69AD | a0 03 | ldy#$03 |
| $69AF | 20 45 6a | jsrfill_color_row |
| $69B2 | a9 09 | b_69B2lda#<hud_year_and_logo; Source: control instructions at $6809 ; x-ref: $69A9 |
| $69B4 | 85 fb | stazp_ptr_src_lo |
| $69B6 | a9 68 | lda#>hud_year_and_logo; Dest: screen RAM $07AD (row 16, col 5) |
| $69B8 | 85 fc | stazp_ptr_src_hi |
| $69BA | a9 ad | lda#<SCREEN_RAM_R23C21 |
| $69BC | 85 fd | stazp_ptr_dst_lo |
| $69BE | a9 07 | lda#>SCREEN_RAM_R23C21 |
| $69C0 | 85 fe | stazp_ptr_dst_hi |
| $69C2 | a9 03 | lda#VicIIColors.CYAN; Color: cyan |
| $69C4 | 20 a8 36 | jsrdraw_text_with_color; Draw control instructions text |
| $69C7 | 20 d5 53 | jsrreset_all_sprites; Deactivate all sprites first |
| $69CA | a9 3f | lda#$3f; Enable sprites 0-5 for menu decorations |
| $69CC | 8d 15 d0 | sta$d015; Sprite display Enable |
| $69CF | 20 ff 1d | jsrabort_transition; Cancel any active screen transition |
| $69D2 | 20 67 36 | jsrenable_screen |
| $69D5 | a9 28 | lda#$28; A=$28 = raster line for menu IRQ |
| $69D7 | a2 84 | ldx#$84 |
| $69D9 | a0 6b | ldy#$6b; X/Y=$6B84 = menu raster IRQ handler |
| $69DB | 4c 4c 21 | jmpsetup_raster_irq; Install raster IRQ and return |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| ; Draws the main menu's title artwork (logo) onto the screen. |
| ; Copies a 24x8 block of character data and color data from ROM to |
| ; Screen RAM ($0430) and Color RAM ($D830). |
| ; |
| ; Inputs: None |
| ; Outputs: None |
| ; Side Effects: Modifies Screen RAM and Color RAM |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| $69DE | a9 0e | draw_title_artworklda#<title_logo_chars; Source 1 (Characters) = $680E ; x-ref: $696C |
| $69E0 | 85 02 | stazp_work0 |
| $69E2 | a9 68 | lda#>title_logo_chars |
| $69E4 | 85 03 | stazp_work1 |
| $69E6 | a9 b6 | lda#<title_logo_colors; Source 2 (Colors) = $68B6 |
| $69E8 | 85 04 | stazp_work2 |
| $69EA | a9 68 | lda#>title_logo_colors |
| $69EC | 85 05 | stazp_work3 |
| $69EE | a9 30 | lda#<SCREEN_RAM_R1C8; Destination 1 (Screen) = $0430 |
| $69F0 | 85 06 | stazp_ptr_aux1_lo |
| $69F2 | a9 04 | lda#>SCREEN_RAM_R1C8 |
| $69F4 | 85 07 | stazp_ptr_aux1_hi |
| $69F6 | a9 30 | lda#<COLOR_RAM_R1C8; Destination 2 (Color) = $D830 |
| $69F8 | 85 08 | stazp_ptr_aux2_lo |
| $69FA | a9 d8 | lda#>COLOR_RAM_R1C8 |
| $69FC | 85 09 | stazp_ptr_aux2_hi |
| $69FE | a2 07 | ldx#$07; X = 8 rows (7 down to 0) |
| $6A00 | a0 17 | b_6A00ldy#$17; Y = 24 columns (23 down to 0) ; x-ref: $6A42 |
| $6A02 | b1 02 | b_6A02lda(zp_work0),y; Copy character byte ; x-ref: $6A0B |
| $6A04 | 91 06 | sta(zp_ptr_aux1_lo),y |
| $6A06 | b1 04 | lda(zp_work2),y; Copy color byte |
| $6A08 | 91 08 | sta(zp_ptr_aux2_lo),y |
| $6A0A | 88 | dey; Inner loop (columns) |
| $6A0B | 10 f5 | bplb_6A02 |
| $6A0D | a5 02 | ldazp_work0; Add 24 to Source 1 pointer |
| $6A0F | 18 | clc |
| $6A10 | 69 18 | adc#$18 |
| $6A12 | 85 02 | stazp_work0 |
| $6A14 | a5 03 | ldazp_work1 |
| $6A16 | 69 00 | adc#$00 |
| $6A18 | 85 03 | stazp_work1 |
| $6A1A | a5 04 | ldazp_work2; Add 24 to Source 2 pointer |
| $6A1C | 18 | clc |
| $6A1D | 69 18 | adc#$18 |
| $6A1F | 85 04 | stazp_work2 |
| $6A21 | a5 05 | ldazp_work3 |
| $6A23 | 69 00 | adc#$00 |
| $6A25 | 85 05 | stazp_work3 |
| $6A27 | a5 06 | ldazp_ptr_aux1_lo; Add 40 to Dest 1 (next line) |
| $6A29 | 18 | clc |
| $6A2A | 69 28 | adc#$28 |
| $6A2C | 85 06 | stazp_ptr_aux1_lo |
| $6A2E | a5 07 | ldazp_ptr_aux1_hi |
| $6A30 | 69 00 | adc#$00 |
| $6A32 | 85 07 | stazp_ptr_aux1_hi |
| $6A34 | a5 08 | ldazp_ptr_aux2_lo; Add 40 to Dest 2 (next line) |
| $6A36 | 18 | clc |
| $6A37 | 69 28 | adc#$28 |
| $6A39 | 85 08 | stazp_ptr_aux2_lo |
| $6A3B | a5 09 | ldazp_ptr_aux2_hi |
| $6A3D | 69 00 | adc#$00 |
| $6A3F | 85 09 | stazp_ptr_aux2_hi |
| $6A41 | ca | dex; Outer loop (rows) |
| $6A42 | d0 bc | bneb_6A00 |
| $6A44 | 60 | rts |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| ; Fills one 40-column row of Color RAM with a given color value. |
| ; Used to highlight/unhighlight menu items by painting a full row. |
| ; The base address is COLOR_RAM_ROW11; Y selects the row offset |
| ; (each row is 80 bytes in the C128 80-col layout), and X holds |
| ; the color value to fill. |
| ; |
| ; Inputs: X = color value to store, Y = row offset from COLOR_RAM_ROW11 |
| ; Outputs: None |
| ; Side Effects: Overwrites 40 bytes of Color RAM at the target row |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| $6A45 | a9 b8 | fill_color_rowlda#<COLOR_RAM_R11C0; Point to COLOR_RAM_ROW11 as base ; x-ref: $69A0, $69AF |
| $6A47 | 85 fb | stazp_ptr_src_lo |
| $6A49 | a9 d9 | lda#>COLOR_RAM_R11C0 |
| $6A4B | 85 fc | stazp_ptr_src_hi |
| $6A4D | c0 00 | cpy#$00; Row offset = 0? Skip advance loop |
| $6A4F | f0 10 | beqb_6A61 |
| $6A51 | a5 fb | b_6A51ldazp_ptr_src_lo; x-ref: $6A5F |
| $6A53 | 18 | clc |
| $6A54 | 69 50 | adc#$50; Add 80 ($50) per row (C128 80-col layout) |
| $6A56 | 85 fb | stazp_ptr_src_lo |
| $6A58 | a5 fc | ldazp_ptr_src_hi |
| $6A5A | 69 00 | adc#$00 |
| $6A5C | 85 fc | stazp_ptr_src_hi |
| $6A5E | 88 | dey; Next row offset |
| $6A5F | d0 f0 | bneb_6A51 |
| $6A61 | 8a | b_6A61txa; A = color value (from X) ; x-ref: $6A4F |
| $6A62 | a0 27 | ldy#$27; Fill 40 columns ($00-$27) |
| $6A64 | 91 fb | b_6A64sta(zp_ptr_src_lo),y; Store color into Color RAM ; x-ref: $6A67 |
| $6A66 | 88 | dey |
| $6A67 | 10 fb | bplb_6A64 |
| $6A69 | 60 | rts |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| ; Ticks the main menu input processing once per frame. |
| ; Detects newly clicked fire button presses to activate menu choices: |
| ; Option 0 (START) -> starts default game |
| ; Option 1 (DYNAMITE) -> cycles control methods (input_mode) |
| ; Option 2 (BEST HEROES) -> shows high score ranking screen |
| ; Option 3 (PLAY LEVELS) -> launches game from selected starting level |
| ; Option 4 (CREDITS) -> shows credits screen |
| ; |
| ; If fire is not pressed, processes directional joystick inputs: |
| ; Left/Right -> shifts starting level group (Option 3 focused) up to max_unlocked_level |
| ; Up/Down -> scrolls cursor, wrapping 0-4 and skipping Option 3 if locked |
| ; |
| ; Inputs: joystick_state ($3E80), joystick_prev_state ($3E81), |
| ; menu_cursor_index ($672A), menu_level_select_index ($672B) |
| ; Outputs: menu_cursor_index, menu_level_select_index, difficulty_mode, input_mode |
| ; Side Effects: Stops audio, transitions to gameplay init, high scores, or credits |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| update_main_menu_selection |
| $6A6A | ad 80 3e | ldajoystick_state; Read current joystick state ; x-ref: $2129 |
| $6A6D | 29 10 | and#$10; Isolate fire button bit (bit 4) |
| $6A6F | d0 53 | bneb_6AC4; Active-low: fire released -> check movement |
| $6A71 | ad 81 3e | ldajoystick_prev_state; Read previous frame joystick state |
| $6A74 | 29 10 | and#$10 |
| $6A76 | f0 4c | beqb_6AC4; Zero = already pressed last frame (hold check), abort |
| $6A78 | ad 2a 67 | ldamenu_cursor_index; Load selected menu option cursor index |
| $6A7B | d0 0b | bneb_6A88; Option > 0 -> check next selections |
| $6A7D | 20 0f 1e | jsrstop_sound; Stop menu audio playback |
| $6A80 | a9 00 | lda#$00; Clear starting level difficulty |
| $6A82 | 8d d8 60 | stadifficulty_mode |
| $6A85 | 4c ff 60 | jmpinit_cave_level; Start gameplay from level 1 |
| $6A88 | c9 01 | b_6A88cmp#MenuOptions.DYNAMITE; Option == 1 (DYNAMITE)? ; x-ref: $6A7B |
| $6A8A | d0 12 | bneb_6A9E |
| $6A8C | ee d7 60 | incinput_mode; Cycle dynamite input control mode |
| $6A8F | ad d7 60 | ldainput_mode |
| $6A92 | c9 04 | cmp#$04; Cycled past max mode 3? |
| $6A94 | d0 05 | bneb_6A9B |
| $6A96 | a9 00 | lda#$00 |
| $6A98 | 8d d7 60 | stainput_mode; Wrap input mode back to 0 |
| $6A9B | 4c 58 6b | b_6A9Bjmpupdate_dynamite_desc; Update HUD text for selected control scheme ; x-ref: $6A94 |
| $6A9E | c9 02 | b_6A9Ecmp#MenuOptions.BEST_HEROES; Option == 2 (BEST HEROES)? ; x-ref: $6A8A |
| $6AA0 | d0 08 | bneb_6AAA |
| $6AA2 | 20 0f 1e | jsrstop_sound |
| $6AA5 | a9 ff | lda#$ff |
| $6AA7 | 4c 3e 6d | jmpinit_high_score_screen; Display high scores board |
| $6AAA | c9 03 | b_6AAAcmp#MenuOptions.PLAY_LEVELS; Option == 3 (PLAY LEVELS)? ; x-ref: $6AA0 |
| $6AAC | d0 10 | bneb_6ABE |
| $6AAE | 20 0f 1e | jsrstop_sound |
| $6AB1 | ae 2b 67 | ldxmenu_level_select_index; Load selected starting level group index |
| $6AB4 | e8 | inx |
| $6AB5 | 8a | txa; Shift group index to starting level index |
| $6AB6 | 0a | asla |
| $6AB7 | 0a | asla |
| $6AB8 | 8d d8 60 | stadifficulty_mode; Set starting level difficulty |
| $6ABB | 4c ff 60 | jmpinit_cave_level; Start gameplay from selected level |
| $6ABE | 20 0f 1e | b_6ABEjsrstop_sound; Stop music, go to credits layout ; x-ref: $6AAC |
| $6AC1 | 4c c3 5e | jmpshow_credits_screen |
| $6AC4 | ad 2a 67 | b_6AC4ldamenu_cursor_index; Check if cursor is on PLAY LEVELS ; x-ref: $6A6F, $6A76 |
| $6AC7 | c9 03 | cmp#MenuOptions.PLAY_LEVELS |
| $6AC9 | d0 37 | bneb_6B02 |
| $6ACB | ad 80 3e | ldajoystick_state; Read joystick state |
| $6ACE | 29 04 | and#$04; Isolate Left direction bit (bit 2) |
| $6AD0 | d0 13 | bneb_6AE5; Left released -> check Right direction |
| $6AD2 | ad 81 3e | ldajoystick_prev_state |
| $6AD5 | 29 04 | and#$04 |
| $6AD7 | f0 0c | beqb_6AE5; Left held -> check Right direction |
| $6AD9 | ad 2b 67 | ldamenu_level_select_index; Check if starting level is at minimum |
| $6ADC | f0 06 | beqr_6AE4 |
| $6ADE | ce 2b 67 | decmenu_level_select_index; Decrement selected starting level group |
| $6AE1 | 4c 6e 6b | jmpupdate_level_select_text; Refresh level range string on screen |
| $6AE4 | 60 | r_6AE4rts; x-ref: $6ADC |
| $6AE5 | ad 80 3e | b_6AE5ldajoystick_state; Isolate Right direction bit (bit 3) ; x-ref: $6AD0, $6AD7 |
| $6AE8 | 29 08 | and#$08 |
| $6AEA | d0 16 | bneb_6B02; Right released -> check Up/Down movement |
| $6AEC | ad 81 3e | ldajoystick_prev_state |
| $6AEF | 29 08 | and#$08 |
| $6AF1 | f0 0f | beqb_6B02; Right held -> check Up/Down movement |
| $6AF3 | ad 2b 67 | ldamenu_level_select_index; Check if level select reached max unlocked |
| $6AF6 | cd c5 52 | cmpmax_unlocked_level |
| $6AF9 | f0 06 | beqr_6B01 |
| $6AFB | ee 2b 67 | incmenu_level_select_index; Check if at max level |
| $6AFE | 4c 6e 6b | jmpupdate_level_select_text |
| $6B01 | 60 | r_6B01rts; x-ref: $6AF9 |
| $6B02 | ad 80 3e | b_6B02ldajoystick_state; Refresh level range string on screen ; x-ref: $6AC9, $6AEA, $6AF1 |
| $6B05 | 29 01 | and#$01 |
| $6B07 | d0 24 | bneb_6B2D |
| $6B09 | ad 81 3e | ldajoystick_prev_state |
| $6B0C | 29 01 | and#$01 |
| $6B0E | f0 1d | beqb_6B2D |
| $6B10 | ce 2a 67 | decmenu_cursor_index; Move cursor up (decrement cursor) |
| $6B13 | ad 2a 67 | ldamenu_cursor_index; Read cursor index |
| $6B16 | c9 03 | cmp#MenuOptions.PLAY_LEVELS; Did we move onto Level Select? |
| $6B18 | d0 09 | bneb_6B23 |
| $6B1A | ad c5 52 | ldamax_unlocked_level; Check if Level Select is unlocked |
| $6B1D | 10 03 | bplr_6B22; If unlocked: skip skip-logic |
| $6B1F | ce 2a 67 | decmenu_cursor_index; Level Select locked: skip it (move up again) |
| $6B22 | 60 | r_6B22rts; x-ref: $6B1D |
| $6B23 | c9 ff | b_6B23cmp#$ff; Did cursor wrap past 0? ; x-ref: $6B18 |
| $6B25 | d0 05 | bner_6B2C |
| $6B27 | a9 04 | lda#MenuOptions.CREDITS; Wrap cursor around to CREDITS (4) |
| $6B29 | 8d 2a 67 | stamenu_cursor_index; Store updated cursor index |
| $6B2C | 60 | r_6B2Crts; x-ref: $6B25 |
| $6B2D | ad 80 3e | b_6B2Dldajoystick_state; Read current joystick state ; x-ref: $6B07, $6B0E |
| $6B30 | 29 02 | and#$02; Isolate Down direction bit (bit 1) |
| $6B32 | d0 23 | bner_6B57; Down released -> abort frame tick |
| $6B34 | ad 81 3e | ldajoystick_prev_state; Read previous frame joystick state |
| $6B37 | 29 02 | and#$02; Isolate previous Down direction bit |
| $6B39 | f0 1c | beqr_6B57; Zero = already pressed last frame (hold check), abort |
| $6B3B | ee 2a 67 | incmenu_cursor_index; Move cursor down (increment cursor) |
| $6B3E | ad 2a 67 | ldamenu_cursor_index; Read cursor index |
| $6B41 | c9 03 | cmp#MenuOptions.PLAY_LEVELS; Did we move onto Level Select? |
| $6B43 | d0 09 | bneb_6B4E |
| $6B45 | ad c5 52 | ldamax_unlocked_level; Check if Level Select is unlocked |
| $6B48 | 10 03 | bplr_6B4D; If unlocked: skip skip-logic |
| $6B4A | ee 2a 67 | incmenu_cursor_index; Level Select locked: skip it (move down again) |
| $6B4D | 60 | r_6B4Drts; x-ref: $6B48 |
| $6B4E | c9 05 | b_6B4Ecmp#$05; Did cursor wrap past CREDITS (4)? ; x-ref: $6B43 |
| $6B50 | d0 05 | bner_6B57 |
| $6B52 | a9 00 | lda#MenuOptions.START; Wrap cursor around to START (0) |
| $6B54 | 8d 2a 67 | stamenu_cursor_index; Store updated cursor index |
| $6B57 | 60 | r_6B57rts; x-ref: $6B32, $6B39, $6B50 |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| ; Updates the on-screen dynamite control description text based on input_mode. |
| ; Looks up input_mode (0-3), multiplies by 30 to index into the |
| ; dynamite_desc_strings table (4 entries × 30 screencodes each), and copies |
| ; the 30-character string to scr_hud_row on screen RAM. |
| ; |
| ; Strings: |
| ; 0 = " DYNAMITE: JOYSTICK DOWN " |
| ; 1 = "DYNAMITE: DOUBLE JOYSTICK DOWN" |
| ; 2 = " DYNAMITE: SPACE BAR " |
| ; 3 = " DYNAMITE: 2ND FIRE BUTTON " |
| ; |
| ; Inputs: input_mode (0-3) — selected dynamite activation method |
| ; Outputs: None |
| ; Side Effects: Writes 30 bytes to screen RAM at scr_hud_row ($060D) |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| $6B58 | ad d7 60 | update_dynamite_descldainput_mode; ; x-ref: $6999, $6A9B |
| $6B5B | 20 b5 21 | jsrmultiply_by_30; Offset = input_mode * 30 |
| $6B5E | aa | tax; X = index into string table |
| $6B5F | a0 00 | ldy#$00; Y = screen write offset |
| $6B61 | bd 7d 67 | b_6B61ldadynamite_desc_strings,x; Read screencode from string table ; x-ref: $6B6B joystick down |
| $6B64 | 99 0d 06 | staSCREEN_RAM_R13C5,y; Write to screen RAM HUD row |
| $6B67 | e8 | inx |
| $6B68 | c8 | iny |
| $6B69 | c0 1e | cpy#$1e; 30 chars ($1E) per description |
| $6B6B | d0 f4 | bneb_6B61 |
| $6B6D | 60 | rts |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| ; Updates the level-select display on the menu screen. |
| ; Reads menu_level_select_index (0-3), multiplies by 5 to index into |
| ; level_select_strings (4 entries × 5 screencodes each), and copies the |
| ; 5-char level range string to scr_lives_display on screen RAM. |
| ; |
| ; Strings: |
| ; 0 = "05-08" 1 = "09-12" 2 = "13-16" 3 = "17-20" |
| ; |
| ; Inputs: menu_level_select_index ($672B) — selected starting level group |
| ; Outputs: None |
| ; Side Effects: Writes 5 bytes to screen RAM at scr_lives_display ($06BF) |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| update_level_select_text |
| $6B6E | ad 2b 67 | ldamenu_level_select_index; Load selected level group (0-3) ; x-ref: $69A3, $6AE1, $6AFE |
| $6B71 | 20 a5 21 | jsrmultiply_by_5; Offset = index * 5 (5 chars per entry) |
| $6B74 | aa | tax; X = byte offset into string table |
| $6B75 | a0 00 | ldy#$00; Y = screen write position |
| $6B77 | bd f5 67 | b_6B77ldalevel_select_strings,x; Read level range char from table ; x-ref: $6B81 05-08 |
| $6B7A | 99 bf 06 | staSCREEN_RAM_R17C23,y; Write to screen RAM (lives/level area) |
| $6B7D | e8 | inx |
| $6B7E | c8 | iny |
| $6B7F | c0 05 | cpy#$05; 5 chars per level string |
| $6B81 | d0 f4 | bneb_6B77 |
| $6B83 | 60 | rts |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| ; Title screen raster IRQ handler — sprite setup. |
| ; Positions 5 sprites to form the title/logo graphic: |
| ; Sprites 0-3 in a row at Y=$3B (X=$59,$89,$B9,$EA) |
| ; Sprite 4 centered at Y=$5B (X=$8F) |
| ; Assigns sprite pointers $F5-$F9 and sets all 5 to white ($01). |
| ; Computes next raster line from menu_cursor_index (each option is 16px |
| ; apart, base $86) and chains to irq_menu_cursor_top. |
| ; |
| ; Inputs: menu_cursor_index = currently highlighted menu option (0-based) |
| ; Outputs: None |
| ; Side Effects: VIC-II sprite registers $D000-$D00B, sprite pointers, |
| ; sprite colors, next IRQ chained to irq_menu_cursor_top |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| irq_title_screen_sprites |
| $6B84 | a9 59 | lda#$59; Sprite 0 X = $59 ; x-ref: $6CC5, $6CC7 |
| $6B86 | 8d 00 d0 | sta$d000; Sprite 0 X Pos |
| $6B89 | a9 89 | lda#$89; Sprite 1 X = $89 |
| $6B8B | 8d 02 d0 | sta$d002; Sprite 1 X Pos |
| $6B8E | a9 b9 | lda#$b9; Sprite 2 X = $B9 |
| $6B90 | 8d 04 d0 | sta$d004; Sprite 2 X Pos |
| $6B93 | a9 ea | lda#$ea; Sprite 3 X = $EA |
| $6B95 | 8d 06 d0 | sta$d006; Sprite 3 X Pos |
| $6B98 | a9 8f | lda#$8f; Sprite 4 X = $8F (centered below) |
| $6B9A | 8d 08 d0 | sta$d008; Sprite 4 X Pos |
| $6B9D | a9 3b | lda#$3b; Sprites 0-3 Y = $3B (top row) |
| $6B9F | 8d 01 d0 | sta$d001; Sprite 0 Y Pos |
| $6BA2 | 8d 03 d0 | sta$d003; Sprite 1 Y Pos |
| $6BA5 | 8d 05 d0 | sta$d005; Sprite 2 Y Pos |
| $6BA8 | 8d 07 d0 | sta$d007; Sprite 3 Y Pos |
| $6BAB | a9 5b | lda#$5b; Sprite 4 Y = $5B (second row) |
| $6BAD | 8d 09 d0 | sta$d009; Sprite 4 Y Pos |
| $6BB0 | a2 f5 | ldx#$f5; Sprite pointers $F5-$F9 (title logo frames) |
| $6BB2 | 8e f8 07 | stxSPRITE_PTR_0 |
| $6BB5 | e8 | inx |
| $6BB6 | 8e f9 07 | stxSPRITE_PTR_1 |
| $6BB9 | e8 | inx |
| $6BBA | 8e fa 07 | stxSPRITE_PTR_2 |
| $6BBD | e8 | inx |
| $6BBE | 8e fb 07 | stxSPRITE_PTR_3 |
| $6BC1 | e8 | inx |
| $6BC2 | 8e fc 07 | stxSPRITE_PTR_4 |
| $6BC5 | a9 01 | lda#VicIIColors.WHITE; All 5 title sprites = white |
| $6BC7 | 8d 27 d0 | sta$d027; Sprite 0 Color |
| $6BCA | 8d 28 d0 | sta$d028; Sprite 1 Color |
| $6BCD | 8d 29 d0 | sta$d029; Sprite 2 Color |
| $6BD0 | 8d 2a d0 | sta$d02a; Sprite 3 Color |
| $6BD3 | 8d 2b d0 | sta$d02b; Sprite 4 Color |
| $6BD6 | ad 2a 67 | ldamenu_cursor_index; Get current menu selection |
| $6BD9 | 0a | asla; cursor_index * 16 |
| $6BDA | 0a | asla |
| $6BDB | 0a | asla |
| $6BDC | 0a | asla |
| $6BDD | 69 86 | adc#$86; + $86 = raster line for top highlight bar |
| $6BDF | a2 e6 | ldx#<irq_menu_cursor_top |
| $6BE1 | a0 6b | ldy#>irq_menu_cursor_top |
| $6BE3 | 4c 7c 21 | jmpirq_chain_next; Chain to irq_menu_cursor_top |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| ; Menu cursor highlight — top bar raster IRQ. |
| ; NOP sled for stable raster timing, then sets $D021 to light blue ($0E) |
| ; for one character row, waits, then resets $D021 to blue ($06). |
| ; This creates a highlighted horizontal bar on the selected menu option. |
| ; Computes the raster line for the bottom bar from menu_cursor_index |
| ; (top + 8 lines = $94 base) and chains to irq_menu_cursor_bottom. |
| ; |
| ; Inputs: menu_cursor_index = currently highlighted menu option (0-based) |
| ; Outputs: None |
| ; Side Effects: $D021 (background color) flashed to light blue then blue |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| $6BE6 | ea | irq_menu_cursor_topnop; NOP sled — stable raster timing ; x-ref: $6BDF, $6BE1 |
| $6BE7 | ea | nop |
| $6BE8 | ea | nop |
| $6BE9 | ea | nop |
| $6BEA | ea | nop |
| $6BEB | ea | nop |
| $6BEC | ea | nop |
| $6BED | ea | nop |
| $6BEE | ea | nop |
| $6BEF | ea | nop |
| $6BF0 | ea | nop |
| $6BF1 | ea | nop |
| $6BF2 | a9 0e | lda#VicIIColors.LIGHT_BLUE; Set background to light blue ($0E) |
| $6BF4 | 8d 21 d0 | sta$d021; Background Color 0 |
| $6BF7 | ea | nop |
| $6BF8 | ea | nop |
| $6BF9 | ea | nop |
| $6BFA | ea | nop |
| $6BFB | ea | nop |
| $6BFC | ea | nop |
| $6BFD | ea | nop |
| $6BFE | ea | nop |
| $6BFF | ea | nop |
| $6C00 | ea | nop |
| $6C01 | ea | nop |
| $6C02 | ea | nop |
| $6C03 | ea | nop |
| $6C04 | ea | nop |
| $6C05 | ea | nop |
| $6C06 | ea | nop |
| $6C07 | ea | nop |
| $6C08 | ea | nop |
| $6C09 | ea | nop |
| $6C0A | ea | nop |
| $6C0B | ea | nop |
| $6C0C | ea | nop |
| $6C0D | ea | nop |
| $6C0E | ea | nop |
| $6C0F | ea | nop |
| $6C10 | ea | nop |
| $6C11 | ea | nop |
| $6C12 | ea | nop |
| $6C13 | ea | nop |
| $6C14 | ea | nop |
| $6C15 | a9 06 | lda#VicIIColors.BLUE; Restore background to blue ($06) |
| $6C17 | 8d 21 d0 | sta$d021; Background Color 0 |
| $6C1A | ad 2a 67 | ldamenu_cursor_index; Get menu selection index |
| $6C1D | 0a | asla; cursor_index * 16 |
| $6C1E | 0a | asla |
| $6C1F | 0a | asla |
| $6C20 | 0a | asla |
| $6C21 | 69 94 | adc#$94; + $94 = raster line for bottom highlight bar |
| $6C23 | a2 2a | ldx#<irq_menu_cursor_bottom |
| $6C25 | a0 6c | ldy#>irq_menu_cursor_bottom |
| $6C27 | 4c 7c 21 | jmpirq_chain_next; Chain to irq_menu_cursor_bottom |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| ; Menu cursor highlight — bottom bar raster IRQ. |
| ; Same pattern as irq_menu_cursor_top: NOP sled for stable raster, then |
| ; sets $D021 to light blue ($0E) for one character row, waits, then resets |
| ; $D021 to black ($00) (the default menu screen background). |
| ; Chains to irq_setup_status_bar_sprites at raster line $DC. |
| ; |
| ; Inputs: None (entered via IRQ vector) |
| ; Outputs: None |
| ; Side Effects: $D021 flashed to light blue then reset to black ($00) |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| irq_menu_cursor_bottom |
| $6C2A | ea | nop; NOP sled — stable raster timing ; x-ref: $6C23, $6C25 |
| $6C2B | ea | nop |
| $6C2C | ea | nop |
| $6C2D | ea | nop |
| $6C2E | ea | nop |
| $6C2F | ea | nop |
| $6C30 | ea | nop |
| $6C31 | ea | nop |
| $6C32 | ea | nop |
| $6C33 | ea | nop |
| $6C34 | ea | nop |
| $6C35 | ea | nop |
| $6C36 | a9 0e | lda#VicIIColors.LIGHT_BLUE; Set background to light blue ($0E) |
| $6C38 | 8d 21 d0 | sta$d021; Background Color 0 |
| $6C3B | ea | nop |
| $6C3C | ea | nop |
| $6C3D | ea | nop |
| $6C3E | ea | nop |
| $6C3F | ea | nop |
| $6C40 | ea | nop |
| $6C41 | ea | nop |
| $6C42 | ea | nop |
| $6C43 | ea | nop |
| $6C44 | ea | nop |
| $6C45 | ea | nop |
| $6C46 | ea | nop |
| $6C47 | ea | nop |
| $6C48 | ea | nop |
| $6C49 | ea | nop |
| $6C4A | ea | nop |
| $6C4B | ea | nop |
| $6C4C | ea | nop |
| $6C4D | ea | nop |
| $6C4E | ea | nop |
| $6C4F | ea | nop |
| $6C50 | ea | nop |
| $6C51 | ea | nop |
| $6C52 | ea | nop |
| $6C53 | ea | nop |
| $6C54 | ea | nop |
| $6C55 | ea | nop |
| $6C56 | ea | nop |
| $6C57 | ea | nop |
| $6C58 | ea | nop |
| $6C59 | a9 00 | lda#VicIIColors.BLACK; Reset background to black ($00) |
| $6C5B | 8d 21 d0 | sta$d021; Background Color 0 |
| $6C5E | a9 dc | lda#$dc; Next raster at $DC for status bar sprites |
| $6C60 | a2 67 | ldx#<irq_setup_status_bar_sprites |
| $6C62 | a0 6c | ldy#>irq_setup_status_bar_sprites |
| $6C64 | 4c 7c 21 | jmpirq_chain_next; Chain to irq_setup_status_bar_sprites |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| ; Raster IRQ handler that configures 6 sprites to form the bottom status bar. |
| ; Positions 3 pairs of sprites in two columns (X=$8B/$A3) at Y=$E6, |
| ; assigns consecutive sprite pointers $EF–$F4, and sets pair colors |
| ; (white, light blue, blue). Chains to the next raster IRQ at line $28. |
| ; |
| ; Inputs: None (entered via IRQ vector) |
| ; Outputs: None |
| ; Side Effects: VIC-II sprite registers $D000–$D02C, sprite pointers $07F8–$07FD, |
| ; next IRQ set at raster $28 with handler at $6B84 |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| irq_setup_status_bar_sprites |
| $6C67 | a9 8b | lda#$8b; X pos for left column sprites ; x-ref: $6C60, $6C62 |
| $6C69 | 8d 00 d0 | sta$d000; Sprite 0 X Pos |
| $6C6C | 8d 04 d0 | sta$d004; Sprite 2 X Pos |
| $6C6F | 8d 08 d0 | sta$d008; Sprite 4 X Pos |
| $6C72 | 18 | clc; Offset right column by 24px |
| $6C73 | 69 18 | adc#$18 |
| $6C75 | 8d 02 d0 | sta$d002; Sprite 1 X Pos |
| $6C78 | 8d 06 d0 | sta$d006; Sprite 3 X Pos |
| $6C7B | 8d 0a d0 | sta$d00a; Sprite 5 X Pos |
| $6C7E | a9 e6 | lda#$e6; Y=$E6: near bottom of screen |
| $6C80 | 8d 01 d0 | sta$d001; Sprite 0 Y Pos |
| $6C83 | 8d 03 d0 | sta$d003; Sprite 1 Y Pos |
| $6C86 | 8d 05 d0 | sta$d005; Sprite 2 Y Pos |
| $6C89 | 8d 07 d0 | sta$d007; Sprite 3 Y Pos |
| $6C8C | 8d 09 d0 | sta$d009; Sprite 4 Y Pos |
| $6C8F | 8d 0b d0 | sta$d00b; Sprite 5 Y Pos |
| $6C92 | a2 ef | ldx#$ef; Sprite pointers $EF-$F4 (blocks 239-244): LC GA |
| $6C94 | 8e f8 07 | stxSPRITE_PTR_0 |
| $6C97 | e8 | inx; #$f0 = MES |
| $6C98 | 8e f9 07 | stxSPRITE_PTR_1 |
| $6C9B | e8 | inx; #$F1 = LC GAM (highlight) |
| $6C9C | 8e fa 07 | stxSPRITE_PTR_2 |
| $6C9F | e8 | inx; #$F2 = MES (highlight) |
| $6CA0 | 8e fb 07 | stxSPRITE_PTR_3 |
| $6CA3 | e8 | inx; #$F3 = LC GA (highlight 2) |
| $6CA4 | 8e fc 07 | stxSPRITE_PTR_4 |
| $6CA7 | e8 | inx; #$F4 = MES (highlight 2) |
| $6CA8 | 8e fd 07 | stxSPRITE_PTR_5 |
| $6CAB | a9 01 | lda#VicIIColors.WHITE; White for pair 0-1 |
| $6CAD | 8d 27 d0 | sta$d027; Sprite 0 Color |
| $6CB0 | 8d 28 d0 | sta$d028; Sprite 1 Color |
| $6CB3 | a9 0e | lda#VicIIColors.LIGHT_BLUE; Light blue for pair 2-3 |
| $6CB5 | 8d 29 d0 | sta$d029; Sprite 2 Color |
| $6CB8 | 8d 2a d0 | sta$d02a; Sprite 3 Color |
| $6CBB | a9 06 | lda#VicIIColors.BLUE; Blue for pair 4-5 |
| $6CBD | 8d 2b d0 | sta$d02b; Sprite 4 Color |
| $6CC0 | 8d 2c d0 | sta$d02c; Sprite 5 Color |
| $6CC3 | a9 28 | lda#$28; Next raster IRQ at line $28 |
| $6CC5 | a2 84 | ldx#<irq_title_screen_sprites |
| $6CC7 | a0 6b | ldy#>irq_title_screen_sprites |
| $6CC9 | 4c 7c 21 | jmpirq_chain_next; Exit via IRQ epilogue |
| | .encode |
| | .enc"screen" |
| ; Controls high score screen behavior. |
| ; Bit 7 set ($FF) = show table only (no name entry). |
| ; Bit 7 clear (0-9) = player ranking position for name input. |
| high_score_screen_flag |
| $6CCC | | .text"@"; x-ref: $6D3E, $6D5F, $6E63, $6E75 |
| ; High score table title: "BEST HEROES" |
| $6CCD | | txt_best_heroes.text"BEST HEROES@"; x-ref: $6D68, $6D6C |
| ; High score table column header: "RANK SCORE LVL NAME" |
| $6CD9 | | txt_hiscore_header.text"RANK SCORE LVL NAME@"; x-ref: $6D7D, $6D81 |
| ; Rank label strings for the high score table, 4 chars each. |
| ; 10 entries: " 1ST", " 2ND", " 3RD", " 4TH" ... " 9TH", "10TH". |
| ; Followed by status messages ("SAVING DATA...", "RESETTING RANKING..."). |
| $6CF2 | | rank_label_strings.text" 1ST 2ND 3RD 4TH 5TH 6TH 7TH 8TH 9TH10TH"; x-ref: $6DB8 |
| ; Disk I/O status message: "SAVING DATA..." |
| $6D1A | | txt_saving_data.text"SAVING DATA...@"; x-ref: $6EE3, $6EE7 |
| ; High score reset status message: "RESETTING RANKING..." |
| txt_resetting_ranking |
| $6D29 | | .text"RESETTING RANKING...@"; x-ref: $6EB9, $6EBD |
| | .endencode |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| ; Initializes the High Scores / Scoreboard screen layout. |
| ; Saves the player's ranking slot index in high_score_screen_flag, transitions |
| ; game_state to GameState.GAME_OVER, blanks the display, configures VIC rows, clears |
| ; the screen RAM, draws the scoreboard tables via draw_high_score_table, and resets |
| ; active sprites. |
| ; Finally, checks high_score_screen_flag; if negative ($FF), returns immediately |
| ; (view-only mode). Otherwise, transitions to enter_high_score_name to let the |
| ; player enter their initials. |
| ; |
| ; Inputs: A = player ranking slot index (0-9), or $FF for view-only |
| ; Outputs: None |
| ; Side Effects: Sets game_state to GameState.GAME_OVER, configures VIC registers, |
| ; clears screen, draws high score table, resets sprites, enables screen |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| init_high_score_screen |
| $6D3E | 8d cc 6c | stahigh_score_screen_flag; Store ranking slot index / view flag ; x-ref: $1DCE, $62B4, $6AA7, $6ED9 |
| $6D41 | a9 04 | lda#GameState.GAME_OVER |
| $6D43 | 8d d3 20 | stagame_state; Store game state |
| $6D46 | 20 7e 36 | jsrblank_screen; Blank VIC-II display to hide redraw |
| $6D49 | 20 39 36 | jsrset_vic_scroll_and_rows; Set standard C128 scroll and 25-row mode |
| $6D4C | a9 00 | lda#$00; Disable dynamic tile zero-suppression |
| $6D4E | 8d 38 36 | stazero_suppress_disable |
| $6D51 | a0 01 | ldy#$01; Clear screen using character color index 1 (white) |
| $6D53 | 20 44 36 | jsrclear_screen; Wipe screen RAM |
| $6D56 | 20 68 6d | jsrdraw_high_score_table; Draw entire high score table layout |
| $6D59 | 20 d5 53 | jsrreset_all_sprites; Clear all hardware sprites from view |
| $6D5C | 20 67 36 | jsrenable_screen; Re-enable VIC-II display |
| $6D5F | ad cc 6c | ldahigh_score_screen_flag; Reload ranking slot index flag |
| $6D62 | 30 03 | bmir_6D67; Active-high/negative flag ($FF) -> view-only, exit (RTS) |
| $6D64 | 4c 61 6e | jmpenter_high_score_name; New high-score entry! Go to text input loop |
| $6D67 | 60 | r_6D67rts; Return from high score setup ; x-ref: $6D62 |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| ; Draws the complete high score table on the screen. |
| ; First prints the title "BEST HEROES" (green, at SCR_HISCORE_TITLE) and the |
| ; column header "RANK SCORE LVL NAME" (cyan, at SCR_HISCORE_HEADER). |
| ; Then loops through 10 score entries (7 bytes each in the score buffer), |
| ; rendering each row: |
| ; - Rank label from rank_label_strings (" 1ST", " 2ND", etc.) |
| ; - 6-digit BCD score at column +7 |
| ; - Level number at column +15 (or "---" if slot empty, $FF) |
| ; - 3-char player name at column +21 |
| ; Rows advance by $50 (80 bytes, C128 80-col screen layout). |
| ; |
| ; Inputs: Score buffer pointed to by set_score_buffer_ptr |
| ; Outputs: None |
| ; Side Effects: Writes to screen RAM from $04D0 downward, 10 rows |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| draw_high_score_table |
| $6D68 | a9 cd | lda#<txt_best_heroes; Source: "BEST HEROES" title string ; x-ref: $6D56 |
| $6D6A | 85 fb | stazp_ptr_src_lo |
| $6D6C | a9 6c | lda#>txt_best_heroes |
| $6D6E | 85 fc | stazp_ptr_src_hi |
| $6D70 | a9 37 | lda#<SCREEN_RAM_R1C15; Dest: screen row for title |
| $6D72 | 85 fd | stazp_ptr_dst_lo |
| $6D74 | a9 04 | lda#>SCREEN_RAM_R1C15 |
| $6D76 | 85 fe | stazp_ptr_dst_hi |
| $6D78 | a9 05 | lda#VicIIColors.GREEN; Color = green |
| $6D7A | 20 a8 36 | jsrdraw_text_with_color |
| $6D7D | a9 d9 | lda#<txt_hiscore_header; Source: "RANK SCORE LVL NAME" |
| $6D7F | 85 fb | stazp_ptr_src_lo |
| $6D81 | a9 6c | lda#>txt_hiscore_header |
| $6D83 | 85 fc | stazp_ptr_src_hi |
| $6D85 | a9 80 | lda#<SCREEN_RAM_R3C8 |
| $6D87 | 85 fd | stazp_ptr_dst_lo |
| $6D89 | a9 04 | lda#>SCREEN_RAM_R3C8 |
| $6D8B | 85 fe | stazp_ptr_dst_hi |
| $6D8D | a9 03 | lda#VicIIColors.CYAN; Color = cyan |
| $6D8F | 20 a8 36 | jsrdraw_text_with_color; Draw high score header text |
| $6D92 | a9 00 | lda#$00; Entry counter = 0 (10 entries total) |
| $6D94 | 85 06 | stazp_ptr_aux1_lo |
| $6D96 | 20 cb 53 | jsrset_score_buffer_ptr; Init score buffer pointer ($FB/$FC) |
| $6D99 | a5 fb | ldazp_ptr_src_lo; Save score buffer ptr to zpa_02/03 |
| $6D9B | 85 02 | stazp_work0 |
| $6D9D | a5 fc | ldazp_ptr_src_hi |
| $6D9F | 85 03 | stazp_work1 |
| $6DA1 | a9 d0 | lda#$d0; Screen row dest starts at $04D0 |
| $6DA3 | 85 04 | stazp_work2 |
| $6DA5 | a9 04 | lda#$04 |
| $6DA7 | 85 05 | stazp_work3 |
| $6DA9 | a5 04 | j_6DA9ldazp_work2; Copy screen ptr to $FB/$FC ; x-ref: $6E5D |
| $6DAB | 85 fb | stazp_ptr_src_lo |
| $6DAD | a5 05 | ldazp_work3 |
| $6DAF | 85 fc | stazp_ptr_src_hi |
| $6DB1 | a5 06 | ldazp_ptr_aux1_lo; Rank index * 4 for rank_label_strings |
| $6DB3 | 0a | asla |
| $6DB4 | 0a | asla |
| $6DB5 | aa | tax |
| $6DB6 | a0 00 | ldy#$00 |
| $6DB8 | bd f2 6c | b_6DB8ldarank_label_strings,x; Copy rank label chars to screen ; x-ref: $6DC1 |
| $6DBB | 91 fb | sta(zp_ptr_src_lo),y |
| $6DBD | e8 | inx |
| $6DBE | c8 | iny |
| $6DBF | c0 04 | cpy#$04 |
| $6DC1 | d0 f5 | bneb_6DB8 |
| $6DC3 | a5 02 | ldazp_work0; Restore score buffer ptr |
| $6DC5 | 85 fb | stazp_ptr_src_lo |
| $6DC7 | a5 03 | ldazp_work1 |
| $6DC9 | 85 fc | stazp_ptr_src_hi |
| $6DCB | a5 04 | ldazp_work2; Screen ptr + 7 → score column dest |
| $6DCD | 18 | clc |
| $6DCE | 69 07 | adc#$07 |
| $6DD0 | 85 fd | stazp_ptr_dst_lo |
| $6DD2 | a5 05 | ldazp_work3 |
| $6DD4 | 69 00 | adc#$00 |
| $6DD6 | 85 fe | stazp_ptr_dst_hi |
| $6DD8 | a2 06 | ldx#$06; Print 6-digit BCD score |
| $6DDA | 20 0e 37 | jsrprint_bcd_number; Print BCD score at screen + 7 |
| $6DDD | a5 02 | ldazp_work0 |
| $6DDF | 18 | clc |
| $6DE0 | 69 03 | adc#$03; Score entry + 3 = level byte |
| $6DE2 | 85 fb | stazp_ptr_src_lo |
| $6DE4 | a5 03 | ldazp_work1 |
| $6DE6 | 69 00 | adc#$00 |
| $6DE8 | 85 fc | stazp_ptr_src_hi |
| $6DEA | a5 04 | ldazp_work2; Screen ptr + 15 → level column dest |
| $6DEC | 18 | clc |
| $6DED | 69 0f | adc#$0f |
| $6DEF | 85 fd | stazp_ptr_dst_lo |
| $6DF1 | a5 05 | ldazp_work3 |
| $6DF3 | 69 00 | adc#$00 |
| $6DF5 | 85 fe | stazp_ptr_dst_hi |
| $6DF7 | a0 00 | ldy#$00 |
| $6DF9 | b1 fb | lda(zp_ptr_src_lo),y; Read level byte from score entry |
| $6DFB | c9 ff | cmp#$ff; $FF = empty slot |
| $6DFD | d0 0f | bneb_6E0E |
| $6DFF | a9 01 | lda#$01; Display "---" for empty entry |
| $6E01 | 91 fd | sta(zp_ptr_dst_lo),y |
| $6E03 | c8 | iny |
| $6E04 | a9 0c | lda#$0c |
| $6E06 | 91 fd | sta(zp_ptr_dst_lo),y |
| $6E08 | c8 | iny |
| $6E09 | 91 fd | sta(zp_ptr_dst_lo),y |
| $6E0B | 4c 16 6e | jmpj_6E16 |
| $6E0E | 18 | b_6E0Eclc; Level is 0-based, display as 1-based ; x-ref: $6DFD |
| $6E0F | 69 01 | adc#$01 |
| $6E11 | a2 03 | ldx#$03; 3 digits for level |
| $6E13 | 20 ef 36 | jsrprint_byte_as_decimal; Print level number at screen + 15 |
| $6E16 | a5 02 | j_6E16ldazp_work0; Score buffer + 4 → name ptr ; x-ref: $6E0B |
| $6E18 | 18 | clc |
| $6E19 | 69 04 | adc#$04; Score entry + 4 = 3-char name |
| $6E1B | 85 fb | stazp_ptr_src_lo |
| $6E1D | a5 03 | ldazp_work1 |
| $6E1F | 69 00 | adc#$00 |
| $6E21 | 85 fc | stazp_ptr_src_hi |
| $6E23 | a5 04 | ldazp_work2; Screen ptr + 21 → name column dest |
| $6E25 | 18 | clc |
| $6E26 | 69 15 | adc#$15 |
| $6E28 | 85 fd | stazp_ptr_dst_lo |
| $6E2A | a5 05 | ldazp_work3 |
| $6E2C | 69 00 | adc#$00 |
| $6E2E | 85 fe | stazp_ptr_dst_hi |
| $6E30 | a0 00 | ldy#$00 |
| $6E32 | b1 fb | b_6E32lda(zp_ptr_src_lo),y; Copy 3-char player name to screen ; x-ref: $6E39 |
| $6E34 | 91 fd | sta(zp_ptr_dst_lo),y |
| $6E36 | c8 | iny |
| $6E37 | c0 03 | cpy#$03 |
| $6E39 | d0 f7 | bneb_6E32 |
| $6E3B | e6 06 | inczp_ptr_aux1_lo; Next entry (index++) |
| $6E3D | a5 06 | ldazp_ptr_aux1_lo |
| $6E3F | c9 0a | cmp#$0a; Done all 10 entries? |
| $6E41 | f0 1d | beqr_6E60 |
| $6E43 | a5 02 | ldazp_work0; Score buffer ptr += 7 (entry size) |
| $6E45 | 18 | clc |
| $6E46 | 69 07 | adc#$07; Next score entry (+7 bytes each) |
| $6E48 | 85 02 | stazp_work0 |
| $6E4A | a5 03 | ldazp_work1 |
| $6E4C | 69 00 | adc#$00 |
| $6E4E | 85 03 | stazp_work1 |
| $6E50 | a5 04 | ldazp_work2; Screen ptr += $50 (next row, 80 cols) |
| $6E52 | 18 | clc |
| $6E53 | 69 50 | adc#$50; Next screen row (+$50, 80 cols) |
| $6E55 | 85 04 | stazp_work2 |
| $6E57 | a5 05 | ldazp_work3 |
| $6E59 | 69 00 | adc#$00 |
| $6E5B | 85 05 | stazp_work3 |
| $6E5D | 4c a9 6d | jmpj_6DA9; Loop back for next entry |
| $6E60 | 60 | r_6E60rts; x-ref: $6E41 |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| ; Prompts the player to enter their 3-character initials for the high score |
| ; table, copies the entered name into the score buffer at the correct rank |
| ; position, then displays the updated table and saves it to disk. |
| ; |
| ; Inputs: a_6CCC = player's ranking position (0-9) |
| ; Outputs: Score buffer updated with player's initials |
| ; Side Effects: Screen redrawn with high score table, scores saved to disk |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| enter_high_score_name |
| $6E61 | a2 1d | ldx#$1d; X = screen column for name input ; x-ref: $6D64 |
| $6E63 | ad cc 6c | ldahigh_score_screen_flag; Load player's ranking position |
| $6E66 | 0a | asla; rank * 2 |
| $6E67 | 18 | clc |
| $6E68 | 69 05 | adc#$05; Y = screen row (rank*2 + 5) |
| $6E6A | a8 | tay |
| $6E6B | a9 03 | lda#$03; A = max 3 chars for initials |
| $6E6D | 20 72 5c | jsrinput_text_string; Prompt player for name entry |
| $6E70 | 20 cb 53 | jsrset_score_buffer_ptr; Point $FB/$FC at score buffer |
| $6E73 | a9 04 | lda#$04; A = starting offset in buffer |
| $6E75 | ae cc 6c | ldxhigh_score_screen_flag; Get rank slot for name storage offset |
| $6E78 | f0 06 | beqb_6E80; Rank 0 → offset stays at 4 |
| $6E7A | 18 | clc |
| $6E7B | 69 07 | b_6E7Badc#$07; Add 7 per rank to reach name field ; x-ref: $6E7E |
| $6E7D | ca | dex |
| $6E7E | d0 fb | bneb_6E7B |
| $6E80 | a8 | b_6E80tay; Y = offset to name field in buffer ; x-ref: $6E78 |
| $6E81 | a2 00 | ldx#$00 |
| $6E83 | bd d9 5b | b_6E83ldainput_text_buffer,x; Copy entered char from input buffer ; x-ref: $6E8E |
| $6E86 | f0 08 | beqb_6E90; Skip if null terminator |
| $6E88 | 91 fb | sta(zp_ptr_src_lo),y; Store char in score buffer |
| $6E8A | c8 | iny |
| $6E8B | e8 | inx |
| $6E8C | e0 03 | cpx#$03; Copy up to 3 chars |
| $6E8E | d0 f3 | bneb_6E83 |
| $6E90 | 20 dd 6e | b_6E90jsrshow_saving_and_save_scores; Display final table and save to disk ; x-ref: $6E86 |
| $6E93 | 4c 5e 69 | jmpshow_main_menu; Return to title/game screen |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| ; Ticks the high score / scoreboard screen once per frame. |
| ; Polls the joystick fire button; a new click instantly transitions back to the |
| ; main menu. |
| ; If fire is not pressed, polls keyboard row 0 for the RUN/STOP key. A new RUN/STOP |
| ; click triggers a scoreboard factory reset: |
| ; 1. Displays "RESETTING RANKING..." message |
| ; 2. Restores default score list via init_default_high_scores |
| ; 3. Flushes default high scores to the floppy disk via save_high_scores_to_disk |
| ; 4. Reloads the high score table screen |
| ; |
| ; Inputs: joystick_state ($3E80), joystick_prev_state ($3E81), |
| ; kb_row0_cur ($3F0C), kb_row0_prev ($3F0D) |
| ; Outputs: None |
| ; Side Effects: Clears screen, overwrites high score floppy file, reloads |
| ; scoreboard view, or exits back to main menu |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| update_high_score_screen |
| $6E96 | ad 80 3e | ldajoystick_state; Read current joystick state ; x-ref: $2130 |
| $6E99 | 29 10 | and#$10; Isolate fire button bit (bit 4) |
| $6E9B | d0 0a | bneb_6EA7; Active-low: fire released -> check keyboard input |
| $6E9D | ad 81 3e | ldajoystick_prev_state; Read previous frame joystick state |
| $6EA0 | 29 10 | and#$10 |
| $6EA2 | f0 03 | beqb_6EA7; Zero = already pressed last frame (hold check), abort |
| $6EA4 | 4c 5e 69 | jmpshow_main_menu; New fire click! Return back to main menu |
| $6EA7 | ad 0c 3f | b_6EA7ldakb_row0_cur; Read current keyboard row 0 state ; x-ref: $6E9B, $6EA2 |
| $6EAA | cd 0d 3f | cmpkb_row0_prev; Check if keyboard state changed |
| $6EAD | f0 2d | beqr_6EDC; No key change: exit screen tick |
| $6EAF | c9 ef | cmp#$ef; Check if RUN/STOP key is pressed |
| $6EB1 | d0 29 | bner_6EDC; Not RUN/STOP: exit screen tick |
| $6EB3 | 20 7e 36 | jsrblank_screen; Blank VIC-II display to hide layout draw |
| $6EB6 | 20 44 36 | jsrclear_screen; Wipe screen RAM clean |
| $6EB9 | a9 29 | lda#<txt_resetting_ranking; Source pointer = 'RESETTING RANKING...' text |
| $6EBB | 85 fb | stazp_ptr_src_lo |
| $6EBD | a9 6d | lda#>txt_resetting_ranking |
| $6EBF | 85 fc | stazp_ptr_src_hi |
| $6EC1 | a9 ea | lda#<SCREEN_RAM_R12C10; Destination pointer = screen RAM row 15 |
| $6EC3 | 85 fd | stazp_ptr_dst_lo |
| $6EC5 | a9 05 | lda#>SCREEN_RAM_R12C10 |
| $6EC7 | 85 fe | stazp_ptr_dst_hi |
| $6EC9 | a9 01 | lda#VicIIColors.WHITE; Draw message text in White |
| $6ECB | 20 a8 36 | jsrdraw_text_with_color |
| $6ECE | 20 67 36 | jsrenable_screen; Re-enable VIC-II display |
| $6ED1 | 20 26 53 | jsrinit_default_high_scores; Reset high score data table to defaults |
| $6ED4 | 20 f7 52 | jsrsave_high_scores_to_disk; Write default scoreboard to floppy disk |
| $6ED7 | a9 ff | lda#$ff; Load default ranking code ($FF) |
| $6ED9 | 4c 3e 6d | jmpinit_high_score_screen; Reload high score table screen |
| $6EDC | 60 | r_6EDCrts; Return from scoreboard screen update ; x-ref: $6EAD, $6EB1 |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| ; Displays "SAVING DATA..." message on a blank screen, resets sprites, re-enables |
| ; the display, then saves high scores to disk via save_high_scores_to_disk. |
| ; Called when exiting gameplay (RUN/STOP or high-score entry complete) while a |
| ; game was in progress. |
| ; |
| ; Inputs: None |
| ; Outputs: None |
| ; Side Effects: Blanks/clears screen, displays save message, resets sprites, |
| ; re-enables VIC-II display, writes high scores to disk |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| show_saving_and_save_scores |
| $6EDD | 20 7e 36 | jsrblank_screen; Turn off display to avoid glitches ; x-ref: $6196, $62AE, $6E90 |
| $6EE0 | 20 44 36 | jsrclear_screen; Wipe screen RAM |
| $6EE3 | a9 1a | lda#<txt_saving_data; src = "SAVING DATA..." text |
| $6EE5 | 85 fb | stazp_ptr_src_lo |
| $6EE7 | a9 6d | lda#>txt_saving_data |
| $6EE9 | 85 fc | stazp_ptr_src_hi |
| $6EEB | a9 ed | lda#<SCREEN_RAM_R12C13; dst = screen position $05ED |
| $6EED | 85 fd | stazp_ptr_dst_lo |
| $6EEF | a9 05 | lda#>SCREEN_RAM_R12C13 |
| $6EF1 | 85 fe | stazp_ptr_dst_hi |
| $6EF3 | a9 01 | lda#VicIIColors.WHITE; color 1 = white |
| $6EF5 | 20 a8 36 | jsrdraw_text_with_color; Render "SAVING DATA..." on screen |
| $6EF8 | 20 d5 53 | jsrreset_all_sprites; Remove all sprites from display |
| $6EFB | 20 67 36 | jsrenable_screen; Re-enable VIC-II display (set DEN bit) |
| $6EFE | 4c f7 52 | jmpsave_high_scores_to_disk; Tail call: save scores and return |
| $6F01 | | explosion_state.byte$00; x-ref: $4FF8, $6494, $6F11, $6F19, $6F3E, ... |
| $6F02 | | explosion_x_lo.byte$00; x-ref: $6FBD, $6FEC, $7021, $7046, $7079 |
| $6F03 | | explosion_x_hi.byte$00; x-ref: $6FC4, $6FF4, $7027, $704C, $7081 |
| $6F04 | | explosion_y.byte$00; x-ref: $6FB4, $6FE4, $7030, $7052, $7088 |
| $6F05 | | explosion_frame.byte$00; x-ref: $6F55, $6F77, $6F7A, $6F83, $6F8E, ... |
| $6F06 | | explosion_color.byte$00; x-ref: $649B, $6F4C, $6F99 |
| $6F07 | | explosion_anim_tick.byte$00; x-ref: $6F68, $6F6B, $6F74, $705C |
| $6F08 | | explosion_timer.byte$00; x-ref: $6F20, $6F32, $6F35, $6F5D, $6F93, ... |
| explosion_color_table |
| $6F09 | | .byteVicIIColors.WHITE; white ; x-ref: $6F49, $6F96 |
| $6F0A | | .byteVicIIColors.BLACK; black |
| $6F0B | | .byteVicIIColors.YELLOW; yellow |
| $6F0C | | .byteVicIIColors.ORANGE; orange |
| $6F0D | | .byteVicIIColors.RED; red |
| $6F0E | | .byteVicIIColors.BLACK; black |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| ; Resets the screen color flash subsystem to its idle state. |
| ; Clears the state variable (a_6F01) so no flash animation runs, |
| ; and restores the default screen color (yellow = 7) via zpa_82. |
| ; |
| ; Inputs: None |
| ; Outputs: a_6F01 = 0, zpa_82 = 7 |
| ; Side Effects: Stops any active color flash animation |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| $6F0F | a9 00 | reset_color_flashlda#$00; idle state: no flash active ; x-ref: $4B01 |
| $6F11 | 8d 01 6f | staexplosion_state; clear flash state machine |
| $6F14 | a9 07 | lda#VicIIColors.YELLOW; 7 = yellow (default color) |
| $6F16 | 85 82 | stazp_screen_color; restore default screen color (yellow) |
| $6F18 | 60 | rts |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| ; Explosion animation state machine. Called every frame from the main game loop. |
| ; Dispatches on explosion_state ($6F01): |
| ; State 0: Inactive — do nothing. |
| ; State 1: Countdown delay, then init explosion (state 2) + check hero proximity. |
| ; State 2: Animate explosion — cycle colors from table, advance sprite frames |
| ; ($A1–$A4). After 6 color ticks, deactivate and check entity collisions. |
| ; State 3: Fade-out — decrement timer, then deactivate. |
| ; |
| ; Inputs: explosion_state ($6F01), explosion_timer ($6F08) |
| ; Outputs: explosion_state, explosion_frame, explosion_color, explosion_anim_tick |
| ; Side Effects: May trigger entity destroy (j_875A) or hero death (j_8185) |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| $6F19 | ad 01 6f | update_explosionldaexplosion_state; Read current explosion state ; x-ref: $61DD |
| $6F1C | c9 01 | cmp#$01; State 1? (countdown delay) |
| $6F1E | d0 0e | bneb_6F2E |
| $6F20 | ce 08 6f | decexplosion_timer; Decrement delay timer |
| $6F23 | d0 06 | bneb_6F2B |
| $6F25 | 20 87 6f | jsrinit_explosion; Timer expired → start explosion animation |
| $6F28 | 4c df 6f | jmpcheck_hero_explosion_hit; Then check hero proximity |
| $6F2B | 4c 68 6f | b_6F2Bjmptick_explosion_anim; Timer not expired → tick animation frame ; x-ref: $6F23 |
| $6F2E | c9 02 | b_6F2Ecmp#$02; State 2? (active explosion) ; x-ref: $6F1E |
| $6F30 | d0 27 | bneb_6F59 |
| $6F32 | ee 08 6f | incexplosion_timer; Increment timer for color cycling |
| $6F35 | ae 08 6f | ldxexplosion_timer |
| $6F38 | e0 06 | cpx#$06; 6 ticks → explosion finished |
| $6F3A | d0 0d | bneb_6F49 |
| $6F3C | a9 00 | lda#$00; Deactivate explosion |
| $6F3E | 8d 01 6f | staexplosion_state |
| $6F41 | a9 00 | lda#VicIIColors.BLACK; Set screen color to black |
| $6F43 | 20 be 50 | jsrset_screen_color |
| $6F46 | 4c a2 6f | jmpcheck_entity_explosion_hit; Check entity collisions with explosion |
| $6F49 | bd 09 6f | b_6F49ldaexplosion_color_table,x; Load color from cycling table ; x-ref: $6F3A white |
| $6F4C | 8d 06 6f | staexplosion_color; Set current explosion color |
| $6F4F | e0 03 | cpx#$03; At color index 3? |
| $6F51 | d0 05 | bner_6F58 |
| $6F53 | a9 a5 | lda#$a5; Set special frame $A5 at midpoint |
| $6F55 | 8d 05 6f | staexplosion_frame |
| $6F58 | 60 | r_6F58rts; x-ref: $6F51 |
| $6F59 | c9 03 | b_6F59cmp#$03; State 3? (fade-out) ; x-ref: $6F30 |
| $6F5B | d0 0a | bner_6F67 |
| $6F5D | ce 08 6f | decexplosion_timer; Decrement fade-out timer |
| $6F60 | d0 05 | bner_6F67 |
| $6F62 | a9 00 | lda#$00; Timer expired → deactivate explosion |
| $6F64 | 8d 01 6f | staexplosion_state; Clear explosion state |
| $6F67 | 60 | r_6F67rts; ; x-ref: $6F5B, $6F60 |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| ; Advances the explosion animation by one tick. Increments anim_tick; every 4 |
| ; ticks advances to the next sprite frame, cycling through $A1-$A3. |
| ; |
| ; Inputs: explosion_anim_tick, explosion_frame |
| ; Outputs: explosion_anim_tick (incremented, wraps at 4), explosion_frame |
| ; Side Effects: None |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| $6F68 | ee 07 6f | tick_explosion_animincexplosion_anim_tick; Increment animation sub-tick counter ; x-ref: $6F2B |
| $6F6B | ad 07 6f | ldaexplosion_anim_tick |
| $6F6E | c9 04 | cmp#$04; Every 4 sub-ticks? |
| $6F70 | d0 14 | bner_6F86 |
| $6F72 | a9 00 | lda#$00; Reset sub-tick counter |
| $6F74 | 8d 07 6f | staexplosion_anim_tick |
| $6F77 | ee 05 6f | incexplosion_frame; Advance to next sprite frame |
| $6F7A | ad 05 6f | ldaexplosion_frame |
| $6F7D | c9 a4 | cmp#$a4; Past frame $A3? |
| $6F7F | d0 05 | bner_6F86 |
| $6F81 | a9 a1 | lda#$a1; Wrap back to first explosion frame $A1 |
| $6F83 | 8d 05 6f | staexplosion_frame |
| $6F86 | 60 | r_6F86rts; x-ref: $6F70, $6F7F |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| ; Initializes the explosion animation. Sets state to 2 (active), resets frame |
| ; to $A4, loads initial color from explosion_color_table, and signals active. |
| ; |
| ; Inputs: explosion_color_table ($6F09) |
| ; Outputs: explosion_state=2, explosion_frame=$A4, explosion_timer=0, |
| ; explosion_color from table, a_88EC=1 |
| ; Side Effects: None |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| $6F87 | a9 02 | init_explosionlda#$02; State = 2 (active explosion) ; x-ref: $4FFF, $6F25 |
| $6F89 | 8d 01 6f | staexplosion_state; Set explosion state to active |
| $6F8C | a9 a4 | lda#$a4; Start at sprite frame $A4 |
| $6F8E | 8d 05 6f | staexplosion_frame; Store initial frame |
| $6F91 | a9 00 | lda#$00; Reset timer to 0 |
| $6F93 | 8d 08 6f | staexplosion_timer; Clear explosion timer |
| $6F96 | ad 09 6f | ldaexplosion_color_table; Load initial color from table[0]; white |
| $6F99 | 8d 06 6f | staexplosion_color; Set explosion display color |
| $6F9C | a9 01 | lda#$01; Signal explosion active |
| $6F9E | 8d ec 88 | stasfx_hit_state; Flag explosion as active |
| $6FA1 | 60 | rts |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| ; Checks all active entities for collision with the explosion. Iterates through |
| ; entity slots; if an entity's Y matches explosion_y and X is within 25 pixels, |
| ; calls j_875A to destroy it. |
| ; |
| ; Inputs: a_85E4 (entity count), f_85C9/D5/CF/D2 (entity tables), |
| ; explosion_x_lo/hi, explosion_y |
| ; Outputs: None (entities may be destroyed via j_875A) |
| ; Side Effects: May destroy entities within blast radius |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| check_entity_explosion_hit |
| $6FA2 | ae e4 85 | ldxdynamic_tile_count; Load active entity count ; x-ref: $5009, $6F46 |
| $6FA5 | d0 01 | bneb_6FA8; Any entities? Skip if none |
| $6FA7 | 60 | rts |
| $6FA8 | ca | b_6FA8dex; Convert count to 0-based index ; x-ref: $6FA5 |
| $6FA9 | bd c9 85 | b_6FA9ldadtile_id,x; Tile active? ; x-ref: $6FDC |
| $6FAC | f0 2d | beqb_6FDB |
| $6FAE | bd d5 85 | ldadtile_x,x; Tile pixel X |
| $6FB1 | 18 | clc |
| $6FB2 | 69 09 | adc#$09 |
| $6FB4 | cd 04 6f | cmpexplosion_y; Same row as explosion? |
| $6FB7 | d0 22 | bneb_6FDB |
| $6FB9 | bd cf 85 | ldadtile_y_lo,x; Tile pixel Y lo |
| $6FBC | 38 | sec |
| $6FBD | ed 02 6f | sbcexplosion_x_lo |
| $6FC0 | a8 | tay; Entity X hi - explosion X hi |
| $6FC1 | bd d2 85 | ldadtile_y_hi,x; Tile pixel Y hi |
| $6FC4 | ed 03 6f | sbcexplosion_x_hi |
| $6FC7 | d0 07 | bneb_6FD0 |
| $6FC9 | c0 19 | cpy#$19; Within 25 pixels? ($19) |
| $6FCB | b0 0e | bcsb_6FDB |
| $6FCD | 4c 5a 87 | jmpj_875A; Yes → destroy entity |
| $6FD0 | c9 ff | b_6FD0cmp#$ff; High byte = $FF? (negative offset) ; x-ref: $6FC7 |
| $6FD2 | d0 07 | bneb_6FDB |
| $6FD4 | c0 e8 | cpy#$e8; Within -24 pixels? ($E8 = -24) |
| $6FD6 | 90 03 | bccb_6FDB |
| $6FD8 | 4c 5a 87 | jmpj_875A; Yes → destroy entity |
| $6FDB | ca | b_6FDBdex; Next entity slot ; x-ref: $6FAC, $6FB7, $6FCB, $6FD2, $6FD6 |
| $6FDC | 10 cb | bplb_6FA9; More entities to check? |
| $6FDE | 60 | rts |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| ; Checks if the hero is within the explosion blast radius. If a_7AFA is nonzero |
| ; (hero invulnerable/dead), skips the check. Compares explosion position against |
| ; hero position; if within ±30 pixels on X and same Y row, calls j_8185 (hero death). |
| ; |
| ; Inputs: explosion_x_lo/hi, explosion_y, a_7AFB/7AFC/7AFD (hero position) |
| ; Outputs: None |
| ; Side Effects: May trigger hero death via j_8185 |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| check_hero_explosion_hit |
| $6FDF | ad fa 7a | ldahero_state; Hero status (nonzero = invulnerable/dead) ; x-ref: $6F28 |
| $6FE2 | d0 2a | bner_700E; Hero not idle → bail out |
| $6FE4 | ad 04 6f | ldaexplosion_y; Same Y row as explosion? |
| $6FE7 | cd fd 7a | cmphero_y_pos |
| $6FEA | d0 22 | bner_700E; Y coords differ → no hit |
| $6FEC | ad 02 6f | ldaexplosion_x_lo; Explosion X - hero X (lo byte) |
| $6FEF | 38 | sec |
| $6FF0 | ed fb 7a | sbchero_x_lo |
| $6FF3 | a8 | tay; Low byte of distance → Y reg |
| $6FF4 | ad 03 6f | ldaexplosion_x_hi; Explosion X - hero X (hi byte) |
| $6FF7 | ed fc 7a | sbchero_x_hi; Subtract hero X high byte (with borrow) |
| $6FFA | d0 07 | bneb_7003; High byte nonzero → check negative case |
| $6FFC | c0 1e | cpy#$1e; Within 30 pixels? ($1E) |
| $6FFE | b0 0e | bcsr_700E; Distance >= 30 → no hit |
| $7000 | 4c 85 81 | jmpj_8185; Yes → hero death |
| $7003 | c9 ff | b_7003cmp#$ff; High byte = $FF? (negative offset) ; x-ref: $6FFA |
| $7005 | d0 07 | bner_700E; High byte not $FF → too far |
| $7007 | c0 e3 | cpy#$e3; Within -29 pixels? ($E3 = -29) |
| $7009 | 90 03 | bccr_700E; Too far left → no hit |
| $700B | 4c 85 81 | jmpj_8185; Yes → hero death |
| $700E | 60 | r_700Erts; x-ref: $6FE2, $6FEA, $6FFE, $7005, $7009 |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| ; Triggered when an enemy collision occurs. Starts the explosion fade-out |
| ; (state 3) if currently inactive, or continues the existing state 3. |
| ; |
| ; Inputs: explosion_state, entity position in X register |
| ; Outputs: explosion_state=3, explosion position set from entity tables |
| ; Side Effects: Sets explosion_timer to $1E (30 frames) |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| start_explosion_from_hit |
| $700F | ad 01 6f | ldaexplosion_state; Current explosion state ; x-ref: $880C |
| $7012 | f0 05 | beqb_7019; State 0 (inactive)? → start new |
| $7014 | c9 03 | cmp#$03; Already in state 3? → update position |
| $7016 | f0 06 | beqb_701E |
| $7018 | 60 | rts |
| $7019 | a9 03 | b_7019lda#$03; Set state to 3 (fade-out) ; x-ref: $7012 |
| $701B | 8d 01 6f | staexplosion_state |
| $701E | bd cf 85 | b_701Eldadtile_y_lo,x; Copy entity X lo to explosion X ; x-ref: $7016 |
| $7021 | 8d 02 6f | staexplosion_x_lo |
| $7024 | bd d2 85 | ldadtile_y_hi,x |
| $7027 | 8d 03 6f | staexplosion_x_hi; Copy entity X hi to explosion X |
| $702A | bd d5 85 | ldadtile_x,x |
| $702D | 38 | sec |
| $702E | e9 05 | sbc#$05 |
| $7030 | 8d 04 6f | staexplosion_y; Entity Y - 5 = explosion Y (center offset) |
| $7033 | a9 a6 | lda#$a6 |
| $7035 | 8d 05 6f | staexplosion_frame; Set starting frame $A6 |
| $7038 | a9 1e | lda#$1e |
| $703A | 8d 08 6f | staexplosion_timer; Set timer to 30 frames ($1E) |
| $703D | 60 | rts |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| ; Initializes explosion at the hero's position. Sets state to 1 (countdown |
| ; delay), copies hero coordinates, and sets screen color to yellow. |
| ; Called when hero is hit by an enemy. |
| ; |
| ; Inputs: a_7AFB/7AFC/7AFD (hero position) |
| ; Outputs: explosion_state=1, explosion position from hero, explosion_timer=$1E |
| ; Side Effects: Sets screen color to $0B (dark grey), a_8940=1 |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| $703E | a9 01 | init_hero_explosionlda#$01; State = 1 (countdown delay) ; x-ref: $7C4B |
| $7040 | 8d 01 6f | staexplosion_state; Activate blast effect state machine |
| $7043 | ad fb 7a | ldahero_x_lo; Copy hero X lo to explosion X |
| $7046 | 8d 02 6f | staexplosion_x_lo; Store as effect X position (low) |
| $7049 | ad fc 7a | ldahero_x_hi; Load blast origin X position (high) |
| $704C | 8d 03 6f | staexplosion_x_hi; Copy hero X hi to explosion X |
| $704F | ad fd 7a | ldahero_y_pos; Copy hero Y to explosion Y |
| $7052 | 8d 04 6f | staexplosion_y; Store as effect Y position |
| $7055 | a9 a1 | lda#$a1; Starting frame $A1 |
| $7057 | 8d 05 6f | staexplosion_frame; Set display character for effect |
| $705A | a9 00 | lda#$00; Clear anim tick counter |
| $705C | 8d 07 6f | staexplosion_anim_tick |
| $705F | a9 1e | lda#$1e; Set timer to 30 frames |
| $7061 | 8d 08 6f | staexplosion_timer; Set effect frame counter |
| $7064 | a9 0b | lda#VicIIColors.DARK_GREY; Set screen color to dark grey ($0B) |
| $7066 | 20 be 50 | jsrset_screen_color; Apply blast color to screen |
| $7069 | a9 01 | lda#$01; Signal hero explosion active |
| $706B | 8d 40 89 | stasfx_explosion_state; Enable blast processing |
| $706E | 60 | rts |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| ; Prepares explosion sprite parameters for the multiplexer. |
| ; If no explosion is active, hides the sprite by setting Y to $FF. |
| ; Otherwise, converts explosion world position to screen coordinates |
| ; (X += $0C, Y += $25), copies the animation frame, and stores all |
| ; values into the zero-page sprite parameter slots. |
| ; |
| ; Inputs: explosion_state, explosion_x_lo/hi, explosion_y, explosion_frame |
| ; Outputs: zpa_36 (Y pos), zpa_49 (X lo), zpa_5C (X hi), zpa_6F (frame) |
| ; Side Effects: None |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| setup_explosion_sprite |
| $706F | ad 01 6f | ldaexplosion_state; Is explosion active? ; x-ref: $647A |
| $7072 | d0 05 | bneb_7079; Yes -> set up sprite coords |
| $7074 | a9 ff | lda#$ff; $FF = offscreen Y (hide sprite) |
| $7076 | 85 36 | stazp_mux_y_explode; Store Y pos = offscreen |
| $7078 | 60 | rts |
| $7079 | ad 02 6f | b_7079ldaexplosion_x_lo; Explosion world X (lo) ; x-ref: $7072 |
| $707C | 18 | clc |
| $707D | 69 0c | adc#$0c; Add $0C pixel offset to center sprite |
| $707F | 85 49 | stazp_mux_x_lo_explode; Store screen X lo for multiplexer |
| $7081 | ad 03 6f | ldaexplosion_x_hi; Explosion world X (hi) |
| $7084 | 69 00 | adc#$00; Propagate carry to hi byte |
| $7086 | 85 5c | stazp_mux_x_hi_explode; Store screen X hi for multiplexer |
| $7088 | ad 04 6f | ldaexplosion_y; Explosion world Y |
| $708B | 18 | clc |
| $708C | 69 25 | adc#$25; Add $25 pixel offset to center sprite |
| $708E | 85 36 | stazp_mux_y_explode; Store screen Y for multiplexer |
| $7090 | ad 05 6f | ldaexplosion_frame; Current animation frame index |
| $7093 | 85 6f | stazp_mux_frame_explode; Store sprite frame for multiplexer |
| $7095 | 60 | rts |
| ; Entity status array (15 slots, indexed by X). |
| ; Values: 0 = active/alive, 2 = inactive/dead. |
| ; Used by both the animated-tile subsystem and the |
| ; enemy collision routines to skip dead entities. |
| $7096 | | entity_status.fill15, $00; x-ref: $1F28, $1FD0, $2014, $723D, $7243, ... |
| ; Entity type array (15 slots, indexed by X). |
| ; Values: 0-4 select tile behavior, hitbox, animation. |
| ; Used to dispatch per-type update, collision, and init logic. |
| $70A5 | | entity_type.fill15, $00; x-ref: $1FC9, $2028, $7225, $726B, $73C6, ... |
| ; Entity X position fractional byte (15 slots, indexed by X). |
| ; Sub-pixel precision for smooth 24-bit movement. |
| ; Combined with entity_x_lo/entity_x_hi for full position. |
| $70B4 | | entity_x_frac.fill15, $00; x-ref: $725C, $7419, $7420, $74F1, $74F7, ... |
| ; Entity X position low byte (15 slots, indexed by X). |
| ; Pixel-level X coordinate, used in collision checks. |
| ; Mid byte of 24-bit position (frac/lo/hi). |
| $70C3 | | entity_x_lo.fill15, $00; x-ref: $1F43, $1FEB, $2046, $7275, $72A9, ... |
| ; Entity X position high byte (15 slots, indexed by X). |
| ; Screen page for X coordinate, used in collision checks. |
| ; High byte of 24-bit position (frac/lo/hi). |
| $70D2 | | entity_x_hi.fill15, $00; x-ref: $1F4A, $1FF2, $204D, $727C, $72B0, ... |
| ; Entity Y position fractional byte (15 slots, indexed by X). |
| ; Sub-pixel precision for gravity/spring physics. |
| ; Combined with entity_y for smooth vertical movement. |
| $70E1 | | entity_y_frac.fill15, $00; x-ref: $725F, $747E, $7485 |
| ; Entity Y position in pixels (15 slots, indexed by X). |
| ; Used in collision checks and rendering. |
| ; For type 2 entities, updated by gravity physics. |
| $70F0 | | entity_y.fill15, $00; x-ref: $1F34, $1FDC, $201D, $7284, $72B5, ... |
| ; Entity current animation frame/tile index (15 slots, indexed by X). |
| ; Holds the tile character code ($A7-$B8 range). |
| ; Used by renderer and for sub-type hitbox refinement. |
| $70FF | | entity_frame.fill15, $00; x-ref: $728A, $72C6, $7310, $736C, $739C, ... |
| ; Entity animation speed / color (15 slots, indexed by X). |
| ; During init, set per entity type (5-14). |
| ; Also bulk-initialized as sprite color at $50B7. |
| $710E | | entity_anim_speed.fill15, $00; x-ref: $50B7, $728F, $72CB, $7371, $73A1, ... |
| ; Entity X position target/limit low byte (15 slots, indexed by X). |
| ; Used by type 2 gravity physics as the X convergence target. |
| ; Compared against entity_x_lo to determine accel/decel. |
| $711D | | entity_x_limit_lo.fill15, $00; x-ref: $72E8, $7442 |
| ; Entity X position target/limit high byte (15 slots, indexed by X). |
| ; Used by type 2 gravity physics as the X convergence target. |
| ; Compared against entity_x_hi to determine accel/decel. |
| $712C | | entity_x_limit_hi.fill15, $00; x-ref: $72F2, $7438 |
| ; Entity Y position target/limit (15 slots, indexed by X). |
| ; Used by type 1 (vertical oscillation) and type 2 (gravity). |
| ; Gravity physics accelerates toward this Y value. |
| $713B | | entity_y_limit.fill15, $00; x-ref: $72B8, $72FD, $740E, $7494 |
| ; Entity X velocity low byte (15 slots, indexed by X). |
| ; Type 2 gravity: fractional velocity, difficulty-scaled. |
| ; Values: $00 (mid/hard) or $21 (easy). |
| $714A | | entity_vel_x_lo.fill15, $00; x-ref: $731C, $7330, $7340, $741D, $7447, ... |
| ; Entity X velocity mid byte (15 slots, indexed by X). |
| ; Type 2 gravity: pixel-level velocity component. |
| ; Values: $01 (easy), $02 (mid), $04 (hard). |
| $7159 | | entity_vel_x_mid.fill15, $00; x-ref: $7321, $7335, $7345, $7426, $7451, ... |
| ; Entity X velocity high byte (15 slots, indexed by X). |
| ; Type 2 gravity: page-level velocity for fast-moving entities. |
| ; Usually 0; carries from mid byte during acceleration. |
| $7168 | | entity_vel_x_hi.fill15, $00; x-ref: $7302, $742F, $7459, $745E, $7476, ... |
| ; Entity Y velocity low byte (15 slots, indexed by X). |
| ; Type 2 gravity: fractional vertical velocity. |
| ; Accelerated by +/- $0B per frame toward entity_y_limit. |
| $7177 | | entity_vel_y_lo.fill15, $00; x-ref: $730A, $7482, $7499, $749F, $74AB, ... |
| ; Entity Y velocity high byte (15 slots, indexed by X). |
| ; Type 2 gravity: pixel-level vertical velocity. |
| ; Carries from vel_y_lo during vertical acceleration. |
| $7186 | | entity_vel_y_hi.fill15, $00; x-ref: $7305, $748B, $74A2, $74A7, $74B4, ... |
| ; Entity movement phase index (15 slots, indexed by X). |
| ; Type 1: vertical oscillation offset (0-15, wraps). |
| ; Indexes into displacement table f_71E5 for Y offset. |
| $7195 | | entity_move_phase.fill15, $00; x-ref: $72BD, $73FE, $7401, $740A |
| ; Entity animation frame table index (15 slots, indexed by X). |
| ; Indexes into per-type frame lookup tables (a_71F5, etc.). |
| ; Wraps at type-specific limits (2, 4, or 8 frames). |
| $71A4 | | entity_anim_index.fill15, $00; x-ref: $7262, $754E, $7559, $7573, $757E, ... |
| ; Entity animation delay counter (15 slots, indexed by X). |
| ; Counts up each frame; when reaching the delay threshold |
| ; (a_71E2-a_71E4), advances entity_anim_index and resets to 0. |
| $71B3 | | entity_anim_counter.fill15, $00; x-ref: $7265, $753E, $7541, $754B, $7563, ... |
| ; Entity despawn/death timer (15 slots, indexed by X). |
| ; Type 1: sub-counter for movement (wraps at 4). |
| ; Dying entities ($75F5): set to $1E, counts down to 0 then status=2. |
| $71C2 | | entity_timer.fill15, $00; x-ref: $72C0, $73BB, $73EF, $73F2, $73FB, ... |
| ; Entity dynamite hit flag (15 slots, indexed by X). |
| ; Set to $FF by check_dynamite_vs_enemies when entity is |
| ; within blast radius. Death handler ($7758) sets status=2 |
| ; for flagged entities. |
| $71D1 | | entity_hit_flag.fill15, $00; x-ref: $2063, $7268, $775E |
| ; Number of active animated tiles. Used as loop bound for entity iteration. |
| $71E0 | | tile_count.byte$00; x-ref: $1F21, $1FC2, $200D, $720F, $7217, ... |
| ; Physics acceleration for type 2 tiles (gravity/spring). Difficulty-scaled: $11 (easy), $20 (mid), $80 (hard). |
| $71E1 | | tile_accel.byte$00; x-ref: $7326, $733A, $734A, $744B, $7468 |
| ; Animation frame delay for type 0 tiles. Default 10, halved on level >= 10. |
| $71E2 | | tile_delay_type0.byte$00; x-ref: $729C, $7544 |
| ; Animation frame delay for type 1 tiles. Default 10, halved on level >= 10. |
| $71E3 | | tile_delay_type1.byte$00; x-ref: $72D8, $7569 |
| ; Animation frame delay for type 3 tiles. Default 8, halved on level >= 10. |
| $71E4 | | tile_delay_type3.byte$00; x-ref: $737E, $75B2 |
| ; 16-byte signed Y-offset table for type 1 bounce animation: +1..+4..+1, 0, -1..-4..-1, 0. |
| $71E5 | | tile_bounce_offsets.byte$01, $02, $03, $04, $03, $02, $01, $00; x-ref: $7412 |
| $71ED | | .byte$ff, $fe, $fd, $fc, $fd, $fe, $ff, $00 |
| ; 2-frame animation sequence for type 0 tiles ($A7, $A8). |
| $71F5 | | tile_frames_type0.byte$a7, $a8; x-ref: $7287, $755C |
| ; 2-frame animation sequence for type 1 tiles ($A9, $AA). |
| $71F7 | | tile_frames_type1.byte$a9, $aa; x-ref: $72C3, $7581 |
| ; 4-frame animation sequence for type 2 tiles ($AB-$AE). |
| $71F9 | | tile_frames_type2.byte$ab, $ac, $ad, $ae; x-ref: $730D, $75A5 |
| ; 8-frame palindrome animation for type 3 tiles ($AF-$B3-$B0). |
| $71FD | | tile_frames_type3.byte$af, $b0, $b1, $b2, $b3, $b2, $b1, $b0; x-ref: $7369, $75CA |
| ; 8-frame palindrome animation for type 4 tiles ($B4-$B8-$B5). |
| $7205 | | tile_frames_type4.byte$b4, $b5, $b6, $b7, $b8, $b7, $b6, $b5; x-ref: $7399, $75EE |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| ; Resets the animated tile subsystem by clearing the tile count to zero. |
| ; Called during level initialization to prepare for new tile spawning. |
| ; |
| ; Inputs: None |
| ; Outputs: a_71E0 = 0 (animated tile count cleared) |
| ; Side Effects: None |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| $720D | a9 00 | reset_animated_tileslda#$00; A = 0 ; x-ref: $4B04 |
| $720F | 8d e0 71 | statile_count; clear animated tile count |
| $7212 | 60 | rts |
| $7213 | 86 1e | j_7213stxzp_temp_x; x-ref: $4FF4 |
| $7215 | 84 1f | styzp_temp_y |
| $7217 | ae e0 71 | ldxtile_count |
| $721A | 20 25 72 | jsrinit_animated_tile |
| $721D | ee e0 71 | inctile_count |
| $7220 | a6 1e | ldxzp_temp_x |
| $7222 | a4 1f | ldyzp_temp_y |
| $7224 | 60 | rts |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| ; Initializes an animated tile slot based on tile type. |
| ; Looks up the level map to check if the tile cell is occupied, then |
| ; configures position, animation frames, and speed based on the tile type |
| ; (0-4). Difficulty scaling halves animation delay on level >= 10. |
| ; |
| ; Inputs: A = tile type (0-4), X = tile slot index |
| ; Outputs: Tile slot arrays populated (position, frame, speed, status) |
| ; Side Effects: Writes to a_71E1-a_71E4 (global animation counters) |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| $7225 | 9d a5 70 | init_animated_tilestaentity_type,x; store tile type in slot ; x-ref: $721A |
| $7228 | ac 9e 3f | ldycurrent_room_index; Y = current level index |
| $722B | b9 09 49 | ldalevel_map_ptr_lo,y; Get map row base addr (lo) for current level |
| $722E | 85 1c | stazp_ptr_map_lo; zpa_1C = map pointer lo |
| $7230 | b9 69 49 | ldalevel_map_ptr_hi,y; Get map row base addr (hi) for current level |
| $7233 | 85 1d | stazp_ptr_map_hi; zpa_1D = map pointer hi |
| $7235 | 8a | txa; Y = tile slot index |
| $7236 | a8 | tay |
| $7237 | b1 1c | lda(zp_ptr_map_lo),y; read map cell for this tile |
| $7239 | d0 06 | bneb_7241; cell != 0? -> tile is active |
| $723B | a9 02 | lda#$02; cell is empty: mark tile inactive |
| $723D | 9d 96 70 | staentity_status,x; status = 2 (inactive) |
| $7240 | 60 | rts |
| $7241 | a9 00 | b_7241lda#$00; mark tile as active (status = 0) ; x-ref: $7239 |
| $7243 | 9d 96 70 | staentity_status,x |
| $7246 | a9 00 | lda#$00 |
| $7248 | 85 1d | stazp_ptr_map_hi |
| $724A | a5 1f | ldazp_temp_y; zpa_1F (col) * 8 = column pixel X |
| $724C | 0a | asla |
| $724D | 0a | asla |
| $724E | 0a | asla |
| $724F | 26 1d | rolzp_ptr_map_hi |
| $7251 | 85 1c | stazp_ptr_map_lo; zpa_1C/1D = column pixel pos (16-bit) |
| $7253 | a5 1e | ldazp_temp_x; zpa_1E (row) * 8 = row pixel Y |
| $7255 | 0a | asla |
| $7256 | 0a | asla |
| $7257 | 0a | asla |
| $7258 | 85 1b | stazp_temp_pixel_y; zpa_1B = row pixel pos |
| $725A | a9 00 | lda#$00; clear state fields for this slot |
| $725C | 9d b4 70 | staentity_x_frac,x |
| $725F | 9d e1 70 | staentity_y_frac,x |
| $7262 | 9d a4 71 | staentity_anim_index,x |
| $7265 | 9d b3 71 | staentity_anim_counter,x |
| $7268 | 9d d1 71 | staentity_hit_flag,x |
| $726B | bd a5 70 | ldaentity_type,x; check tile type |
| $726E | d0 30 | bneb_72A0; type != 0? check next |
| $7270 | a5 1c | ldazp_ptr_map_lo; --- Type 0 handler --- |
| $7272 | 18 | clc |
| $7273 | 69 09 | adc#$09 |
| $7275 | 9d c3 70 | staentity_x_lo,x; x_pos = col_px + 9 |
| $7278 | a5 1d | ldazp_ptr_map_hi |
| $727A | 69 00 | adc#$00 |
| $727C | 9d d2 70 | staentity_x_hi,x |
| $727F | a5 1b | ldazp_temp_pixel_y |
| $7281 | 18 | clc |
| $7282 | 69 0c | adc#$0c |
| $7284 | 9d f0 70 | staentity_y,x |
| $7287 | ad f5 71 | ldatile_frames_type0; frame base = a_71F5 (tile $A7-$A8) |
| $728A | 9d ff 70 | staentity_frame,x |
| $728D | a9 07 | lda#$07; speed = 7 |
| $728F | 9d 0e 71 | staentity_anim_speed,x |
| $7292 | a9 0a | lda#$0a; anim delay = 10 |
| $7294 | ac d9 60 | ldycurrent_level; level >= 10? |
| $7297 | c0 0a | cpy#$0a; no -> keep delay = 10 |
| $7299 | 90 01 | bccb_729C; yes -> delay /= 2 (faster on harder levels) |
| $729B | 4a | lsra |
| $729C | 8d e2 71 | b_729Cstatile_delay_type0; store type 0 anim delay ; x-ref: $7299 |
| $729F | 60 | rts |
| $72A0 | c9 01 | b_72A0cmp#$01; --- Type 1 handler --- ; x-ref: $726E |
| $72A2 | d0 38 | bneb_72DC |
| $72A4 | a5 1c | ldazp_ptr_map_lo; x_pos = col_px + 9 |
| $72A6 | 18 | clc |
| $72A7 | 69 09 | adc#$09 |
| $72A9 | 9d c3 70 | staentity_x_lo,x |
| $72AC | a5 1d | ldazp_ptr_map_hi |
| $72AE | 69 00 | adc#$00 |
| $72B0 | 9d d2 70 | staentity_x_hi,x |
| $72B3 | a5 1b | ldazp_temp_pixel_y |
| $72B5 | 9d f0 70 | staentity_y,x |
| $72B8 | 9d 3b 71 | staentity_y_limit,x |
| $72BB | a9 00 | lda#$00 |
| $72BD | 9d 95 71 | staentity_move_phase,x |
| $72C0 | 9d c2 71 | staentity_timer,x |
| $72C3 | ad f7 71 | ldatile_frames_type1; frame base = a_71F7 (tile $A9-$AA) |
| $72C6 | 9d ff 70 | staentity_frame,x |
| $72C9 | a9 08 | lda#$08; speed = 8 |
| $72CB | 9d 0e 71 | staentity_anim_speed,x |
| $72CE | a9 0a | lda#$0a; anim delay = 10 |
| $72D0 | ac d9 60 | ldycurrent_level |
| $72D3 | c0 0a | cpy#$0a; no -> keep delay = 10 |
| $72D5 | 90 01 | bccb_72D8; yes -> delay /= 2 |
| $72D7 | 4a | lsra |
| $72D8 | 8d e3 71 | b_72D8statile_delay_type1; store type 1 anim delay ; x-ref: $72D5 |
| $72DB | 60 | rts |
| $72DC | c9 02 | b_72DCcmp#$02; --- Type 2 handler --- ; x-ref: $72A2 |
| $72DE | d0 6e | bneb_734E |
| $72E0 | a5 1c | ldazp_ptr_map_lo; x_pos = col_px + 12 |
| $72E2 | 18 | clc |
| $72E3 | 69 0c | adc#$0c |
| $72E5 | 9d c3 70 | staentity_x_lo,x |
| $72E8 | 9d 1d 71 | staentity_x_limit_lo,x |
| $72EB | a5 1d | ldazp_ptr_map_hi |
| $72ED | 69 00 | adc#$00 |
| $72EF | 9d d2 70 | staentity_x_hi,x |
| $72F2 | 9d 2c 71 | staentity_x_limit_hi,x |
| $72F5 | a5 1b | ldazp_temp_pixel_y; y_pos = row_px + 8 |
| $72F7 | 18 | clc |
| $72F8 | 69 08 | adc#$08 |
| $72FA | 9d f0 70 | staentity_y,x |
| $72FD | 9d 3b 71 | staentity_y_limit,x |
| $7300 | a9 00 | lda#$00 |
| $7302 | 9d 68 71 | staentity_vel_x_hi,x |
| $7305 | 9d 86 71 | staentity_vel_y_hi,x |
| $7308 | a9 c6 | lda#$c6 |
| $730A | 9d 77 71 | staentity_vel_y_lo,x |
| $730D | ad f9 71 | ldatile_frames_type2; frame base = a_71F9 (tile $AB-$AE) |
| $7310 | 9d ff 70 | staentity_frame,x |
| $7313 | ad d9 60 | ldacurrent_level; check difficulty tier |
| $7316 | c9 0a | cmp#$0a; level < 10? -> easy tier |
| $7318 | b0 10 | bcsb_732A; level >= 10: check mid tier |
| $731A | a9 21 | lda#$21; easy: horiz speed = $21 |
| $731C | 9d 4a 71 | staentity_vel_x_lo,x |
| $731F | a9 01 | lda#$01; easy: vert speed = 1 |
| $7321 | 9d 59 71 | staentity_vel_x_mid,x |
| $7324 | a9 11 | lda#$11; easy: combined speed = $11 |
| $7326 | 8d e1 71 | statile_accel |
| $7329 | 60 | rts |
| $732A | c9 10 | b_732Acmp#$10; level >= 16? -> hard tier ; x-ref: $7318 |
| $732C | b0 10 | bcsb_733E |
| $732E | a9 00 | lda#$00; mid: horiz speed = 0 |
| $7330 | 9d 4a 71 | staentity_vel_x_lo,x |
| $7333 | a9 02 | lda#$02; mid: vert speed = 2 |
| $7335 | 9d 59 71 | staentity_vel_x_mid,x |
| $7338 | a9 20 | lda#$20; mid: combined speed = $20 |
| $733A | 8d e1 71 | statile_accel |
| $733D | 60 | rts |
| $733E | a9 00 | b_733Elda#$00; hard: horiz speed = 0 ; x-ref: $732C |
| $7340 | 9d 4a 71 | staentity_vel_x_lo,x |
| $7343 | a9 04 | lda#$04; hard: vert speed = 4 |
| $7345 | 9d 59 71 | staentity_vel_x_mid,x |
| $7348 | a9 80 | lda#$80; hard: combined speed = $80 |
| $734A | 8d e1 71 | statile_accel |
| $734D | 60 | rts |
| $734E | c9 03 | b_734Ecmp#$03; --- Type 3 handler --- ; x-ref: $72DE |
| $7350 | d0 30 | bneb_7382 |
| $7352 | a5 1c | ldazp_ptr_map_lo |
| $7354 | 18 | clc; x_pos = col_px + 6 |
| $7355 | 69 06 | adc#$06 |
| $7357 | 9d c3 70 | staentity_x_lo,x |
| $735A | a5 1d | ldazp_ptr_map_hi |
| $735C | 69 00 | adc#$00 |
| $735E | 9d d2 70 | staentity_x_hi,x |
| $7361 | a5 1b | ldazp_temp_pixel_y |
| $7363 | 18 | clc; y_pos = row_px + 6 |
| $7364 | 69 06 | adc#$06 |
| $7366 | 9d f0 70 | staentity_y,x |
| $7369 | ad fd 71 | ldatile_frames_type3; frame base = a_71FD (tile $AF-$B2 cycling) |
| $736C | 9d ff 70 | staentity_frame,x |
| $736F | a9 05 | lda#$05; speed = 5 |
| $7371 | 9d 0e 71 | staentity_anim_speed,x |
| $7374 | a9 08 | lda#$08; anim delay = 8 |
| $7376 | ac d9 60 | ldycurrent_level |
| $7379 | c0 0a | cpy#$0a; no -> keep delay = 8 |
| $737B | 90 01 | bccb_737E; yes -> delay /= 2 |
| $737D | 4a | lsra |
| $737E | 8d e4 71 | b_737Estatile_delay_type3; store type 3 anim delay ; x-ref: $737B |
| $7381 | 60 | rts |
| $7382 | a5 1c | b_7382ldazp_ptr_map_lo; --- Type 4+ (default) handler --- ; x-ref: $7350 |
| $7384 | 18 | clc; x_pos = col_px + 8 |
| $7385 | 69 08 | adc#$08 |
| $7387 | 9d c3 70 | staentity_x_lo,x |
| $738A | a5 1d | ldazp_ptr_map_hi |
| $738C | 69 00 | adc#$00 |
| $738E | 9d d2 70 | staentity_x_hi,x |
| $7391 | a5 1b | ldazp_temp_pixel_y |
| $7393 | 18 | clc; y_pos = row_px + 3 |
| $7394 | 69 03 | adc#$03 |
| $7396 | 9d f0 70 | staentity_y,x |
| $7399 | ad 05 72 | ldatile_frames_type4; frame base = a_7205 (tile $B4-$B8 cycling) |
| $739C | 9d ff 70 | staentity_frame,x |
| $739F | a9 0e | lda#$0e; speed = 14 |
| $73A1 | 9d 0e 71 | staentity_anim_speed,x |
| $73A4 | 60 | rts |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| ; Iterates over all tile entities (tile_count-1 down to 0) and updates each one. |
| ; For each tile, checks entity_status: if non-zero and not 2, decrements the timer |
| ; and marks the tile as dying (status=2) when the timer expires. Active tiles |
| ; (status=0) are dispatched by entity_type to the appropriate update handler: |
| ; Type 0 → j_753E, Type 1 → bounce animation (s_73EF) + j_7563, |
| ; Type 2 → gravity physics (update_tile_gravity) + j_7588, |
| ; Type 3 → j_75AC, Default → s_74BD + j_75D1. |
| ; |
| ; Inputs: tile_count (number of tile entities to process) |
| ; Outputs: None (updates entity arrays in-place) |
| ; Side Effects: Modifies entity_status, entity_timer, positions, and velocities |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| $73A5 | ae e0 71 | update_all_tilesldxtile_count; X = number of tile entities ; x-ref: $61E0, $6298 |
| $73A8 | f0 07 | beqr_73B1; no tiles? skip |
| $73AA | ca | dex; adjust to 0-based index |
| $73AB | 20 b2 73 | b_73ABjsrupdate_tile_entity; update tile X ; x-ref: $73AF |
| $73AE | ca | dex; next tile |
| $73AF | 10 fa | bplb_73AB; loop until all processed |
| $73B1 | 60 | r_73B1rts; x-ref: $73A8 |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| ; Updates a single tile entity: handles death timer countdown, dispatches |
| ; type-specific movement (bounce, gravity, follow hero), and advances animation. |
| ; |
| ; Inputs: X = entity index into entity arrays |
| ; Outputs: Updated entity_status, entity_timer, entity_frame, position arrays |
| ; Side Effects: Entity position, animation frame, and status modified in-place |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| $73B2 | bd 96 70 | update_tile_entityldaentity_status,x; status==0? tile is active ; x-ref: $73AB |
| $73B5 | f0 0f | beqb_73C6; status==2? already dying, skip |
| $73B7 | c9 02 | cmp#$02; status==2? → dead, skip |
| $73B9 | f0 0a | beqr_73C5 |
| $73BB | de c2 71 | decentity_timer,x; count down entity timer |
| $73BE | d0 05 | bner_73C5; timer not expired yet |
| $73C0 | a9 02 | lda#$02; mark as dying (status=2) |
| $73C2 | 9d 96 70 | staentity_status,x |
| $73C5 | 60 | r_73C5rts; x-ref: $73B9, $73BE |
| $73C6 | bd a5 70 | b_73C6ldaentity_type,x; get tile type for dispatch ; x-ref: $73B5 |
| $73C9 | d0 03 | bneb_73CE; type==0? |
| $73CB | 4c 3e 75 | jmpj_753E; type 0: simple 2-frame animation |
| $73CE | c9 01 | b_73CEcmp#$01; type==1? bounce animation ; x-ref: $73C9 |
| $73D0 | d0 06 | bneb_73D8 |
| $73D2 | 20 ef 73 | jsrupdate_tile_bounce; type 1: bounce movement + animate |
| $73D5 | 4c 63 75 | jmpj_7563 |
| $73D8 | c9 02 | b_73D8cmp#$02; type==2? gravity physics ; x-ref: $73D0 |
| $73DA | d0 06 | bneb_73E2 |
| $73DC | 20 19 74 | jsrupdate_tile_gravity; type 2: gravity physics + animate |
| $73DF | 4c 88 75 | jmpj_7588 |
| $73E2 | c9 03 | b_73E2cmp#$03; type==3? ; x-ref: $73DA |
| $73E4 | d0 03 | bneb_73E9 |
| $73E6 | 4c ac 75 | jmpj_75AC; type 3: 8-frame animation only |
| $73E9 | 20 bd 74 | b_73E9jsrchase_hero_horizontal; default: hero proximity + render ; x-ref: $73E4 |
| $73EC | 4c d1 75 | jmpj_75D1 |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| ; Animates a tile's vertical bounce by stepping through a 16-entry |
| ; offset table (tile_bounce_offsets). Every 4 frames, the move_phase |
| ; index advances. The phase wraps at 16, producing a smooth |
| ; oscillation: +1..+4..+1, 0, -1..-4..-1, 0 pixels relative to |
| ; entity_y_limit (the base Y position). Called as movement type 1 |
| ; in the entity movement dispatcher. |
| ; |
| ; Inputs: X = entity slot index |
| ; Outputs: entity_y[x] = entity_y_limit[x] + tile_bounce_offsets[phase] |
| ; Side Effects: entity_timer[x] and entity_move_phase[x] updated |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| $73EF | fe c2 71 | update_tile_bounceincentity_timer,x; tick frame delay counter ; x-ref: $73D2 |
| $73F2 | bd c2 71 | ldaentity_timer,x |
| $73F5 | c9 04 | cmp#$04; trigger every 4 frames |
| $73F7 | d0 1f | bner_7418; not yet → skip bounce update |
| $73F9 | a9 00 | lda#$00; reset timer to 0 |
| $73FB | 9d c2 71 | staentity_timer,x |
| $73FE | fe 95 71 | incentity_move_phase,x; advance to next phase in bounce table |
| $7401 | bd 95 71 | ldaentity_move_phase,x |
| $7404 | c9 10 | cmp#$10; 16 entries in table → wrap |
| $7406 | d0 05 | bneb_740D |
| $7408 | a9 00 | lda#$00; wrap phase back to 0 |
| $740A | 9d 95 71 | staentity_move_phase,x |
| $740D | a8 | b_740Dtay; Y = phase index ; x-ref: $7406 |
| $740E | bd 3b 71 | ldaentity_y_limit,x; base Y position |
| $7411 | 18 | clc |
| $7412 | 79 e5 71 | adctile_bounce_offsets,y; add signed bounce offset |
| $7415 | 9d f0 70 | staentity_y,x; store final Y position |
| $7418 | 60 | r_7418rts; x-ref: $73F7 |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| ; Updates an animated tile's position using gravity/acceleration physics. |
| ; Adds X velocity to X position, then adjusts velocity toward a target X limit. |
| ; Adds Y velocity to Y position, then adjusts velocity toward a target Y limit. |
| ; The tile accelerates toward its target position and decelerates past it, |
| ; producing a gravity/spring effect. Called during tile animation phase 2. |
| ; |
| ; Inputs: X = tile index into entity arrays |
| ; Outputs: Updated position (f_70B4/f_70C3/f_70D2,x) and Y pos (f_70E1/f_70F0,x) |
| ; Side Effects: Velocity arrays (f_714A/f_7159/f_7168,x and f_7177/f_7186,x) modified |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| $7419 | bd b4 70 | update_tile_gravityldaentity_x_frac,x; pos_x_lo += vel_x_lo ; x-ref: $73DC |
| $741C | 18 | clc; clear carry for 24-bit add |
| $741D | 7d 4a 71 | adcentity_vel_x_lo,x; pos_lo += vel_lo |
| $7420 | 9d b4 70 | staentity_x_frac,x |
| $7423 | bd c3 70 | ldaentity_x_lo,x; pos_x_mid += vel_x_mid + carry |
| $7426 | 7d 59 71 | adcentity_vel_x_mid,x |
| $7429 | 9d c3 70 | staentity_x_lo,x |
| $742C | bd d2 70 | ldaentity_x_hi,x; pos_x_hi += vel_x_hi + carry |
| $742F | 7d 68 71 | adcentity_vel_x_hi,x |
| $7432 | 9d d2 70 | staentity_x_hi,x |
| $7435 | bd d2 70 | ldaentity_x_hi,x; compare pos_x_hi vs limit_hi |
| $7438 | dd 2c 71 | cmpentity_x_limit_hi,x; compare pos_hi with limit_hi |
| $743B | 90 27 | bccb_7464; pos_x_hi > limit_hi: decelerate |
| $743D | d0 08 | bneb_7447; above limit -> decelerate (bounce) |
| $743F | bd c3 70 | ldaentity_x_lo,x; pos_x_hi == limit_hi: check mid byte |
| $7442 | dd 1d 71 | cmpentity_x_limit_lo,x; compare pos_x_mid vs limit_mid |
| $7445 | 90 1d | bccb_7464; pos < limit: accelerate |
| $7447 | bd 4a 71 | b_7447ldaentity_vel_x_lo,x; vel_x_lo -= accel (decelerate) ; x-ref: $743D |
| $744A | 38 | sec |
| $744B | ed e1 71 | sbctile_accel; vel_lo -= a_71E1 (bounce decel) |
| $744E | 9d 4a 71 | staentity_vel_x_lo,x |
| $7451 | bd 59 71 | ldaentity_vel_x_mid,x; vel_x_mid -= borrow |
| $7454 | e9 00 | sbc#$00 |
| $7456 | 9d 59 71 | staentity_vel_x_mid,x; vel_mid -= borrow |
| $7459 | bd 68 71 | ldaentity_vel_x_hi,x; vel_x_hi -= borrow |
| $745C | e9 00 | sbc#$00 |
| $745E | 9d 68 71 | staentity_vel_x_hi,x; vel_hi -= borrow |
| $7461 | 4c 7e 74 | jmpj_747E; skip acceleration branch |
| $7464 | bd 4a 71 | b_7464ldaentity_vel_x_lo,x; vel_x_lo += accel (accelerate) ; x-ref: $743B, $7445 |
| $7467 | 18 | clc |
| $7468 | 6d e1 71 | adctile_accel; vel_lo += a_71E1 (gravity accel) |
| $746B | 9d 4a 71 | staentity_vel_x_lo,x |
| $746E | bd 59 71 | ldaentity_vel_x_mid,x; vel_x_mid += carry |
| $7471 | 69 00 | adc#$00; vel_mid += carry |
| $7473 | 9d 59 71 | staentity_vel_x_mid,x |
| $7476 | bd 68 71 | ldaentity_vel_x_hi,x; vel_x_hi += carry |
| $7479 | 69 00 | adc#$00 |
| $747B | 9d 68 71 | staentity_vel_x_hi,x |
| $747E | bd e1 70 | j_747Eldaentity_y_frac,x; pos_y_lo += vel_y_lo ; x-ref: $7461 |
| $7481 | 18 | clc; h_pos_lo += h_vel_lo |
| $7482 | 7d 77 71 | adcentity_vel_y_lo,x |
| $7485 | 9d e1 70 | staentity_y_frac,x |
| $7488 | bd f0 70 | ldaentity_y,x; pos_y_hi += vel_y_hi + carry |
| $748B | 7d 86 71 | adcentity_vel_y_hi,x |
| $748E | 9d f0 70 | staentity_y,x |
| $7491 | bd f0 70 | ldaentity_y,x; compare pos_y_hi vs y_limit |
| $7494 | dd 3b 71 | cmpentity_y_limit,x |
| $7497 | 90 12 | bccb_74AB; below limit: increase vel_y |
| $7499 | bd 77 71 | ldaentity_vel_y_lo,x; vel_y_lo -= $0B (decelerate Y) |
| $749C | 38 | sec |
| $749D | e9 0b | sbc#$0b; h_vel_lo -= $0B |
| $749F | 9d 77 71 | staentity_vel_y_lo,x |
| $74A2 | bd 86 71 | ldaentity_vel_y_hi,x; vel_y_hi -= borrow |
| $74A5 | e9 00 | sbc#$00 |
| $74A7 | 9d 86 71 | staentity_vel_y_hi,x |
| $74AA | 60 | rts |
| $74AB | bd 77 71 | b_74ABldaentity_vel_y_lo,x; vel_y_lo += $0B (accelerate Y) ; x-ref: $7497 |
| $74AE | 18 | clc |
| $74AF | 69 0b | adc#$0b; h_vel_lo += $0B |
| $74B1 | 9d 77 71 | staentity_vel_y_lo,x |
| $74B4 | bd 86 71 | ldaentity_vel_y_hi,x; vel_y_hi += carry |
| $74B7 | 69 00 | adc#$00 |
| $74B9 | 9d 86 71 | staentity_vel_y_hi,x |
| $74BC | 60 | rts |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| ; Chases the hero horizontally. Compares the entity's X position (indexed by X |
| ; register) against the hero's X position, then moves the entity left or right |
| ; by a half-pixel ($80 fractional) per call. Before moving, it checks the |
| ; destination map tile — if the tile is >= $1A (solid/blocking), movement is |
| ; skipped, preventing the entity from walking through walls. |
| ; |
| ; Inputs: X = entity index |
| ; Outputs: entity_x_frac/lo/hi[X] updated |
| ; Side Effects: None |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| chase_hero_horizontal |
| $74BD | ad fa 7a | ldahero_state; Skip if hero is inactive/dead ; x-ref: $73E9 |
| $74C0 | f0 01 | beqb_74C3 |
| $74C2 | 60 | rts |
| $74C3 | ad fc 7a | b_74C3ldahero_x_hi; Compare hero X vs entity X (hi byte) ; x-ref: $74C0 |
| $74C6 | dd d2 70 | cmpentity_x_hi,x |
| $74C9 | 90 0d | bccb_74D8; Entity is to the right of hero -> move left |
| $74CB | d0 3e | bneb_750B; Entity is to the left of hero -> move right |
| $74CD | ad fb 7a | ldahero_x_lo; Hi bytes equal, compare lo bytes |
| $74D0 | dd c3 70 | cmpentity_x_lo,x |
| $74D3 | 90 03 | bccb_74D8 |
| $74D5 | d0 34 | bneb_750B |
| $74D7 | 60 | rts; Positions equal, nothing to do |
| $74D8 | bd c3 70 | b_74D8ldaentity_x_lo,x; --- Move entity LEFT toward hero --- ; x-ref: $74C9, $74D3 |
| $74DB | 38 | sec |
| $74DC | e9 09 | sbc#$09; Check tile 9 pixels to the left |
| $74DE | 85 fd | stazp_ptr_dst_lo |
| $74E0 | bd d2 70 | ldaentity_x_hi,x |
| $74E3 | e9 00 | sbc#$00 |
| $74E5 | 85 fe | stazp_ptr_dst_hi |
| $74E7 | bd f0 70 | ldaentity_y,x |
| $74EA | 20 ca 50 | jsrget_map_tile |
| $74ED | c9 1a | cmp#$1a; Tile >= $1A? Blocked, skip movement |
| $74EF | b0 19 | bcsr_750A |
| $74F1 | bd b4 70 | ldaentity_x_frac,x |
| $74F4 | 38 | sec |
| $74F5 | e9 80 | sbc#$80; Subtract half-pixel (fractional step left) |
| $74F7 | 9d b4 70 | staentity_x_frac,x |
| $74FA | bd c3 70 | ldaentity_x_lo,x |
| $74FD | e9 00 | sbc#$00; Propagate borrow to lo byte |
| $74FF | 9d c3 70 | staentity_x_lo,x |
| $7502 | bd d2 70 | ldaentity_x_hi,x |
| $7505 | e9 00 | sbc#$00; Propagate borrow to hi byte |
| $7507 | 9d d2 70 | staentity_x_hi,x |
| $750A | 60 | r_750Arts; x-ref: $74EF |
| $750B | bd c3 70 | b_750Bldaentity_x_lo,x; --- Move entity RIGHT toward hero --- ; x-ref: $74CB, $74D5 |
| $750E | 18 | clc |
| $750F | 69 06 | adc#$06; Check tile 6 pixels to the right |
| $7511 | 85 fd | stazp_ptr_dst_lo |
| $7513 | bd d2 70 | ldaentity_x_hi,x |
| $7516 | 69 00 | adc#$00 |
| $7518 | 85 fe | stazp_ptr_dst_hi |
| $751A | bd f0 70 | ldaentity_y,x |
| $751D | 20 ca 50 | jsrget_map_tile |
| $7520 | c9 1a | cmp#$1a; Tile >= $1A? Blocked, skip movement |
| $7522 | b0 19 | bcsr_753D |
| $7524 | bd b4 70 | ldaentity_x_frac,x |
| $7527 | 18 | clc |
| $7528 | 69 80 | adc#$80; Add half-pixel (fractional step right) |
| $752A | 9d b4 70 | staentity_x_frac,x |
| $752D | bd c3 70 | ldaentity_x_lo,x |
| $7530 | 69 00 | adc#$00; Propagate carry to lo byte |
| $7532 | 9d c3 70 | staentity_x_lo,x |
| $7535 | bd d2 70 | ldaentity_x_hi,x |
| $7538 | 69 00 | adc#$00; Propagate carry to hi byte |
| $753A | 9d d2 70 | staentity_x_hi,x |
| $753D | 60 | r_753Drts; x-ref: $7522 |
| $753E | fe b3 71 | j_753Eincentity_anim_counter,x; x-ref: $73CB |
| $7541 | bd b3 71 | ldaentity_anim_counter,x |
| $7544 | cd e2 71 | cmptile_delay_type0 |
| $7547 | d0 19 | bner_7562 |
| $7549 | a9 00 | lda#$00 |
| $754B | 9d b3 71 | staentity_anim_counter,x |
| $754E | bc a4 71 | ldyentity_anim_index,x |
| $7551 | c8 | iny |
| $7552 | c0 02 | cpy#$02 |
| $7554 | d0 02 | bneb_7558 |
| $7556 | a0 00 | ldy#$00 |
| $7558 | 98 | b_7558tya; x-ref: $7554 |
| $7559 | 9d a4 71 | staentity_anim_index,x |
| $755C | b9 f5 71 | ldatile_frames_type0,y |
| $755F | 9d ff 70 | staentity_frame,x |
| $7562 | 60 | r_7562rts; x-ref: $7547 |
| $7563 | fe b3 71 | j_7563incentity_anim_counter,x; x-ref: $73D5 |
| $7566 | bd b3 71 | ldaentity_anim_counter,x |
| $7569 | cd e3 71 | cmptile_delay_type1 |
| $756C | d0 19 | bner_7587 |
| $756E | a9 00 | lda#$00 |
| $7570 | 9d b3 71 | staentity_anim_counter,x |
| $7573 | bc a4 71 | ldyentity_anim_index,x |
| $7576 | c8 | iny |
| $7577 | c0 02 | cpy#$02 |
| $7579 | d0 02 | bneb_757D |
| $757B | a0 00 | ldy#$00 |
| $757D | 98 | b_757Dtya; x-ref: $7579 |
| $757E | 9d a4 71 | staentity_anim_index,x |
| $7581 | b9 f7 71 | ldatile_frames_type1,y |
| $7584 | 9d ff 70 | staentity_frame,x |
| $7587 | 60 | r_7587rts; x-ref: $756C |
| $7588 | fe b3 71 | j_7588incentity_anim_counter,x; x-ref: $73DF |
| $758B | bd b3 71 | ldaentity_anim_counter,x |
| $758E | c9 04 | cmp#$04 |
| $7590 | d0 19 | bner_75AB |
| $7592 | a9 00 | lda#$00 |
| $7594 | 9d b3 71 | staentity_anim_counter,x |
| $7597 | bc a4 71 | ldyentity_anim_index,x |
| $759A | c8 | iny |
| $759B | c0 04 | cpy#$04 |
| $759D | d0 02 | bneb_75A1 |
| $759F | a0 00 | ldy#$00 |
| $75A1 | 98 | b_75A1tya; x-ref: $759D |
| $75A2 | 9d a4 71 | staentity_anim_index,x |
| $75A5 | b9 f9 71 | ldatile_frames_type2,y |
| $75A8 | 9d ff 70 | staentity_frame,x |
| $75AB | 60 | r_75ABrts; x-ref: $7590 |
| $75AC | fe b3 71 | j_75ACincentity_anim_counter,x; x-ref: $73E6 |
| $75AF | bd b3 71 | ldaentity_anim_counter,x |
| $75B2 | cd e4 71 | cmptile_delay_type3 |
| $75B5 | d0 19 | bner_75D0 |
| $75B7 | a9 00 | lda#$00 |
| $75B9 | 9d b3 71 | staentity_anim_counter,x |
| $75BC | bc a4 71 | ldyentity_anim_index,x |
| $75BF | c8 | iny |
| $75C0 | c0 08 | cpy#$08 |
| $75C2 | d0 02 | bneb_75C6 |
| $75C4 | a0 00 | ldy#$00 |
| $75C6 | 98 | b_75C6tya; x-ref: $75C2 |
| $75C7 | 9d a4 71 | staentity_anim_index,x |
| $75CA | b9 fd 71 | ldatile_frames_type3,y |
| $75CD | 9d ff 70 | staentity_frame,x |
| $75D0 | 60 | r_75D0rts; x-ref: $75B5 |
| $75D1 | fe b3 71 | j_75D1incentity_anim_counter,x; x-ref: $73EC |
| $75D4 | bd b3 71 | ldaentity_anim_counter,x |
| $75D7 | c9 10 | cmp#$10 |
| $75D9 | d0 19 | bner_75F4 |
| $75DB | a9 00 | lda#$00 |
| $75DD | 9d b3 71 | staentity_anim_counter,x |
| $75E0 | bc a4 71 | ldyentity_anim_index,x |
| $75E3 | c8 | iny |
| $75E4 | c0 08 | cpy#$08 |
| $75E6 | d0 02 | bneb_75EA |
| $75E8 | a0 00 | ldy#$00 |
| $75EA | 98 | b_75EAtya; x-ref: $75E6 |
| $75EB | 9d a4 71 | staentity_anim_index,x |
| $75EE | b9 05 72 | ldatile_frames_type4,y |
| $75F1 | 9d ff 70 | staentity_frame,x |
| $75F4 | 60 | r_75F4rts; x-ref: $75D9 |
| $75F5 | a9 01 | j_75F5lda#$01; x-ref: $1FFB, $2006 |
| $75F7 | 9d 96 70 | staentity_status,x |
| $75FA | a9 b9 | lda#$b9 |
| $75FC | 9d ff 70 | staentity_frame,x |
| $75FF | a9 01 | lda#$01 |
| $7601 | 9d 0e 71 | staentity_anim_speed,x |
| $7604 | a9 1e | lda#$1e |
| $7606 | 9d c2 71 | staentity_timer,x |
| $7609 | 20 6f 77 | jsrclear_map_tile |
| $760C | a9 50 | lda#$50 |
| $760E | 85 fb | stazp_ptr_src_lo |
| $7610 | a9 00 | lda#$00 |
| $7612 | 85 fc | stazp_ptr_src_hi |
| $7614 | a9 00 | lda#$00 |
| $7616 | 85 fd | stazp_ptr_dst_lo |
| $7618 | 4c d8 51 | jmpj_51D8 |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| ; Looks up the enemy type from f_70A5[X] and sets the collision hitbox |
| ; bounding-box parameters in zpa_02..zpa_05. |
| ; zpa_02 = Y upper bound (positive threshold) |
| ; zpa_03 = Y lower bound (negative threshold, signed) |
| ; zpa_04 = X upper bound (positive threshold) |
| ; zpa_05 = X lower bound (negative threshold, signed) |
| ; The enemy type selects a preset hitbox size; for types 2–4 the |
| ; sub-type in f_70FF[X] further refines the horizontal bounds. |
| ; |
| ; Inputs: X = enemy slot index, f_70A5[X] = enemy type, |
| ; f_70FF[X] = enemy sub-type (used by types 2–4) |
| ; Outputs: zpa_02..zpa_05 = hitbox bounding-box thresholds |
| ; Side Effects: None |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| $761B | bd a5 70 | get_enemy_hitboxldaentity_type,x; A = enemy type ; x-ref: $1F2D |
| $761E | d0 11 | bneb_7631; type != 0? check next |
| $7620 | a9 0c | lda#$0c; --- Type 0: standard hitbox --- |
| $7622 | 85 02 | stazp_work0; Y upper = $0C |
| $7624 | a9 f4 | lda#$f4; Y lower = $F4 (-12 signed) |
| $7626 | 85 03 | stazp_work1 |
| $7628 | a9 0b | lda#$0b; X upper = $0B |
| $762A | 85 04 | stazp_work2 |
| $762C | a9 f4 | lda#$f4; X lower = $F4 (-12 signed) |
| $762E | 85 05 | stazp_work3 |
| $7630 | 60 | rts |
| $7631 | c9 01 | b_7631cmp#$01; type == 1? ; x-ref: $761E |
| $7633 | d0 11 | bneb_7646; no? check next type |
| $7635 | a9 0e | lda#$0e; --- Type 1: slightly wider Y --- |
| $7637 | 85 02 | stazp_work0; Y upper = $0E |
| $7639 | a9 f4 | lda#$f4 |
| $763B | 85 03 | stazp_work1; X upper = $0B (same as type 0) |
| $763D | a9 0b | lda#$0b |
| $763F | 85 04 | stazp_work2 |
| $7641 | a9 f4 | lda#$f4 |
| $7643 | 85 05 | stazp_work3 |
| $7645 | 60 | rts |
| $7646 | c9 02 | b_7646cmp#$02; type == 2? ; x-ref: $7633 |
| $7648 | d0 2e | bneb_7678; no? check type 3 |
| $764A | a9 0f | lda#$0f; --- Type 2: Y=$0F/$F2, X varies by sub-type --- |
| $764C | 85 02 | stazp_work0; Y upper = $0F |
| $764E | a9 f2 | lda#$f2 |
| $7650 | 85 03 | stazp_work1; Y lower = $F2 (-14 signed) |
| $7652 | bd ff 70 | ldaentity_frame,x; A = sub-type from f_70FF[X] |
| $7655 | c9 ad | cmp#$ad; sub-type == $AD? |
| $7657 | d0 09 | bneb_7662; no? check $AE |
| $7659 | a9 0b | lda#$0b; sub-type $AD: X = ($0B, $F4) |
| $765B | 85 04 | stazp_work2 |
| $765D | a9 f4 | lda#$f4 |
| $765F | 85 05 | stazp_work3 |
| $7661 | 60 | rts |
| $7662 | c9 ae | b_7662cmp#$ae; sub-type == $AE? ; x-ref: $7657 |
| $7664 | d0 09 | bneb_766F; no? use default X bounds |
| $7666 | a9 09 | lda#$09; sub-type $AE: X = ($09, $F6) |
| $7668 | 85 04 | stazp_work2 |
| $766A | a9 f6 | lda#$f6 |
| $766C | 85 05 | stazp_work3 |
| $766E | 60 | rts |
| $766F | a9 07 | b_766Flda#$07; default sub-type: X = ($07, $F8) ; x-ref: $7664 |
| $7671 | 85 04 | stazp_work2 |
| $7673 | a9 f8 | lda#$f8 |
| $7675 | 85 05 | stazp_work3 |
| $7677 | 60 | rts |
| $7678 | c9 03 | b_7678cmp#$03; type == 3? ; x-ref: $7648 |
| $767A | d0 19 | bneb_7695; no? must be type >= 4 |
| $767C | a9 0c | lda#$0c; --- Type 3: Y=($0C,$F4), computed X --- |
| $767E | 85 02 | stazp_work0; Y upper = $0C |
| $7680 | a9 f4 | lda#$f4 |
| $7682 | 85 03 | stazp_work1 |
| $7684 | bd ff 70 | ldaentity_frame,x; A = sub-type from f_70FF[X] |
| $7687 | 38 | sec; A = sub-type - $AF |
| $7688 | e9 af | sbc#$af |
| $768A | 0a | asla; A = (sub-type - $AF) * 4 |
| $768B | 0a | asla |
| $768C | 69 01 | adc#$01; X upper = (sub-type - $AF) * 4 + 1 |
| $768E | 85 04 | stazp_work2 |
| $7690 | a9 ff | lda#$ff; X lower = $FF (-1: very wide) |
| $7692 | 85 05 | stazp_work3 |
| $7694 | 60 | rts |
| $7695 | a9 00 | b_7695lda#$00; --- Type >= 4: computed Y, fixed X --- ; x-ref: $767A |
| $7697 | 85 02 | stazp_work0; Y upper = $00 (disabled) |
| $7699 | bd ff 70 | ldaentity_frame,x; A = sub-type from f_70FF[X] |
| $769C | 38 | sec; A = sub-type - $B4 |
| $769D | e9 b4 | sbc#$b4 |
| $769F | 0a | asla; temp = (sub-type - $B4) * 2 |
| $76A0 | 85 ff | stazp_temp |
| $76A2 | a9 f8 | lda#$f8; Y lower = $F8 - temp |
| $76A4 | 38 | sec |
| $76A5 | e5 ff | sbczp_temp |
| $76A7 | 85 03 | stazp_work1 |
| $76A9 | bd ff 70 | ldaentity_frame,x; re-read sub-type for special case |
| $76AC | c9 b6 | cmp#$b6; sub-type == $B6? |
| $76AE | d0 04 | bneb_76B4; no? skip adjustment |
| $76B0 | c6 03 | deczp_work1; sub-type $B6: Y lower -= 2 (extra tall) |
| $76B2 | c6 03 | deczp_work1 |
| $76B4 | a9 09 | b_76B4lda#$09; X upper = $09 ; x-ref: $76AE |
| $76B6 | 85 04 | stazp_work2 |
| $76B8 | a9 f6 | lda#$f6; X lower = $F6 (-10 signed) |
| $76BA | 85 05 | stazp_work3 |
| $76BC | 60 | rts |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| ; Returns the laser collision hitbox parameters for the current enemy. |
| ; Branches on the enemy state (f_70A5,x) and sub-type (f_70FF,x) to select |
| ; Y-range bounds (zpa_02/zpa_03) and X-range bounds (zpa_04/zpa_05). |
| ; The direction flag a_7B01 and a_7828 adjust X bounds for facing. |
| ; |
| ; Inputs: X = enemy slot index |
| ; Outputs: zpa_02 = Y upper bound, zpa_03 = Y lower bound, |
| ; zpa_04 = X right bound, zpa_05 = X left bound |
| ; Side Effects: None |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| get_laser_hitbox_params |
| $76BD | bd a5 70 | ldaentity_type,x; branch on enemy state ; x-ref: $1FD5 |
| $76C0 | d0 3d | bneb_76FF; state != 0 → check further |
| $76C2 | bd ff 70 | ldaentity_frame,x; load enemy sub-type |
| $76C5 | c9 a7 | cmp#$a7; sub-type == $A7? |
| $76C7 | d0 07 | bneb_76D0 |
| $76C9 | a9 0b | lda#$0b; Y upper = 11 (tall hitbox) |
| $76CB | 85 02 | stazp_work0 |
| $76CD | 4c d4 76 | jmpj_76D4 |
| $76D0 | a9 0a | b_76D0lda#$0a; Y upper = 10 (default for state 0) ; x-ref: $76C7 |
| $76D2 | 85 02 | stazp_work0 |
| $76D4 | a9 05 | j_76D4lda#$05; Y lower = 5 ; x-ref: $76CD |
| $76D6 | 85 03 | stazp_work1 |
| $76D8 | ad 01 7b | j_76D8ldahero_scroll_dir; check direction flag ; x-ref: $7712, $771D, $772C |
| $76DB | c9 01 | cmp#$01; facing right? |
| $76DD | d0 10 | bneb_76EF |
| $76DF | a9 34 | lda#$34; X right = $34 (facing right) |
| $76E1 | ac 28 78 | ldyhit_strength; check secondary flag |
| $76E4 | f0 02 | beqb_76E8 |
| $76E6 | a9 19 | lda#$19; X right = $19 (alt facing) |
| $76E8 | 85 04 | b_76E8stazp_work2; store X right bound ; x-ref: $76E4 |
| $76EA | a9 ff | lda#$ff; X left = $FF (no left bound) |
| $76EC | 85 05 | stazp_work3 |
| $76EE | 60 | rts |
| $76EF | a9 00 | b_76EFlda#$00; facing left path ; x-ref: $76DD |
| $76F1 | 85 04 | stazp_work2; X right = $00 (no right bound) |
| $76F3 | a9 cb | lda#$cb; X left = $CB (facing left) |
| $76F5 | ac 28 78 | ldyhit_strength; check secondary flag |
| $76F8 | f0 02 | beqb_76FC |
| $76FA | a9 e6 | lda#$e6; X left = $E6 (alt facing) |
| $76FC | 85 05 | b_76FCstazp_work3; store X left bound ; x-ref: $76F8 |
| $76FE | 60 | rts |
| $76FF | c9 01 | b_76FFcmp#$01; --- State 1 --- ; x-ref: $76C0 |
| $7701 | d0 1d | bneb_7720 |
| $7703 | bd ff 70 | ldaentity_frame,x; load enemy sub-type |
| $7706 | c9 a9 | cmp#$a9; sub-type == $A9? |
| $7708 | d0 0b | bneb_7715 |
| $770A | a9 0b | lda#$0b; Y upper = 11 |
| $770C | 85 02 | stazp_work0 |
| $770E | a9 04 | lda#$04; Y lower = 4 |
| $7710 | 85 03 | stazp_work1 |
| $7712 | 4c d8 76 | jmpj_76D8; → compute X bounds |
| $7715 | a9 0d | b_7715lda#$0d; Y upper = 13 (default for state 1) ; x-ref: $7708 |
| $7717 | 85 02 | stazp_work0 |
| $7719 | a9 05 | lda#$05; Y lower = 5 |
| $771B | 85 03 | stazp_work1 |
| $771D | 4c d8 76 | jmpj_76D8; → compute X bounds |
| $7720 | c9 02 | b_7720cmp#$02; --- State 2 --- ; x-ref: $7701 |
| $7722 | d0 0b | bneb_772F |
| $7724 | a9 0e | lda#$0e; Y upper = 14 |
| $7726 | 85 02 | stazp_work0 |
| $7728 | a9 03 | lda#$03; Y lower = 3 |
| $772A | 85 03 | stazp_work1 |
| $772C | 4c d8 76 | jmpj_76D8; → compute X bounds |
| $772F | a9 0b | b_772Flda#$0b; --- Default state (>=3) --- ; x-ref: $7722 |
| $7731 | 85 02 | stazp_work0; Y upper = 11 |
| $7733 | a9 05 | lda#$05 |
| $7735 | 85 03 | stazp_work1; Y lower = 5 |
| $7737 | ad 01 7b | ldahero_scroll_dir; check direction flag |
| $773A | c9 01 | cmp#$01 |
| $773C | d0 11 | bneb_774F; facing left? → fixed X bounds |
| $773E | bd ff 70 | ldaentity_frame,x; load sub-type |
| $7741 | 38 | sec; sub-type -= $AF |
| $7742 | e9 af | sbc#$af |
| $7744 | 0a | asla; (sub-type - $AF) * 4 |
| $7745 | 0a | asla |
| $7746 | 69 2a | adc#$2a; X right = (sub-type-$AF)*4 + $2A |
| $7748 | 85 04 | stazp_work2; store X right bound |
| $774A | a9 ff | lda#$ff; X left = $FF |
| $774C | 85 05 | stazp_work3 |
| $774E | 60 | rts |
| $774F | a9 00 | b_774Flda#$00; facing left: X right = $00, X left = $C7 ; x-ref: $773C |
| $7751 | 85 04 | stazp_work2 |
| $7753 | a9 c7 | lda#$c7 |
| $7755 | 85 05 | stazp_work3 |
| $7757 | 60 | rts |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| ; Marks all hit entities as destroyed and clears them from the level map. |
| ; Loops through entities 0..tile_count-1, checks entity_hit_flag for each. |
| ; If hit, sets entity_status to $02 (destroyed) and zeroes the entity's |
| ; slot in the current room's level map via clear_entity_from_map. |
| ; |
| ; Inputs: None (reads tile_count, entity_hit_flag) |
| ; Outputs: None |
| ; Side Effects: Sets entity_status=$02 for hit entities, clears map slots |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| $7758 | ae e0 71 | process_hit_entitiesldxtile_count; count of active entities ; x-ref: $7B62 |
| $775B | f0 11 | beqr_776E; no entities? done |
| $775D | ca | dex; start from last entity |
| $775E | bd d1 71 | b_775Eldaentity_hit_flag,x; was this entity hit? ; x-ref: $776C |
| $7761 | f0 08 | beqb_776B; no → skip |
| $7763 | a9 02 | lda#$02; $02 = destroyed |
| $7765 | 9d 96 70 | staentity_status,x |
| $7768 | 20 6f 77 | jsrclear_map_tile; remove from level map |
| $776B | ca | b_776Bdex; next entity ; x-ref: $7761 |
| $776C | 10 f0 | bplb_775E; loop until all checked |
| $776E | 60 | r_776Erts; x-ref: $775B |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| ; Clears an entity's slot from the current room's level map. |
| ; Looks up the level map pointer for the current room, then writes $00 |
| ; at offset X (entity index) to remove the entity from the map. |
| ; |
| ; Inputs: X = entity index |
| ; Outputs: Y = entity index (copied from X) |
| ; Side Effects: Zeroes one byte in the level map |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| $776F | ac 9e 3f | clear_map_tileldycurrent_room_index; get current room ; x-ref: $7609, $7768 |
| $7772 | b9 09 49 | ldalevel_map_ptr_lo,y; lo byte of map pointer |
| $7775 | 85 1c | stazp_ptr_map_lo |
| $7777 | b9 69 49 | ldalevel_map_ptr_hi,y; hi byte of map pointer |
| $777A | 85 1d | stazp_ptr_map_hi |
| $777C | 8a | txa; copy entity index to Y |
| $777D | a8 | tay |
| $777E | a9 00 | lda#$00; clear entity from map |
| $7780 | 91 1c | sta(zp_ptr_map_lo),y; clear tile at map[entity_index] |
| $7782 | 60 | rts |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| ; Iterates through all active entities (enemies/creatures) and populates |
| ; the zero-page sprite arrays used by the sprite sort-and-render multiplexer. |
| ; For each entity: if status == 2 (dead), marks sprite Y as $FF (off-screen); |
| ; if rendering is locked, skips entirely; otherwise computes screen-space |
| ; coordinates from entity world position with fixed offsets (+12 X, +37 Y) |
| ; and copies the animation frame and speed into the sprite arrays. |
| ; |
| ; Inputs: tile_count (number of entities), entity tables (status, x, y, frame, anim_speed) |
| ; Outputs: zpf_37,x (Y pos), zpf_4A,x (X lo), zpf_5D,x (X hi), zpf_70,x (frame), zpf_83,x (anim speed) |
| ; Side Effects: None (only writes to zero-page sprite arrays) |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| $7783 | ae e0 71 | setup_entity_spritesldxtile_count; Load entity count as loop index ; x-ref: $647D |
| $7786 | d0 01 | bneb_7789; No entities? bail out |
| $7788 | 60 | rts |
| $7789 | ca | b_7789dex; Adjust to 0-based index (count-1..0) ; x-ref: $7786 |
| $778A | bd 96 70 | b_778Aldaentity_status,x; Check entity alive/dead status ; x-ref: $77BF |
| $778D | c9 02 | cmp#$02; Status == 2 means dead/inactive |
| $778F | d0 07 | bneb_7798 |
| $7791 | a9 ff | lda#$ff; $FF = off-screen Y (hide sprite) |
| $7793 | 95 37 | stazp_mux_y_entities,x; Mark sprite Y as off-screen |
| $7795 | 4c be 77 | jmpj_77BE |
| $7798 | ad a7 3f | b_7798ldarendering_in_progress; Skip sprite setup if render locked ; x-ref: $778F |
| $779B | d0 21 | bnej_77BE |
| $779D | bd c3 70 | ldaentity_x_lo,x; Get entity world X position (lo) |
| $77A0 | 18 | clc |
| $77A1 | 69 0c | adc#$0c; Add horizontal sprite offset (+12 px) |
| $77A3 | 95 4a | stazp_mux_x_lo_entities,x; Store screen X lo for multiplexer |
| $77A5 | bd d2 70 | ldaentity_x_hi,x; Get entity world X position (hi) |
| $77A8 | 69 00 | adc#$00; Propagate carry to hi byte |
| $77AA | 95 5d | stazp_mux_x_hi_entities,x; Store screen X hi for multiplexer |
| $77AC | bd f0 70 | ldaentity_y,x; Get entity world Y position |
| $77AF | 18 | clc |
| $77B0 | 69 25 | adc#$25; Add vertical sprite offset (+37 px) |
| $77B2 | 95 37 | stazp_mux_y_entities,x; Store screen Y for multiplexer |
| $77B4 | bd ff 70 | ldaentity_frame,x; Copy current animation frame |
| $77B7 | 95 70 | stazp_mux_frame_entities,x |
| $77B9 | bd 0e 71 | ldaentity_anim_speed,x; Copy animation speed/delay |
| $77BC | 95 83 | stazp_mux_color_entities,x |
| $77BE | ca | j_77BEdex; Next entity (count down) ; x-ref: $7795, $779B |
| $77BF | 10 c9 | bplb_778A; Loop until all entities processed |
| $77C1 | 60 | rts |
| ; Hazard active flag ($FF=active, $00=inactive). Set by setup_hazard_position, cleared by s_77C6. |
| $77C2 | | hazard_active.byte$00; x-ref: $1E9A, $1EDB, $4AF5, $77C8, $77D2, ... |
| ; Hazard pixel X position, low byte (column*8+4). |
| $77C3 | | hazard_x_lo.byte$00; x-ref: $1EB7, $1EF8, $77E3, $7807 |
| ; Hazard pixel X position, high byte. |
| $77C4 | | hazard_x_hi.byte$00; x-ref: $1EBE, $1EFF, $77EA, $780F |
| ; Hazard pixel Y position (row*8+7). |
| $77C5 | | hazard_y.byte$00; x-ref: $1EA8, $1EE9, $77F5, $7816 |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| ; Deactivates the hazard collision box by clearing the hazard_active flag. |
| ; Called during subsystem reset to ensure no stale hazard state persists |
| ; between screens or game states. |
| ; |
| ; Inputs: None |
| ; Outputs: None |
| ; Side Effects: Sets hazard_active ($77C2) to $00 |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| $77C6 | a9 00 | reset_hazardlda#$00; A = 0 (inactive) ; x-ref: $4B07 |
| $77C8 | 8d c2 77 | stahazard_active; clear hazard collision box |
| $77CB | 60 | rts |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| ; Converts tile-grid coordinates (X=row, Y=column) to pixel coordinates |
| ; and activates the hazard collision box at that position. |
| ; Pixel X (16-bit) = column * 8 + 4 → stored in a_77C3/a_77C4 |
| ; Pixel Y = row * 8 + 7 → stored in a_77C5 |
| ; Sets a_77C2 = $FF to mark the hazard as active. |
| ; Called as tile 12 handler from dispatch_complex_tile. |
| ; |
| ; Inputs: X = tile row, Y = tile column |
| ; Outputs: X, Y preserved (restored before RTS) |
| ; Side Effects: Sets a_77C2 (active flag), a_77C3/C4 (pixel X), a_77C5 (pixel Y) |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| setup_hazard_position |
| $77CC | 86 1e | stxzp_temp_x; save tile row ; x-ref: $4FCC |
| $77CE | 84 1f | styzp_temp_y; save tile column |
| $77D0 | a9 ff | lda#$ff; mark hazard as active |
| $77D2 | 8d c2 77 | stahazard_active |
| $77D5 | a9 00 | lda#$00 |
| $77D7 | 85 1d | stazp_ptr_map_hi; clear hi byte for 16-bit result |
| $77D9 | a5 1f | ldazp_temp_y; column * 8 (shift left 3) |
| $77DB | 0a | asla |
| $77DC | 0a | asla |
| $77DD | 0a | asla |
| $77DE | 26 1d | rolzp_ptr_map_hi; rotate carry into hi byte |
| $77E0 | 18 | clc |
| $77E1 | 69 04 | adc#$04; pixel_x_lo = column * 8 + 4 |
| $77E3 | 8d c3 77 | stahazard_x_lo; store pixel X lo byte |
| $77E6 | a5 1d | ldazp_ptr_map_hi; add carry to hi byte |
| $77E8 | 69 00 | adc#$00 |
| $77EA | 8d c4 77 | stahazard_x_hi; store pixel X hi byte |
| $77ED | a5 1e | ldazp_temp_x; row * 8 (shift left 3) |
| $77EF | 0a | asla |
| $77F0 | 0a | asla |
| $77F1 | 0a | asla |
| $77F2 | 18 | clc |
| $77F3 | 69 07 | adc#$07; pixel_y = row * 8 + 7 |
| $77F5 | 8d c5 77 | stahazard_y; store pixel Y |
| $77F8 | a6 1e | ldxzp_temp_x; restore tile row in X |
| $77FA | a4 1f | ldyzp_temp_y; restore tile column in Y |
| $77FC | 60 | rts |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| ; Sets up the hazard sprite for the multiplexer. Reads the hazard object's |
| ; position (hazard_x_lo/hi, hazard_y) and writes adjusted screen coordinates, |
| ; sprite frame ($BA), and color (dark grey/$0B) into the zero-page sprite |
| ; arrays. Skipped if hazard is inactive or rendering is in progress. |
| ; |
| ; Inputs: hazard_active, hazard_x_lo, hazard_x_hi, hazard_y |
| ; Outputs: zpa_58 (X lo), zpa_6B (X hi), zp_screen_dirty (Y), zpa_7E (frame), |
| ; zp_spr_color_extra (color) |
| ; Side Effects: None |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| $77FD | ad c2 77 | setup_hazard_spriteldahazard_active; Hazard active? ; x-ref: $6480 |
| $7800 | f0 24 | beqr_7826; No → skip |
| $7802 | ad a7 3f | ldarendering_in_progress; Renderer busy? |
| $7805 | d0 1f | bner_7826; Yes → skip to avoid conflict |
| $7807 | ad c3 77 | ldahazard_x_lo; Hazard X lo |
| $780A | 18 | clc |
| $780B | 69 0c | adc#$0c; Add X offset (+12 pixels) |
| $780D | 85 58 | stazp_mux_x_lo_hazard; → sprite X lo |
| $780F | ad c4 77 | ldahazard_x_hi; Hazard X hi |
| $7812 | 69 00 | adc#$00; Propagate carry |
| $7814 | 85 6b | stazp_mux_x_hi_hazard; → sprite X hi |
| $7816 | ad c5 77 | ldahazard_y; Hazard Y |
| $7819 | 18 | clc |
| $781A | 69 25 | adc#$25; Add Y offset (+37 pixels) |
| $781C | 85 45 | stazp_screen_dirty; → sprite Y position |
| $781E | a9 ba | lda#$ba; Sprite frame $BA = hazard shape |
| $7820 | 85 7e | stazp_mux_frame_hazard; → sprite frame |
| $7822 | a9 0b | lda#VicIIColors.DARK_GREY; $0B = dark grey |
| $7824 | 85 91 | stazp_spr_color_extra; → sprite color |
| $7826 | 60 | r_7826rts; x-ref: $7800, $7805 |
| ; Fire/dynamite active flag ($FF=active, $00=inactive). Set by handle_fire_pressed, cleared by s_783D/s_7912. |
| $7827 | | fire_active.byte$00; x-ref: $1ED6, $1FBD, $783F, $784B, $78FA, ... |
| ; Hit strength result: 0=miss, 1=partial/ceiling, 2=direct hit. Written by check_dynamite_enemy_collision. |
| $7828 | | hit_strength.byte$00; x-ref: $76E1, $76F5, $7859, $7871, $78D1, ... |
| ; Fire animation frame counter (0-2). Advances every 2 sub-frames, wraps at 3. |
| $7829 | | fire_anim_frame.byte$00; x-ref: $78EA, $78ED, $78F6, $7906, $7956 |
| ; Fire animation sub-frame counter (0-1). Increments each update, resets at 2 to advance fire_anim_frame. |
| $782A | | fire_anim_tick.byte$00; x-ref: $78DB, $78DE, $78E7, $7909 |
| ; Fire/dynamite sprite X offset table (low bytes), indexed by direction*2 |
| $782B | | fire_offset_x_lo.byte$da; x-ref: $7943 |
| ; Fire/dynamite sprite X offset table (high bytes), indexed by direction*2 |
| $782C | | fire_offset_x_hi.byte$ff, $f0, $ff, $f4, $ff, $0e, $00, $10; x-ref: $794A |
| $7834 | | .byte$00, $0c, $00 |
| ; Sprite pointer table for fire/dynamite animation (6 frames: 3 normal + 3 direct-hit) |
| $7837 | | fire_sprite_frames.byte$9d, $9e, $9f, $a0, $a0, $89; x-ref: $7964 |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| ; Initializes the dynamite/projectile system for a new level. Clears any |
| ; in-flight projectile, resets the countdown timer, and arms the dynamite |
| ; so the player can throw it. |
| ; |
| ; Inputs: None |
| ; Outputs: fire_active = 0, zp_dynamite_timer = 10, zp_dynamite_active = $FF |
| ; Side Effects: None |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| $783D | a9 00 | init_dynamite_statelda#$00; Deactivate any in-flight projectile ; x-ref: $6134 |
| $783F | 8d 27 78 | stafire_active |
| $7842 | a9 0a | lda#$0a; Timer = 10 frames before detonation |
| $7844 | 85 81 | stazp_dynamite_timer; init dynamite timer to 10 frames |
| $7846 | a9 ff | lda#$ff; $FF = dynamite armed and ready to throw |
| $7848 | 85 a7 | stazp_dynamite_active; arm dynamite ($FF = active) |
| $784A | 60 | rts |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| ; Checks if the active dynamite/projectile collides with any enemy or hits |
| ; the ceiling boundary. If a collision is found, sets the hit strength in |
| ; a_7828 (1=partial, 2=direct) and decrements the enemy's HP/timer. |
| ; Also advances the dynamite animation frame counter each call. |
| ; |
| ; Inputs: a_7827 = dynamite active flag (0 = inactive) |
| ; Outputs: a_7828 = collision result (0=miss, 1=partial, 2=direct hit) |
| ; Side Effects: Enemy HP decremented on hit via j_881E, animation frame |
| ; counters a_7829/a_782A advanced |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| update_dynamite_collision |
| $784B | ad 27 78 | ldafire_active; Dynamite active? ; x-ref: $61DA |
| $784E | d0 01 | bneb_7851; No → skip |
| $7850 | 60 | rts |
| $7851 | 20 57 78 | b_7851jsrcheck_dynamite_enemy_collision; Check collision with enemies ; x-ref: $784E |
| $7854 | 4c db 78 | jmpj_78DB; Advance animation frame |
| check_dynamite_enemy_collision |
| $7857 | a9 00 | lda#$00; Clear collision result ; x-ref: $7851 |
| $7859 | 8d 28 78 | stahit_strength; a_7828 = 0 (no hit) |
| $785C | ad 01 7b | ldahero_scroll_dir; Check projectile direction |
| $785F | c9 01 | cmp#$01; Direction == 1 (upward)? |
| $7861 | d0 12 | bneb_7875 |
| $7863 | ad fc 7a | ldahero_x_hi; Y-pos high byte |
| $7866 | d0 0d | bneb_7875; Not zero → skip ceiling check |
| $7868 | ad fb 7a | ldahero_x_lo; Y-pos low byte |
| $786B | c9 20 | cmp#$20; Y < $20 (near top)? |
| $786D | b0 06 | bcsb_7875 |
| $786F | a9 01 | lda#$01; Hit ceiling boundary |
| $7871 | 8d 28 78 | stahit_strength; collision_result = 1 |
| $7874 | 60 | rts |
| $7875 | ae e4 85 | b_7875ldxdynamic_tile_count; Enemy count ; x-ref: $7861, $7866, $786D |
| $7878 | d0 01 | bneb_787B; No enemies → return |
| $787A | 60 | rts |
| $787B | ca | b_787Bdex; Loop index (count-1 → 0) ; x-ref: $7878 |
| $787C | bd c9 85 | b_787Cldadtile_id,x; Enemy active? ; x-ref: $78D8 |
| $787F | f0 56 | beqb_78D7; Inactive → next enemy |
| $7881 | ad fd 7a | ldahero_y_pos; Projectile X-pos |
| $7884 | 38 | sec |
| $7885 | fd d5 85 | sbcdtile_x,x; Minus enemy X-pos |
| $7888 | c9 1c | cmp#$1c; X-distance >= 28? |
| $788A | 10 4b | bplb_78D7 |
| $788C | c9 f4 | cmp#$f4; X-distance <= -12? |
| $788E | 30 47 | bmib_78D7 |
| $7890 | ad 01 7b | ldahero_scroll_dir; Check direction again |
| $7893 | c9 01 | cmp#$01; Direction == 1? |
| $7895 | d0 17 | bneb_78AE |
| $7897 | ad fb 7a | ldahero_x_lo; Y-dist = projectile_Y - enemy_Y |
| $789A | 38 | sec |
| $789B | fd cf 85 | sbcdtile_y_lo,x; Low byte subtract |
| $789E | a8 | tay |
| $789F | ad fc 7a | ldahero_x_hi; High byte of Y-pos |
| $78A2 | fd d2 85 | sbcdtile_y_hi,x; High byte subtract |
| $78A5 | d0 30 | bneb_78D7; High byte != 0 → miss |
| $78A7 | c0 36 | cpy#$36; Y-distance >= $36? |
| $78A9 | b0 2c | bcsb_78D7; Too far → miss |
| $78AB | 4c c2 78 | jmpj_78C2; Within range → classify hit |
| $78AE | bd cf 85 | b_78AEldadtile_y_lo,x; Y-dist = enemy_Y - projectile_Y ; x-ref: $7895 |
| $78B1 | 38 | sec |
| $78B2 | ed fb 7a | sbchero_x_lo |
| $78B5 | a8 | tay |
| $78B6 | bd d2 85 | ldadtile_y_hi,x; High byte subtract |
| $78B9 | ed fc 7a | sbchero_x_hi |
| $78BC | d0 19 | bneb_78D7; High byte != 0 → miss |
| $78BE | c0 36 | cpy#$36; Y-distance >= $36? |
| $78C0 | b0 15 | bcsb_78D7; Too far → miss |
| $78C2 | c0 28 | j_78C2cpy#$28; Y-dist >= $28 (40)? ; x-ref: $78AB |
| $78C4 | b0 0e | bcsb_78D4; Far → no damage (graze) |
| $78C6 | c0 18 | cpy#$18; Y-dist >= $18 (24)? |
| $78C8 | b0 05 | bcsb_78CF; Partial hit → strength 1 |
| $78CA | a9 02 | lda#$02; Direct hit → strength 2 |
| $78CC | 4c d1 78 | jmpj_78D1 |
| $78CF | a9 01 | b_78CFlda#$01; x-ref: $78C8 |
| $78D1 | 8d 28 78 | j_78D1stahit_strength; Store hit strength ; x-ref: $78CC |
| $78D4 | 4c 1e 88 | b_78D4jmpj_881E; Decrement enemy HP/timer ; x-ref: $78C4 |
| $78D7 | ca | b_78D7dex; Next enemy ; x-ref: $787F, $788A, $788E, $78A5, $78A9, ... |
| $78D8 | 10 a2 | bplb_787C; Loop until all checked |
| $78DA | 60 | rts |
| $78DB | ee 2a 78 | j_78DBincfire_anim_tick; Advance sub-frame counter ; x-ref: $7854 |
| $78DE | ad 2a 78 | ldafire_anim_tick |
| $78E1 | c9 02 | cmp#$02; Every 2 sub-frames? |
| $78E3 | d0 14 | bner_78F9 |
| $78E5 | a9 00 | lda#$00; Reset sub-frame counter |
| $78E7 | 8d 2a 78 | stafire_anim_tick |
| $78EA | ee 29 78 | incfire_anim_frame; Advance animation frame |
| $78ED | ad 29 78 | ldafire_anim_frame |
| $78F0 | c9 03 | cmp#$03; Wrap at frame 3 |
| $78F2 | d0 05 | bner_78F9 |
| $78F4 | a9 00 | lda#$00; Reset frame to 0 |
| $78F6 | 8d 29 78 | stafire_anim_frame |
| $78F9 | 60 | r_78F9rts; x-ref: $78E3, $78F2 |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| ; Handles the fire button being pressed. If fire was already registered |
| ; (a_7827 != 0), exits immediately to avoid re-triggering. Otherwise, sets |
| ; the fire-active flag, resets the fire animation frame counters (a_7829 |
| ; and a_782A), and triggers the fire sound effect via a_8988. |
| ; |
| ; Inputs: a_7827 (fire-active flag) |
| ; Outputs: a_7827 = $FF, a_7829 = 0, a_782A = 0, a_8988 = 1 |
| ; Side Effects: Triggers fire sound effect (SID voice 2) |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| $78FA | ad 27 78 | handle_fire_pressedldafire_active; check if fire already active ; x-ref: $7C15 |
| $78FD | d0 12 | bner_7911; already active? skip |
| $78FF | a9 ff | lda#$ff; mark fire as active ($FF) |
| $7901 | 8d 27 78 | stafire_active |
| $7904 | a9 00 | lda#$00; reset animation frame counters |
| $7906 | 8d 29 78 | stafire_anim_frame |
| $7909 | 8d 2a 78 | stafire_anim_tick |
| $790C | a9 01 | lda#$01; trigger fire sound effect |
| $790E | 8d 88 89 | stasfx_fire_phase |
| $7911 | 60 | r_7911rts; x-ref: $78FD |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| ; Deactivates the fire weapon. If fire_active is set, clears it and |
| ; stops the fire sound effect by jumping to the SFX shutdown routine. |
| ; If fire is already inactive, returns immediately. |
| ; |
| ; Inputs: fire_active ($7827) |
| ; Outputs: fire_active cleared to 0 |
| ; Side Effects: Stops fire SFX on SID Voice 2 (via j_8A02) |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| $7912 | ad 27 78 | deactivate_fireldafire_active; Is fire currently active? ; x-ref: $7C1B, $800C, $819A |
| $7915 | f0 08 | beqr_791F; No -> nothing to deactivate |
| $7917 | a9 00 | lda#$00; Clear fire_active flag |
| $7919 | 8d 27 78 | stafire_active |
| $791C | 4c 02 8a | jmpj_8A02; Stop fire SFX (tail call) |
| $791F | 60 | r_791Frts; x-ref: $7915 |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| ; Sets up the dynamite/fire explosion sprite. Calculates the sprite's screen |
| ; position and animation frame based on the hero's position, facing direction, |
| ; and hit strength. Returns early (with $FF = no sprite) if fire is inactive |
| ; or the hero is below the ground boundary. |
| ; |
| ; Inputs: fire_active, hero_y_pos, hero_scroll_dir, hit_strength, |
| ; fire_anim_frame, zp_spr_x_lo/hi, zp_spr_y_pos |
| ; Outputs: zpa_48 = sprite X low, zpa_5B = sprite X high, zpa_35 = sprite Y, |
| ; zpa_6E = sprite frame pointer, zpa_94 = horizontal flip flag |
| ; Side Effects: None |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| $7920 | ad 27 78 | setup_fire_spriteldafire_active; Is fire/dynamite active? ; x-ref: $6489 |
| $7923 | f0 07 | beqb_792C; No → return $FF (no sprite) |
| $7925 | ad fd 7a | ldahero_y_pos; Get hero's Y screen position |
| $7928 | c9 87 | cmp#$87; Below ground boundary ($87)? |
| $792A | 90 05 | bccb_7931; No → calculate sprite position |
| $792C | a9 ff | b_792Clda#$ff; $FF = no sprite to display ; x-ref: $7923 |
| $792E | 85 35 | stazp_mux_y_fire |
| $7930 | 60 | rts |
| $7931 | ad 28 78 | b_7931ldahit_strength; Get hit type (0=punch, 1/2=dynamite) ; x-ref: $792A |
| $7934 | ae 01 7b | ldxhero_scroll_dir; Which direction is hero facing? |
| $7937 | e0 01 | cpx#$01; 1 = facing right, skip offset |
| $7939 | f0 03 | beqb_793E |
| $793B | 18 | clc |
| $793C | 69 03 | adc#$03; Add 3 for left-facing offset group |
| $793E | 0a | b_793Easla; ×2 for word-sized table entries ; x-ref: $7939 |
| $793F | aa | tax |
| $7940 | a5 46 | ldazp_spr_x_lo; Hero sprite X low byte |
| $7942 | 18 | clc |
| $7943 | 7d 2b 78 | adcfire_offset_x_lo,x; Add X offset from table |
| $7946 | 85 48 | stazp_mux_x_lo_fire; Store fire sprite X low |
| $7948 | a5 59 | ldazp_spr_x_hi; Hero sprite X high byte |
| $794A | 7d 2c 78 | adcfire_offset_x_hi,x; Add X offset high from table |
| $794D | 85 5b | stazp_mux_x_hi_fire; Store fire sprite X high |
| $794F | a5 33 | ldazp_spr_y_pos; Hero sprite Y position |
| $7951 | 38 | sec |
| $7952 | e9 08 | sbc#$08; Offset sprite 8px up from hero |
| $7954 | 85 35 | stazp_mux_y_fire; Store fire sprite Y position |
| $7956 | ad 29 78 | ldafire_anim_frame; Current animation frame index |
| $7959 | ae 28 78 | ldxhit_strength; Check hit strength |
| $795C | e0 02 | cpx#$02; 2 = direct hit → use alt frames |
| $795E | d0 03 | bneb_7963 |
| $7960 | 18 | clc; Add 3 for direct-hit frame set |
| $7961 | 69 03 | adc#$03 |
| $7963 | aa | b_7963tax; Use frame index into sprite table ; x-ref: $795E |
| $7964 | bd 37 78 | ldafire_sprite_frames,x; Look up sprite pointer from table |
| $7967 | 85 6e | stazp_mux_frame_fire; Store sprite frame pointer |
| $7969 | a9 ff | lda#$ff; $FF = default to flipped (punch) |
| $796B | ae 28 78 | ldxhit_strength; hit_strength != 0 → dynamite |
| $796E | f0 02 | beqb_7972; Dynamite: no flip needed |
| $7970 | a9 00 | lda#$00 |
| $7972 | 85 94 | b_7972stazp_mux_flip_fire; Store horizontal flip flag ; x-ref: $796E |
| $7974 | 60 | rts |
| ; Water animation frame index (0-7). Advances every 5 ticks, indexes into water_anim_patterns. |
| $7975 | | water_anim_frame.byte$00; x-ref: $7A19, $7A34, $7A37, $7A40 |
| ; Water animation tick divider (0-4). Increments each update, resets at 5 to advance water_anim_frame. |
| $7976 | | water_anim_tick.byte$00; x-ref: $7A1C, $7A25, $7A28, $7A31 |
| ; Water animation pattern table: 8 frames x 20 columns of tile indices ($B0-$B3). |
| $7977 | | water_anim_patterns.byte$b0, $b1, $b2, $b3, $b3, $b2, $b1, $b0; x-ref: $7A52, $7A66 |
| $797F | | .byte$b0, $b1, $b2, $b3, $b3, $b2, $b1, $b0 |
| $7987 | | .byte$b0, $b1, $b2, $b3, $b0, $b0, $b1, $b2 |
| $798F | | .byte$b2, $b1, $b0, $b0, $b1, $b2, $b3, $b3 |
| $7997 | | .byte$b3, $b3, $b2, $b1, $b0, $b0, $b1, $b2 |
| $799F | | .byte$b1, $b0, $b0, $b1, $b1, $b0, $b0, $b1 |
| $79A7 | | .byte$b2, $b3, $b3, $b2, $b2, $b3, $b3, $b2 |
| $79AF | | .byte$b1, $b0, $b0, $b1, $b2, $b1, $b0, $b0 |
| $79B7 | | .byte$b0, $b0, $b1, $b2, $b3, $b3, $b2, $b1 |
| $79BF | | .byte$b1, $b2, $b3, $b3, $b2, $b1, $b0, $b0 |
| $79C7 | | .byte$b3, $b2, $b1, $b0, $b0, $b1, $b2, $b3 |
| $79CF | | .byte$b3, $b2, $b1, $b0, $b0, $b1, $b2, $b3 |
| $79D7 | | .byte$b3, $b2, $b1, $b0, $b3, $b3, $b2, $b1 |
| $79DF | | .byte$b1, $b2, $b3, $b3, $b2, $b1, $b0, $b0 |
| $79E7 | | .byte$b0, $b0, $b1, $b2, $b3, $b3, $b2, $b1 |
| $79EF | | .byte$b2, $b3, $b3, $b2, $b2, $b3, $b3, $b2 |
| $79F7 | | .byte$b1, $b0, $b0, $b1, $b1, $b0, $b0, $b1 |
| $79FF | | .byte$b2, $b3, $b3, $b2, $b1, $b2, $b3, $b3 |
| $7A07 | | .byte$b3, $b3, $b2, $b1, $b0, $b0, $b1, $b2 |
| $7A0F | | .byte$b2, $b1, $b0, $b0, $b1, $b2, $b3, $b3 |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| ; Resets the water/wave animation subsystem. |
| ; Clears both the frame counter and the tick divider so the animation |
| ; restarts from frame 0 on the next screen update. |
| ; |
| ; Inputs: None |
| ; Outputs: None |
| ; Side Effects: a_7975 (frame index) and a_7976 (tick divider) set to 0 |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| reset_water_animation |
| $7A17 | a9 00 | lda#$00; A = 0 ; x-ref: $4B0A |
| $7A19 | 8d 75 79 | stawater_anim_frame; reset animation frame index (0-7) |
| $7A1C | 8d 76 79 | stawater_anim_tick; reset tick divider (0-4) |
| $7A1F | 60 | rts |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| ; Animates the water surface tiles on screen. Runs every 5 frames, cycling |
| ; through 8 animation frames. Each frame selects 20 tile patterns from |
| ; water_anim_patterns and writes them to scr_water_row. The first 20 tiles |
| ; are written left-to-right; the second 20 are written with a reversed |
| ; pattern index, creating a mirrored/reflected water effect. Cells marked |
| ; $80 are treated as transparent and skipped. |
| ; |
| ; Inputs: screen_changed_flag (must be non-zero to proceed) |
| ; Outputs: scr_water_row updated with current animation frame tiles |
| ; Side Effects: Modifies water_anim_tick, water_anim_frame |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| update_water_animation |
| $7A20 | ad a6 3f | ldascreen_changed_flag; skip if no screen update needed ; x-ref: $61D4, $6295 |
| $7A23 | f0 4d | beqr_7A72 |
| $7A25 | ee 76 79 | incwater_anim_tick; advance tick counter |
| $7A28 | ad 76 79 | ldawater_anim_tick |
| $7A2B | c9 05 | cmp#$05; only update every 5 frames |
| $7A2D | d0 43 | bner_7A72 |
| $7A2F | a9 00 | lda#$00; reset tick to 0 |
| $7A31 | 8d 76 79 | stawater_anim_tick |
| $7A34 | ee 75 79 | incwater_anim_frame; advance to next anim frame |
| $7A37 | ad 75 79 | ldawater_anim_frame |
| $7A3A | c9 08 | cmp#$08; wrap frame at 8 (0-7) |
| $7A3C | d0 05 | bneb_7A43 |
| $7A3E | a9 00 | lda#$00 |
| $7A40 | 8d 75 79 | stawater_anim_frame |
| $7A43 | 20 a5 21 | b_7A43jsrmultiply_by_5; frame * 5 * 4 = offset into patterns ; x-ref: $7A3C |
| $7A46 | 0a | asla |
| $7A47 | 0a | asla |
| $7A48 | aa | tax |
| $7A49 | a0 00 | ldy#$00; Y = tile index in water row |
| $7A4B | b9 80 06 | b_7A4BldaSCREEN_RAM_R16C0,y; x-ref: $7A5C |
| $7A4E | c9 80 | cmp#$80; $80 = masked/transparent tile, skip |
| $7A50 | f0 06 | beqb_7A58 |
| $7A52 | bd 77 79 | ldawater_anim_patterns,x; copy pattern to screen row |
| $7A55 | 99 80 06 | staSCREEN_RAM_R16C0,y |
| $7A58 | e8 | b_7A58inx; x-ref: $7A50 |
| $7A59 | c8 | iny |
| $7A5A | c0 14 | cpy#$14; 20 tiles per half-row (left-to-right) |
| $7A5C | d0 ed | bneb_7A4B |
| $7A5E | ca | dex; back up X by 1 for mirror effect |
| $7A5F | b9 80 06 | b_7A5FldaSCREEN_RAM_R16C0,y; x-ref: $7A70 |
| $7A62 | c9 80 | cmp#$80; $80 = masked/transparent, skip |
| $7A64 | f0 06 | beqb_7A6C |
| $7A66 | bd 77 79 | ldawater_anim_patterns,x; copy mirrored pattern to screen |
| $7A69 | 99 80 06 | staSCREEN_RAM_R16C0,y |
| $7A6C | ca | b_7A6Cdex; reverse X for mirror effect ; x-ref: $7A64 |
| $7A6D | c8 | iny |
| $7A6E | c0 28 | cpy#$28; 40 tiles total (second half right-to-left) |
| $7A70 | d0 ed | bneb_7A5F |
| $7A72 | 60 | r_7A72rts; x-ref: $7A23, $7A2D |
| $7A73 | | tile14_active_flag.byte$00; x-ref: $4AF8, $7A7A, $7A84, $7ACF, $7C32, ... |
| $7A74 | | tile14_screen_y_lo.byte$00; x-ref: $7A9B, $7AB0, $7AD9, $7FD5 |
| $7A75 | | tile14_screen_y_hi.byte$00; x-ref: $7AA2, $7AB7, $7AE1, $7FDC |
| $7A76 | | tile14_screen_x.byte$00; x-ref: $7AC7, $7AE8, $7FC6 |
| $7A77 | | tile14_render_param.byte$00; x-ref: $7AA7, $7ABC, $7AF0, $7FFA |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| ; Disables tile-14 (special interactive tile) by clearing its active flag. |
| ; Called during room reset to ensure no stale tile-14 state persists. |
| ; |
| ; Inputs: None |
| ; Outputs: tile14_active_flag = $00 |
| ; Side Effects: None |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| $7A78 | a9 00 | reset_tile14_statelda#$00; disable tile-14 ; x-ref: $4B0D |
| $7A7A | 8d 73 7a | statile14_active_flag |
| $7A7D | 60 | rts |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| ; Initializes tile-14 screen parameters from its tile-map coordinates. |
| ; Converts tile column (X) and row (Y) to pixel screen positions for |
| ; collision detection. Stores a render parameter ($BC or $BE) based on |
| ; whether the tile falls in the upper or lower screen region. |
| ; |
| ; Inputs: X = tile column, Y = tile row |
| ; Outputs: tile14_active_flag = $FF, tile14_screen_y_lo/hi, tile14_screen_x, |
| ; tile14_render_param. X and Y preserved via zpa_1E/zpa_1F. |
| ; Side Effects: None |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| $7A7E | 86 1e | init_tile14_paramsstxzp_temp_x; save tile column ; x-ref: $4FDA |
| $7A80 | 84 1f | styzp_temp_y; save tile row |
| $7A82 | a9 ff | lda#$ff; mark tile-14 as active |
| $7A84 | 8d 73 7a | statile14_active_flag |
| $7A87 | a9 00 | lda#$00; clear high byte for Y*8 |
| $7A89 | 85 1d | stazp_ptr_map_hi |
| $7A8B | a5 1f | ldazp_temp_y; Y = tile_row * 8 (pixel Y) |
| $7A8D | 0a | asla |
| $7A8E | 0a | asla |
| $7A8F | 0a | asla |
| $7A90 | 26 1d | rolzp_ptr_map_hi; rotate carry into high byte |
| $7A92 | d0 19 | bneb_7AAD; if hi != 0 or Y >= 160: lower region |
| $7A94 | c9 a0 | cmp#$a0 |
| $7A96 | b0 15 | bcsb_7AAD |
| $7A98 | 18 | clc; upper region: offset by +10 |
| $7A99 | 69 0a | adc#$0a |
| $7A9B | 8d 74 7a | statile14_screen_y_lo |
| $7A9E | a5 1d | ldazp_ptr_map_hi |
| $7AA0 | 69 00 | adc#$00 |
| $7AA2 | 8d 75 7a | statile14_screen_y_hi |
| $7AA5 | a9 bc | lda#$bc; render param = $BC (upper) |
| $7AA7 | 8d 77 7a | statile14_render_param |
| $7AAA | 4c bf 7a | jmpj_7ABF; jump to X-coordinate calc |
| $7AAD | 38 | b_7AADsec; lower region: offset by -2 ; x-ref: $7A92, $7A96 |
| $7AAE | e9 02 | sbc#$02 |
| $7AB0 | 8d 74 7a | statile14_screen_y_lo |
| $7AB3 | a5 1d | ldazp_ptr_map_hi |
| $7AB5 | e9 00 | sbc#$00 |
| $7AB7 | 8d 75 7a | statile14_screen_y_hi |
| $7ABA | a9 be | lda#$be; render param = $BE (lower) |
| $7ABC | 8d 77 7a | statile14_render_param |
| $7ABF | a5 1e | j_7ABFldazp_temp_x; X = tile_col * 8 (pixel X) ; x-ref: $7AAA |
| $7AC1 | 0a | asla |
| $7AC2 | 0a | asla |
| $7AC3 | 0a | asla |
| $7AC4 | 38 | sec; adjust X by -5 for centering |
| $7AC5 | e9 05 | sbc#$05 |
| $7AC7 | 8d 76 7a | statile14_screen_x |
| $7ACA | a6 1e | ldxzp_temp_x; restore tile column to X |
| $7ACC | a4 1f | ldyzp_temp_y; restore tile row to Y |
| $7ACE | 60 | rts |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| ; Sets up sprite rendering parameters for a tile-14 hazard/obstacle entity. |
| ; Checks if the tile is active and rendering is free, then copies the tile's |
| ; screen position (with pixel offsets) and render parameters into the sprite |
| ; multiplexer's ZP slot for the next frame. |
| ; |
| ; Inputs: None (reads tile14_* state variables) |
| ; Outputs: None |
| ; Side Effects: Populates sprite multiplexer ZP slot (Y, X, frame, color) |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| $7ACF | ad 73 7a | setup_tile14_spriteldatile14_active_flag; tile14 active? ; x-ref: $6483 |
| $7AD2 | f0 25 | beqr_7AF9; skip if tile14 inactive |
| $7AD4 | ad a7 3f | ldarendering_in_progress; renderer busy? |
| $7AD7 | d0 20 | bner_7AF9; skip if render in progress |
| $7AD9 | ad 74 7a | ldatile14_screen_y_lo; tile14 screen Y lo |
| $7ADC | 18 | clc |
| $7ADD | 69 0c | adc#$0c; add 12px vertical offset |
| $7ADF | 85 58 | stazp_mux_x_lo_hazard; -> sprite Y pos lo |
| $7AE1 | ad 75 7a | ldatile14_screen_y_hi; tile14 screen Y hi |
| $7AE4 | 69 00 | adc#$00; propagate carry |
| $7AE6 | 85 6b | stazp_mux_x_hi_hazard; -> sprite Y pos hi |
| $7AE8 | ad 76 7a | ldatile14_screen_x; tile14 screen X |
| $7AEB | 18 | clc |
| $7AEC | 69 25 | adc#$25; add 37px horizontal offset |
| $7AEE | 85 45 | stazp_screen_dirty; -> sprite X pos |
| $7AF0 | ad 77 7a | ldatile14_render_param; tile14 sprite frame |
| $7AF3 | 85 7e | stazp_mux_frame_hazard; -> sprite frame ptr |
| $7AF5 | a9 08 | lda#VicIIColors.ORANGE; color = 8 (orange) |
| $7AF7 | 85 91 | stazp_spr_color_extra; -> sprite color |
| $7AF9 | 60 | r_7AF9rts; x-ref: $7AD2, $7AD7 |
| ; Hero state: 0=normal, 1=falling, 2=landed/hover, 3=hit, 4=dying, 5=dead |
| $7AFA | | hero_state.byte$00; x-ref: $1E76, $1E80, $1E91, $61FA, $6FDF, ... |
| ; Hero X position, low byte (16-bit horizontal map coordinate) |
| $7AFB | | hero_x_lo.byte$00; x-ref: $1EB3, $1EF4, $1F3F, $1F79, $1FE7, ... |
| ; Hero X position, high byte (16-bit horizontal map coordinate) |
| $7AFC | | hero_x_hi.byte$00; x-ref: $1EBB, $1EFC, $1F47, $1F81, $1FEF, ... |
| ; Hero Y screen position (vertical pixel row on screen) |
| $7AFD | | hero_y_pos.byte$00; x-ref: $1EA4, $1EE5, $1F30, $1F6A, $1FD8, ... |
| ; Hero X target position (snapped to 8px grid for movement) |
| $7AFE | | hero_x_target.byte$00; x-ref: $7B30, $7CA6, $7CC7, $7CE4, $7DFA, ... |
| ; Hero Y floor limit (lowest Y before death, set on death to snap pos) |
| $7AFF | | hero_y_floor_limit.byte$00; x-ref: $7B3C, $8101, $8192 |
| ; Hero facing direction: 0=none/left-facing, 1=left, 2=right |
| $7B00 | | hero_direction.byte$00; x-ref: $7CAD, $7CB9, $7CD6, $7CE7, $7FA0, ... |
| ; Hero scroll step size / movement direction (1=slow, 2=fast) |
| $7B01 | | hero_scroll_dir.byte$00; x-ref: $1F03, $76D8, $7737, $785C, $7890, ... |
| ; Hero Y velocity (signed: negative=up, positive=down, 0=hover) |
| $7B02 | | hero_y_velocity.byte$00; x-ref: $7E68, $7E89, $7EBA, $7F54 |
| ; Hero airborne flag: $FF=vertical collision active, $00=grounded |
| $7B03 | | hero_airborne_flag.byte$00; x-ref: $7B74, $7C23, $7C4E, $7ED6, $7F5B, ... |
| ; Hero vertical acceleration counter (0-$2E, increases while UP held) |
| $7B04 | | hero_accel_counter.byte$00; x-ref: $7B79, $7C28, $7C53, $7C6B, $7E2C, ... |
| ; Hero entity collision flag: $FF=colliding with platform entity, $00=free |
| hero_entity_collision |
| $7B05 | | .byte$00; x-ref: $7B86, $7C2D, $7C84, $7FA8, $7FAC, ... |
| ; Hero dynamite count (decremented on use, displayed on HUD) |
| $7B06 | | hero_dynamite_count.byte$00; x-ref: $6131, $6254, $626B, $6349, $635F, ... |
| ; Hero VIC-II sprite pointer index (computed from state/direction/frame) |
| $7B07 | | hero_sprite_ptr.byte$00; x-ref: $814B, $815C, $816D, $8181, $81FB |
| ; Hero walk animation frame index (0-4, advances every 4 subframes) |
| $7B08 | | hero_walk_frame.byte$00; x-ref: $7B7E, $7D56, $80C3, $80C6, $80CF, ... |
| ; Hero walk animation sub-frame counter (3→0, ticks per frame) |
| $7B09 | | hero_walk_subframe.byte$00; x-ref: $7B89, $7D5B, $80B9, $80C0 |
| ; Hero hover animation frame index (0-3, advances when tick overflows) |
| $7B0A | | hero_hover_frame.byte$00; x-ref: $7B8C, $80E3, $80E6, $80EF, $8200 |
| ; Hero hover animation tick counter (0→delay, resets on overflow) |
| $7B0B | | hero_hover_tick.byte$00; x-ref: $7B8F, $80D3, $80D6, $80E0 |
| ; Hero animation frame delay threshold ($0E=fast, slower when damaged) |
| $7B0C | | hero_anim_delay.byte$00; x-ref: $7B97, $7C5A, $7C74, $80D9 |
| ; Hero death sub-step counter (0-4 cycle, increments Y on overflow; $FF=frozen) |
| $7B0D | | hero_death_substep.byte$00; x-ref: $7B81, $7BCB, $7BD0, $7BD3, $7BDC, ... |
| ; Hero death timer (decremented each frame, state→5 when zero; init=$50) |
| $7B0E | | hero_death_timer.byte$00; x-ref: $7BE2, $8197 |
| ; Fire button double-tap state machine (0=idle, 1=first tap, 2=confirmed) |
| $7B0F | | hero_fire_tap_state.byte$00; x-ref: $7B92, $8049, $8055, $8066, $806B, ... |
| ; Fire button double-tap timeout counter (init=$19, decrements to 0) |
| $7B10 | | hero_fire_tap_timer.byte$00; x-ref: $804E, $8070 |
| ; Hero invulnerability flag (non-zero=skip all collision checks) |
| $7B11 | | hero_invulnerable.byte$00; x-ref: $1E70, $7B54, $81F6, $826C |
| ; Sprite pointer lookup table for hero walking animation frames |
| $7B12 | | hero_sprite_table.byte$8b, $8c, $8d, $8e, $8f; x-ref: $8174 |
| ; Hero hover animation sprite frames (4 entries: $99, $9A, $9B, $9A - oscillating sequence) |
| $7B17 | | hero_hover_frames.byte$99, $9a, $9b, $9a; x-ref: $8203 |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| ; Initializes the hero entity from a tile-16 spawn point on the level map. |
| ; Converts the tile grid position (X=column, Y=row) into pixel coordinates, |
| ; sets the movement step size based on vertical position, clears state flags, |
| ; and calls the shared entity state initializer. |
| ; |
| ; Inputs: X = tile column, Y = tile row |
| ; Outputs: X = tile column (preserved), Y = tile row (preserved) |
| ; Side Effects: Populates the hero entity state block ($7AFA-$7B11) |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| $7B1B | 86 1e | init_hero_entitystxzp_temp_x; save tile column ; x-ref: $4FED |
| $7B1D | 84 1f | styzp_temp_y; save tile row |
| $7B1F | a9 00 | lda#$00; clear high byte for Y*8 calculation |
| $7B21 | 85 1d | stazp_ptr_map_hi |
| $7B23 | a5 1f | ldazp_temp_y; Y = tile row |
| $7B25 | 0a | asla; row * 2 |
| $7B26 | 0a | asla; row * 4 |
| $7B27 | 0a | asla; row * 8 |
| $7B28 | 26 1d | rolzp_ptr_map_hi; carry into high byte |
| $7B2A | 18 | clc |
| $7B2B | 69 08 | adc#$08; pixel_y = row * 8 + 8 |
| $7B2D | 8d fb 7a | stahero_x_lo; store as hero Y position low |
| $7B30 | 8d fe 7a | stahero_x_target; also set as Y target position |
| $7B33 | a5 1d | ldazp_ptr_map_hi; propagate carry to high byte |
| $7B35 | 69 00 | adc#$00 |
| $7B37 | 8d fc 7a | stahero_x_hi; store Y position high byte |
| $7B3A | a9 15 | lda#$15; hero X pixel position = 21 |
| $7B3C | 8d ff 7a | stahero_y_floor_limit |
| $7B3F | a9 01 | lda#$01; default step = 1 (slow) |
| $7B41 | ae fc 7a | ldxhero_x_hi; check if Y high byte != 0 |
| $7B44 | d0 09 | bneb_7B4F; if high byte set, stay slow |
| $7B46 | ae fb 7a | ldxhero_x_lo; check if Y low < 160 |
| $7B49 | e0 a0 | cpx#$a0 |
| $7B4B | b0 02 | bcsb_7B4F; near top of screen: step = 2 (fast) |
| $7B4D | a9 02 | lda#$02 |
| $7B4F | 8d 01 7b | b_7B4Fstahero_scroll_dir; set hero movement step size ; x-ref: $7B44, $7B4B |
| $7B52 | a9 00 | lda#$00; clear hero state counter |
| $7B54 | 8d 11 7b | stahero_invulnerable |
| $7B57 | 20 68 7b | jsrinit_hero_state; init remaining hero entity fields |
| $7B5A | a6 1e | ldxzp_temp_x; restore tile column |
| $7B5C | a4 1f | ldyzp_temp_y; restore tile row |
| $7B5E | 60 | rts |
| $7B5F | 20 13 80 | j_7B5Fjsrsnap_hero_x_to_tile; x-ref: $617F |
| $7B62 | 20 58 77 | jsrprocess_hit_entities |
| $7B65 | 20 b6 85 | jsrdeactivate_raft |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| ; Initializes hero entity fields to default values for a new life or respawn. |
| ; Sets the hero to state 1 (active/falling), positions Y near top of screen, |
| ; marks as airborne, and clears all animation, collision, and input counters. |
| ; |
| ; Inputs: None |
| ; Outputs: hero_state, hero_y_pos, hero_airborne_flag, hero_accel_counter, |
| ; hero_walk_frame, hero_death_substep, hero_entity_collision, |
| ; hero_walk_subframe, hero_hover_frame, hero_hover_tick, |
| ; hero_fire_tap_state, hero_anim_delay |
| ; Side Effects: None |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| $7B68 | a9 01 | init_hero_statelda#$01; state = 1 (active/falling) ; x-ref: $7B57 |
| $7B6A | 8d fa 7a | stahero_state |
| $7B6D | a9 f0 | lda#$f0; Y = $F0 (240), near top of screen |
| $7B6F | 8d fd 7a | stahero_y_pos |
| $7B72 | a9 ff | lda#$ff; mark hero as airborne |
| $7B74 | 8d 03 7b | stahero_airborne_flag |
| $7B77 | a9 23 | lda#$23; acceleration counter = $23 (35) |
| $7B79 | 8d 04 7b | stahero_accel_counter |
| $7B7C | a9 ff | lda#$ff; $FF = reset walk animation frame |
| $7B7E | 8d 08 7b | stahero_walk_frame |
| $7B81 | 8d 0d 7b | stahero_death_substep; $FF = reset death substep |
| $7B84 | a9 00 | lda#$00; clear collision, walk subframe, hover, fire-tap |
| $7B86 | 8d 05 7b | stahero_entity_collision |
| $7B89 | 8d 09 7b | stahero_walk_subframe |
| $7B8C | 8d 0a 7b | stahero_hover_frame |
| $7B8F | 8d 0b 7b | stahero_hover_tick |
| $7B92 | 8d 0f 7b | stahero_fire_tap_state |
| $7B95 | a9 06 | lda#$06; animation delay = 6 frames |
| $7B97 | 8d 0c 7b | stahero_anim_delay |
| $7B9A | 60 | rts |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| ; Hero state-machine dispatcher. Reads hero_state and branches to the |
| ; appropriate handler: |
| ; State 0: Normal movement - horizontal scroll, vertical update, |
| ; tile collision check, then fire/animation processing. |
| ; State 1: Falling - delegates to handle_falling_movement. |
| ; State 2: Hover/landing - ticks animation, returns to state 0 |
| ; when joystick is released (no direction pressed). |
| ; State 3: Animation-only - tail-calls the animation tick routine. |
| ; State 4: Death sequence - increments death substep, nudges hero |
| ; sprite downward every 5 frames, decrements death timer, |
| ; transitions to state 5 when timer reaches zero. |
| ; Other: Returns immediately (no-op). |
| ; |
| ; Called once per frame from the main game loop. |
| ; |
| ; Inputs: hero_state, joystick_state, hero_death_substep, hero_death_timer |
| ; Outputs: hero_state (may transition), hero_y_pos (death nudge), |
| ; hero_death_substep, hero_death_timer |
| ; Side Effects: Delegates to movement, collision, fire, and animation routines |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| update_hero_state_machine |
| $7B9B | ad fa 7a | ldahero_state; dispatch on hero_state ; x-ref: $61D7 |
| $7B9E | d0 03 | bnestate1_falling; state == 0? -> normal movement |
| $7BA0 | 4c ed 7b | jmpstate0_normal_movement; state 0: jump to normal movement path |
| $7BA3 | c9 01 | state1_fallingcmp#$01; state == 1? ; x-ref: $7B9E |
| $7BA5 | d0 03 | bnestate2_hover_landing; not state 1 -> check next |
| $7BA7 | 4c f3 80 | jmphandle_falling_movement; state 1: tail-call falling handler |
| $7BAA | c9 02 | state2_hover_landingcmp#$02; state == 2? ; x-ref: $7BA5 |
| $7BAC | d0 12 | bnestate3_anim_only; not state 2 -> check next |
| $7BAE | 20 d3 80 | jsradvance_hero_anim_frame; state 2: tick hover animation |
| $7BB1 | ad 80 3e | ldajoystick_state; read joystick direction bits |
| $7BB4 | 29 0f | and#$0f; mask lower nibble (directions) |
| $7BB6 | c9 0f | cmp#$0f; $0F = no direction pressed? |
| $7BB8 | f0 05 | beqr_7BBF; all released -> stay in hover, return |
| $7BBA | a9 00 | lda#$00; direction pressed -> back to state 0 |
| $7BBC | 8d fa 7a | stahero_state; hero_state = 0 (normal) |
| $7BBF | 60 | r_7BBFrts; x-ref: $7BB8 |
| $7BC0 | c9 03 | state3_anim_onlycmp#$03; state == 3? ; x-ref: $7BAC |
| $7BC2 | d0 03 | bnestate4_death_sequence; not state 3 -> check next |
| $7BC4 | 4c d3 80 | jmpadvance_hero_anim_frame; state 3: tail-call animation tick |
| state4_death_sequence |
| $7BC7 | c9 04 | cmp#$04; state == 4? ; x-ref: $7BC2 |
| $7BC9 | d0 21 | bner_7BEC; not state 4 -> return (unknown state) |
| $7BCB | ad 0d 7b | ldahero_death_substep; negative substep? -> skip nudge |
| $7BCE | 30 12 | bmistate_unknown_return |
| $7BD0 | ee 0d 7b | inchero_death_substep |
| $7BD3 | ad 0d 7b | ldahero_death_substep; substep == 5? (time to nudge) |
| $7BD6 | c9 05 | cmp#$05 |
| $7BD8 | d0 08 | bnestate_unknown_return |
| $7BDA | a9 00 | lda#$00; reset substep to 0 |
| $7BDC | 8d 0d 7b | stahero_death_substep |
| $7BDF | ee fd 7a | inchero_y_pos; nudge hero sprite down 1 pixel |
| $7BE2 | ce 0e 7b | state_unknown_returndechero_death_timer; count down death timer ; x-ref: $7BCE, $7BD8 |
| $7BE5 | d0 05 | bner_7BEC; timer not zero -> keep dying |
| $7BE7 | a9 05 | lda#$05; timer expired -> transition to state 5 |
| $7BE9 | 8d fa 7a | stahero_state; hero_state = 5 (death complete) |
| $7BEC | 60 | r_7BECrts; x-ref: $7BC9, $7BE5 |
| state0_normal_movement |
| $7BED | 20 84 7c | jsrhandle_horizontal_scroll; state 0: process horizontal scrolling ; x-ref: $7BA0 |
| $7BF0 | ad fa 7a | ldahero_state; re-check: death started mid-routine? |
| $7BF3 | c9 04 | cmp#$04; state == 4 -> abort, hero just died |
| $7BF5 | d0 01 | bneb_7BF8 |
| $7BF7 | 60 | rts |
| $7BF8 | 20 25 7e | b_7BF8jsrupdate_hero_vertical; process vertical movement/gravity ; x-ref: $7BF5 |
| $7BFB | ad fa 7a | ldahero_state; re-check again after vertical update |
| $7BFE | c9 04 | cmp#$04; state == 4 -> abort, hero just died |
| $7C00 | d0 01 | bneb_7C03 |
| $7C02 | 60 | rts |
| $7C03 | 20 bd 7f | b_7C03jsrcheck_tile14_collision; check tile14 collision, then fall through to fire/animation ; x-ref: $7C00 |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| ; Processes the hero's fire/dynamite action and updates animation speed. |
| ; |
| ; First checks if the hero is dead (a_7AFA == 3). If so, returns immediately. |
| ; Reads the joystick fire button: if pressed, calls s_78FA to process the fire |
| ; action; if not pressed, calls s_7912 to reset pending fire state. |
| ; Then calls s_802A to detect a valid fire-button press/release event. |
| ; If fire is confirmed, checks multiple guard conditions (a_7B03, a_7B04, |
| ; a_7B05, a_7A73 must all be zero, and explosion_state must be 0 or 3) |
| ; before allowing dynamite usage. |
| ; If all guards pass and dynamite count (a_7B06) > 0, clears the dynamite |
| ; sprite from the HUD, decrements the count, and starts the hero explosion. |
| ; Finally, computes the hero animation frame delay: $0E (fast) when undamaged, |
| ; or a slower speed proportional to damage, and advances the animation counter. |
| ; |
| ; Inputs: a_7AFA (game state), joystick_state (fire button), |
| ; a_7B03-a_7B05 (action flags), explosion_state, a_7B06 (dynamite count) |
| ; Outputs: a_7B0C (animation frame delay), a_8AF0 (animation active flag) |
| ; Side Effects: May trigger hero explosion, clears HUD dynamite sprite, |
| ; advances animation frame counter via s_80D3 |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| process_fire_and_animation |
| $7C06 | ad fa 7a | ldahero_state; load game state |
| $7C09 | c9 03 | cmp#$03; state == 3 (dead)? |
| $7C0B | d0 01 | bneb_7C0E; not dead → continue |
| $7C0D | 60 | rts; dead → return early |
| $7C0E | ad 80 3e | b_7C0Eldajoystick_state; read joystick ; x-ref: $7C0B |
| $7C11 | 29 10 | and#$10; fire button (bit 4)? |
| $7C13 | d0 06 | bneb_7C1B; fire NOT pressed → reset fire state |
| $7C15 | 20 fa 78 | jsrhandle_fire_pressed; fire IS pressed → process fire action |
| $7C18 | 4c 1e 7c | jmpj_7C1E; skip fire state reset |
| $7C1B | 20 12 79 | b_7C1Bjsrdeactivate_fire; reset pending fire state ; x-ref: $7C13 |
| $7C1E | 20 2a 80 | j_7C1Ejsrcheck_hero_fire_input; check fire button press/release pattern ; x-ref: $7C18 |
| $7C21 | f0 2b | beqb_7C4E; no valid fire event → skip to animation |
| $7C23 | ad 03 7b | ldahero_airborne_flag; guard: action flag 1 active? |
| $7C26 | d0 26 | bneb_7C4E; busy → skip dynamite |
| $7C28 | ad 04 7b | ldahero_accel_counter; guard: action flag 2 active? |
| $7C2B | d0 21 | bneb_7C4E; busy → skip dynamite |
| $7C2D | ad 05 7b | ldahero_entity_collision; guard: action flag 3 active? |
| $7C30 | d0 1c | bneb_7C4E; busy → skip dynamite |
| $7C32 | ad 73 7a | ldatile14_active_flag; guard: another action in progress? |
| $7C35 | d0 17 | bneb_7C4E; busy → skip dynamite |
| $7C37 | ad 01 6f | ldaexplosion_state; check explosion state |
| $7C3A | f0 04 | beqb_7C40; no explosion → allow dynamite |
| $7C3C | c9 03 | cmp#$03; explosion finished (state 3)? |
| $7C3E | d0 0e | bneb_7C4E; explosion still active → skip dynamite |
| $7C40 | ad 06 7b | b_7C40ldahero_dynamite_count; any dynamite remaining? ; x-ref: $7C3A |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| ; Handles hero taking damage: if lives remain, clears hero tiles, decrements |
| ; the lives counter, and triggers the explosion animation. Then computes |
| ; the animation frame delay based on remaining damage timer, and manages |
| ; the death sound effect state. Falls through from collision guard checks. |
| ; |
| ; Inputs: A (zero flag from a_7B06 lives check), a_7B03/a_7B04 (damage timers) |
| ; Outputs: a_7B06 (decremented), a_7B0C (animation delay), a_8AF0 (sound state) |
| ; Side Effects: Clears hero screen tiles, starts explosion animation, triggers death SFX |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| $7C43 | f0 09 | handle_hero_damagebeqb_7C4E; no dynamite → skip to animation |
| $7C45 | 20 5f 63 | jsrclear_last_dynamite_icon; clear dynamite sprite from HUD |
| $7C48 | ce 06 7b | dechero_dynamite_count; decrement dynamite count |
| $7C4B | 20 3e 70 | jsrinit_hero_explosion; start hero dynamite explosion |
| $7C4E | ad 03 7b | b_7C4Eldahero_airborne_flag; check damage flag 1 ; x-ref: $7C21, $7C26, $7C2B, $7C30, $7C35, ... |
| $7C51 | d0 15 | bneb_7C68; damaged → compute slower speed |
| $7C53 | ad 04 7b | ldahero_accel_counter; check damage flag 2 |
| $7C56 | d0 10 | bneb_7C68; damaged → compute slower speed |
| $7C58 | a9 0e | lda#$0e; undamaged: fast frame delay ($0E) |
| $7C5A | 8d 0c 7b | stahero_anim_delay; store animation frame delay |
| $7C5D | ad f0 8a | ldasfx6_enable; check if animation active |
| $7C60 | f0 1f | beqb_7C81; not active yet → skip to frame advance |
| $7C62 | 20 61 8b | jsrcancel_sfx6; start animation playback |
| $7C65 | 4c 81 7c | jmpb_7C81; skip to frame advance |
| $7C68 | a9 2e | b_7C68lda#$2e; base delay = $2E (46) ; x-ref: $7C51, $7C56 |
| $7C6A | 38 | sec; set carry for subtraction |
| $7C6B | ed 04 7b | sbchero_accel_counter; subtract damage amount |
| $7C6E | 20 c2 21 | jsrdivide_by_5; divide remaining ticks by 5 |
| $7C71 | 18 | clc; clear carry for addition |
| $7C72 | 69 01 | adc#$01; add 1 → minimum delay of 1 |
| $7C74 | 8d 0c 7b | stahero_anim_delay; store slower frame delay |
| $7C77 | ad f0 8a | ldasfx6_enable; check if animation active |
| $7C7A | d0 05 | bneb_7C81; already active → skip to frame advance |
| $7C7C | a9 01 | lda#$01; mark animation as active |
| $7C7E | 8d f0 8a | stasfx6_enable; store animation active flag |
| $7C81 | 4c d3 80 | b_7C81jmpadvance_hero_anim_frame; tail-call: advance animation frame counter ; x-ref: $7C60, $7C65, $7C7A |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| ; Handles horizontal scrolling based on joystick left/right input. |
| ; If vertical movement is active (a_7B05 != 0), only updates the scroll |
| ; direction flag without actually scrolling. Otherwise, reads joystick, |
| ; sets a target position snapped to an 8-pixel grid, moves 2 pixels per |
| ; frame toward the target, checks map tiles for collisions, and handles |
| ; wrap-around at screen edges. |
| ; |
| ; Inputs: joystick_state (bit 2 = left, bit 3 = right) |
| ; Outputs: a_7AFB/a_7AFC (16-bit horizontal position), |
| ; a_7AFE (target position), a_7B00 (direction), |
| ; a_7B01 (scroll direction) |
| ; Side Effects: Calls s_80B9 (animation tick), s_7D5F (tile collision |
| ; check), j_7DE1/j_7E03 (edge wrap-around) |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| handle_horizontal_scroll |
| $7C84 | ad 05 7b | ldahero_entity_collision; check if vertical movement active ; x-ref: $7BED |
| $7C87 | f0 1a | beqb_7CA3; if not, go to main horizontal logic |
| $7C89 | ad 80 3e | ldajoystick_state; vertical active: just read joystick direction |
| $7C8C | 29 04 | and#$04; joystick left? |
| $7C8E | d0 06 | bneb_7C96 |
| $7C90 | a9 01 | lda#$01; set scroll direction = left |
| $7C92 | 8d 01 7b | stahero_scroll_dir |
| $7C95 | 60 | rts |
| $7C96 | ad 80 3e | b_7C96ldajoystick_state; joystick right? ; x-ref: $7C8E |
| $7C99 | 29 08 | and#$08 |
| $7C9B | d0 05 | bner_7CA2 |
| $7C9D | a9 02 | lda#$02; set scroll direction = right |
| $7C9F | 8d 01 7b | stahero_scroll_dir |
| $7CA2 | 60 | r_7CA2rts; x-ref: $7C9B |
| $7CA3 | ad fb 7a | b_7CA3ldahero_x_lo; current pos == target pos? ; x-ref: $7C87 |
| $7CA6 | cd fe 7a | cmphero_x_target |
| $7CA9 | d0 05 | bneb_7CB0; clear movement direction |
| $7CAB | a9 00 | lda#$00 |
| $7CAD | 8d 00 7b | stahero_direction |
| $7CB0 | ad 80 3e | b_7CB0ldajoystick_state; joystick left? ; x-ref: $7CA9 |
| $7CB3 | 29 04 | and#$04 |
| $7CB5 | d0 16 | bneb_7CCD; direction = left |
| $7CB7 | a9 01 | lda#$01 |
| $7CB9 | 8d 00 7b | stahero_direction; scroll direction = left |
| $7CBC | 8d 01 7b | stahero_scroll_dir |
| $7CBF | ad fb 7a | ldahero_x_lo; target = (pos - 1) AND $F8 (snap to 8px grid) |
| $7CC2 | 38 | sec |
| $7CC3 | e9 01 | sbc#$01 |
| $7CC5 | 29 f8 | and#$f8 |
| $7CC7 | 8d fe 7a | stahero_x_target |
| $7CCA | 4c e7 7c | jmpj_7CE7 |
| $7CCD | ad 80 3e | b_7CCDldajoystick_state; joystick right? ; x-ref: $7CB5 |
| $7CD0 | 29 08 | and#$08 |
| $7CD2 | d0 13 | bnej_7CE7 |
| $7CD4 | a9 02 | lda#$02; direction = right |
| $7CD6 | 8d 00 7b | stahero_direction |
| $7CD9 | 8d 01 7b | stahero_scroll_dir; scroll direction = right |
| $7CDC | ad fb 7a | ldahero_x_lo; target = (pos + 8) AND $F8 (snap to 8px grid) |
| $7CDF | 18 | clc |
| $7CE0 | 69 08 | adc#$08 |
| $7CE2 | 29 f8 | and#$f8 |
| $7CE4 | 8d fe 7a | stahero_x_target |
| $7CE7 | ad 00 7b | j_7CE7ldahero_direction; check movement direction ; x-ref: $7CCA, $7CD2 |
| $7CEA | c9 01 | cmp#$01; moving left? |
| $7CEC | d0 31 | bnemove_hero_right |
| $7CEE | ad fb 7a | ldahero_x_lo; subtract 2 pixels from position (16-bit) |
| $7CF1 | 38 | sec |
| $7CF2 | e9 02 | sbc#$02 |
| $7CF4 | 8d fb 7a | stahero_x_lo |
| $7CF7 | ad fc 7a | ldahero_x_hi |
| $7CFA | e9 00 | sbc#$00 |
| $7CFC | 8d fc 7a | stahero_x_hi |
| $7CFF | 20 b9 80 | jsradvance_walk_anim; tick animation frame counter |
| $7D02 | ad fb 7a | ldahero_x_lo; set tile check addr = pos - 8 |
| $7D05 | 38 | sec |
| $7D06 | e9 08 | sbc#$08 |
| $7D08 | 85 06 | stazp_ptr_aux1_lo |
| $7D0A | ad fc 7a | ldahero_x_hi |
| $7D0D | e9 00 | sbc#$00 |
| $7D0F | 85 07 | stazp_ptr_aux1_hi |
| $7D11 | 20 5f 7d | jsrcheck_horiz_tile_collision; check map tiles for collision |
| $7D14 | ad fa 7a | ldahero_state; state == dead? |
| $7D17 | c9 04 | cmp#$04 |
| $7D19 | f0 03 | beqr_7D1E |
| $7D1B | 4c e1 7d | jmpcheck_scroll_down; handle left-edge wrap-around |
| $7D1E | 60 | r_7D1Erts; x-ref: $7D19 |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| ; Moves hero 2 pixels to the right, advances the walk animation frame, |
| ; then checks 4 map tiles at the right edge (pos+7) for wall or obstacle |
| ; collision. If dying (a_7AFA == 4), returns. Otherwise, checks if the |
| ; screen needs to scroll right. |
| ; |
| ; Inputs: a_7AFB/a_7AFC (hero X position), a_7AFD (hero Y row), |
| ; a_7AFA (hero state) |
| ; Outputs: a_7AFB/a_7AFC (updated X position), a_7B08/a_7B09 (anim frame) |
| ; Side Effects: May trigger wall snap (s_8013), obstacle death (j_8185), |
| ; or screen scroll (j_4FF7) |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| $7D1F | c9 02 | move_hero_rightcmp#$02; direction != 1 (not left)? ; x-ref: $7CEC |
| $7D21 | d0 31 | bnereset_walk_anim; no → reset walk anim & return |
| $7D23 | ad fb 7a | ldahero_x_lo; hero_x_lo += 2 (move right) |
| $7D26 | 18 | clc |
| $7D27 | 69 02 | adc#$02 |
| $7D29 | 8d fb 7a | stahero_x_lo; hero_x_hi += carry |
| $7D2C | ad fc 7a | ldahero_x_hi |
| $7D2F | 69 00 | adc#$00 |
| $7D31 | 8d fc 7a | stahero_x_hi |
| $7D34 | 20 b9 80 | jsradvance_walk_anim; advance walk animation frame |
| $7D37 | ad fb 7a | ldahero_x_lo; right edge = hero_x_lo + 7 |
| $7D3A | 18 | clc |
| $7D3B | 69 07 | adc#$07 |
| $7D3D | 85 06 | stazp_ptr_aux1_lo |
| $7D3F | ad fc 7a | ldahero_x_hi; right edge = hero_x_hi + carry |
| $7D42 | 69 00 | adc#$00 |
| $7D44 | 85 07 | stazp_ptr_aux1_hi |
| $7D46 | 20 5f 7d | jsrcheck_horiz_tile_collision; check 4 tiles at right edge column |
| $7D49 | ad fa 7a | ldahero_state; hero state |
| $7D4C | c9 04 | cmp#$04; state == 4? (dying) |
| $7D4E | f0 03 | beqr_7D53; yes → done, already dying |
| $7D50 | 4c 03 7e | jmpcheck_scroll_up; check if screen should scroll right |
| $7D53 | 60 | r_7D53rts; x-ref: $7D4E |
| $7D54 | a9 ff | reset_walk_animlda#$ff; no movement: reset animation frame ; x-ref: $7D21 |
| $7D56 | 8d 08 7b | stahero_walk_frame |
| $7D59 | a9 00 | lda#$00; reset animation sub-counter |
| $7D5B | 8d 09 7b | stahero_walk_subframe |
| $7D5E | 60 | rts |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| ; Checks 4 map tiles in a vertical column at the right edge of the hero. |
| ; Samples tiles at vertical offsets: row-13, row-5, row+3, row+10 relative |
| ; to hero Y position. If any tile >= $1A, snaps position to wall. If any |
| ; tile >= $0D (but < $1A), triggers obstacle death. |
| ; |
| ; Inputs: zpa_06/zpa_07 (column X addr), a_7AFD (hero Y row) |
| ; Outputs: zpa_02-zpa_05 (4 tile values) |
| ; Side Effects: May jump to snap_pos_to_wall or handle_obstacle_hit |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| check_horiz_tile_collision |
| $7D5F | a5 06 | ldazp_ptr_aux1_lo; copy column addr to ZP pointer ; x-ref: $7D11, $7D46 |
| $7D61 | 85 fd | stazp_ptr_dst_lo |
| $7D63 | a5 07 | ldazp_ptr_aux1_hi; Copy Y-pos hi to ZP pointer |
| $7D65 | 85 fe | stazp_ptr_dst_hi |
| $7D67 | ad fd 7a | ldahero_y_pos; hero Y row |
| $7D6A | 38 | sec |
| $7D6B | e9 0d | sbc#$0d; row - 13 = top of hero sprite |
| $7D6D | aa | tax |
| $7D6E | 20 ca 50 | jsrget_map_tile; get tile at top-right |
| $7D71 | 85 02 | stazp_work0; tile_top → zpa_02 |
| $7D73 | a5 06 | ldazp_ptr_aux1_lo; Restore Y-pos for next lookup |
| $7D75 | 85 fd | stazp_ptr_dst_lo |
| $7D77 | a5 07 | ldazp_ptr_aux1_hi |
| $7D79 | 85 fe | stazp_ptr_dst_hi |
| $7D7B | 8a | txa; X-offset += 8 (next row down) |
| $7D7C | 18 | clc |
| $7D7D | 69 08 | adc#$08; Move down 8 rows |
| $7D7F | aa | tax |
| $7D80 | 20 ca 50 | jsrget_map_tile; get tile at upper-mid-right (+8 rows) |
| $7D83 | 85 03 | stazp_work1; tile_upper_mid → zpa_03 |
| $7D85 | a5 06 | ldazp_ptr_aux1_lo; Restore Y-pos for next lookup |
| $7D87 | 85 fd | stazp_ptr_dst_lo |
| $7D89 | a5 07 | ldazp_ptr_aux1_hi |
| $7D8B | 85 fe | stazp_ptr_dst_hi |
| $7D8D | 8a | txa; X-offset += 8 (another row down) |
| $7D8E | 18 | clc |
| $7D8F | 69 08 | adc#$08 |
| $7D91 | aa | tax |
| $7D92 | 20 ca 50 | jsrget_map_tile; get tile at lower-mid-right (+8 more rows) |
| $7D95 | 85 04 | stazp_work2; tile_lower_mid → zpa_04 |
| $7D97 | a5 06 | ldazp_ptr_aux1_lo; Restore Y-pos for next lookup |
| $7D99 | 85 fd | stazp_ptr_dst_lo |
| $7D9B | a5 07 | ldazp_ptr_aux1_hi |
| $7D9D | 85 fe | stazp_ptr_dst_hi |
| $7D9F | ad fd 7a | ldahero_y_pos; hero Y row |
| $7DA2 | 18 | clc |
| $7DA3 | 69 0a | adc#$0a; row + 10 = bottom of hero sprite |
| $7DA5 | 20 ca 50 | jsrget_map_tile; get tile at bottom-right |
| $7DA8 | 85 05 | stazp_work3; tile_bottom → zpa_05 |
| $7DAA | a5 02 | ldazp_work0; --- Check all 4 tiles for walls ($1A+) --- |
| $7DAC | c9 1a | cmp#$1a; tile_top >= $1A? → wall |
| $7DAE | b0 2b | bcssnap_pos_to_wall; Wall hit -> snap to grid |
| $7DB0 | a5 03 | ldazp_work1; tile_upper_mid >= $1A? → wall |
| $7DB2 | c9 1a | cmp#$1a |
| $7DB4 | b0 25 | bcssnap_pos_to_wall; tile_lower_mid >= $1A? → wall |
| $7DB6 | a5 04 | ldazp_work2; Check tile 3 for wall |
| $7DB8 | c9 1a | cmp#$1a; tile_bottom >= $1A? → wall |
| $7DBA | b0 1f | bcssnap_pos_to_wall; Wall hit → snap X to grid |
| $7DBC | a5 05 | ldazp_work3; Check tile 4 for wall |
| $7DBE | c9 1a | cmp#$1a |
| $7DC0 | b0 19 | bcssnap_pos_to_wall; Wall hit → snap X to grid |
| $7DC2 | a5 02 | ldazp_work0; --- Check all 4 tiles for obstacles ($0D-$19) --- |
| $7DC4 | c9 0d | cmp#$0d; tile_top >= $0D? → obstacle |
| $7DC6 | b0 16 | bcstrampoline_hero_death; Hazard hit -> player death |
| $7DC8 | a5 03 | ldazp_work1; tile_upper_mid >= $0D? → obstacle |
| $7DCA | c9 0d | cmp#$0d |
| $7DCC | b0 10 | bcstrampoline_hero_death; tile_lower_mid >= $0D? → obstacle |
| $7DCE | a5 04 | ldazp_work2; Check tile 3 for hazard |
| $7DD0 | c9 0d | cmp#$0d; tile_bottom >= $0D? → obstacle |
| $7DD2 | b0 0a | bcstrampoline_hero_death; Hazard hit → trigger damage |
| $7DD4 | a5 05 | ldazp_work3; Check tile 4 for hazard |
| $7DD6 | c9 0d | cmp#$0d |
| $7DD8 | b0 04 | bcstrampoline_hero_death; Hazard hit → trigger damage |
| $7DDA | 60 | rts; all tiles clear → safe to move |
| $7DDB | 4c 13 80 | snap_pos_to_walljmpsnap_hero_x_to_tile; wall hit: snap X to tile boundary ; x-ref: $7DAE, $7DB4, $7DBA, $7DC0 |
| trampoline_hero_death |
| $7DDE | 4c 85 81 | jmpj_8185; wall collision → kill hero ; x-ref: $7DC6, $7DCC, $7DD2, $7DD8 |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| ; Checks if the hero has reached the bottom screen boundary. If Y position |
| ; is below row 0 (high byte = 0 and low byte < 2), repositions the hero |
| ; to the top of the next screen section (Y = $0138) and triggers a downward |
| ; screen scroll via j_4FF7 with scroll direction = 1. |
| ; |
| ; Inputs: None (reads hero Y position from a_7AFB/a_7AFC) |
| ; Outputs: None |
| ; Side Effects: May reposition hero and trigger screen scroll down |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| $7DE1 | ad fc 7a | check_scroll_downldahero_x_hi; hero Y position high byte ; x-ref: $7D1B |
| $7DE4 | d0 1c | bner_7E02; high byte != 0 → not at bottom boundary |
| $7DE6 | ad fb 7a | ldahero_x_lo; hero Y position low byte |
| $7DE9 | c9 02 | cmp#$02; Y >= 2 → not at bottom boundary |
| $7DEB | b0 15 | bcsr_7E02 |
| $7DED | a9 38 | lda#$38; reposition hero Y low = $38 (top of next screen) |
| $7DEF | 8d fb 7a | stahero_x_lo |
| $7DF2 | a9 01 | lda#$01; set Y high byte = 1 |
| $7DF4 | 8d fc 7a | stahero_x_hi |
| $7DF7 | ad fb 7a | ldahero_x_lo; sync Y target position with new Y |
| $7DFA | 8d fe 7a | stahero_x_target |
| $7DFD | a9 01 | lda#$01; scroll direction = 1 (down) |
| $7DFF | 4c f7 4f | jmpj_4FF7; trigger screen scroll transition |
| $7E02 | 60 | r_7E02rts; x-ref: $7DE4, $7DEB |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| ; Checks if the hero has passed the right scroll boundary. If hero_x >= $013F |
| ; (page 1, offset $3F), resets position to $0008 and triggers a left-scroll |
| ; of the map (scroll direction = 2). |
| ; |
| ; Inputs: a_7AFB/a_7AFC (hero X position) |
| ; Outputs: a_7AFB/a_7AFC (possibly reset), a_7AFE (scroll target) |
| ; Side Effects: May call j_4FF7 to scroll the screen right |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| $7E03 | ad fc 7a | check_scroll_upldahero_x_hi; hero_x_hi ; x-ref: $7D50 |
| $7E06 | f0 1c | beqr_7E24; high byte == 0 → not at top boundary |
| $7E08 | ad fb 7a | ldahero_x_lo; hero Y position low byte |
| $7E0B | c9 3f | cmp#$3f; Y < $3F → not at top boundary |
| $7E0D | 90 15 | bccr_7E24 |
| $7E0F | a9 08 | lda#$08; reposition hero Y low = $08 (bottom of prev screen) |
| $7E11 | 8d fb 7a | stahero_x_lo |
| $7E14 | a9 00 | lda#$00; clear Y high byte |
| $7E16 | 8d fc 7a | stahero_x_hi |
| $7E19 | ad fb 7a | ldahero_x_lo; sync Y target position with new Y |
| $7E1C | 8d fe 7a | stahero_x_target |
| $7E1F | a9 02 | lda#$02; scroll direction = 2 (up) |
| $7E21 | 4c f7 4f | jmpj_4FF7; trigger screen scroll transition |
| $7E24 | 60 | r_7E24rts; x-ref: $7E06, $7E0D |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| ; Updates the hero's vertical (Y-axis) position based on joystick input. |
| ; Reads the joystick UP button to build an acceleration counter (a_7B04), |
| ; converts it to a velocity value (a_7B02), and applies it to the screen |
| ; Y-position (a_7AFD). Checks for map tile collisions above and below |
| ; the hero using get_map_tile. Clamps position at screen boundaries and |
| ; triggers death if a solid or hazard tile is hit. |
| ; |
| ; Inputs: joystick_state (bit 0 = UP), a_7B04 (accel counter), |
| ; a_7AFD (Y screen pos), a_7AFB/a_7AFC (Y map pos lo/hi) |
| ; Outputs: a_7AFD (updated Y pos), a_7B02 (Y velocity), |
| ; a_7B04 (updated accel counter) |
| ; Side Effects: May trigger death (j_8185) on wall collision, |
| ; may call j_4FF7 to scroll screen on boundary hit |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| $7E25 | ad 80 3e | update_hero_verticalldajoystick_state; Read joystick UP button (bit 0) ; x-ref: $7BF8 |
| $7E28 | 29 01 | and#$01; Isolate UP bit |
| $7E2A | d0 0d | bneb_7E39; Branch if UP not pressed |
| $7E2C | ad 04 7b | ldahero_accel_counter; Load vertical accel counter |
| $7E2F | c9 2e | cmp#$2e; Max accel = $2E |
| $7E31 | f0 0e | beqb_7E41 |
| $7E33 | ee 04 7b | inchero_accel_counter; Accelerate upward |
| $7E36 | 4c 41 7e | jmpb_7E41 |
| $7E39 | ad 04 7b | b_7E39ldahero_accel_counter; UP not pressed: decelerate ; x-ref: $7E2A |
| $7E3C | f0 03 | beqb_7E41 |
| $7E3E | ce 04 7b | dechero_accel_counter |
| $7E41 | ad 04 7b | b_7E41ldahero_accel_counter; Convert accel counter to velocity ; x-ref: $7E31, $7E36, $7E3C |
| $7E44 | d0 05 | bneb_7E4B |
| $7E46 | a9 02 | lda#$02; Stopped: velocity = +2 (drift down) |
| $7E48 | 4c 68 7e | jmpj_7E68 |
| $7E4B | c9 2e | b_7E4Bcmp#$2e; x-ref: $7E44 |
| $7E4D | 90 05 | bccb_7E54 |
| $7E4F | a9 fe | lda#$fe; Max accel: velocity = -2 (fast up) |
| $7E51 | 4c 68 7e | jmpj_7E68 |
| $7E54 | c9 26 | b_7E54cmp#$26; x-ref: $7E4D |
| $7E56 | 90 05 | bccb_7E5D |
| $7E58 | a9 ff | lda#$ff; High accel: velocity = -1 (medium up) |
| $7E5A | 4c 68 7e | jmpj_7E68 |
| $7E5D | c9 08 | b_7E5Dcmp#$08; x-ref: $7E56 |
| $7E5F | b0 05 | bcsb_7E66 |
| $7E61 | a9 01 | lda#$01; Low accel: velocity = +1 (slow down) |
| $7E63 | 4c 68 7e | jmpj_7E68 |
| $7E66 | a9 00 | b_7E66lda#$00; Medium accel: velocity = 0 (hover) ; x-ref: $7E5F |
| $7E68 | 8d 02 7b | j_7E68stahero_y_velocity; Store Y velocity ; x-ref: $7E48, $7E51, $7E5A, $7E63 |
| $7E6B | 18 | clc |
| $7E6C | 6d fd 7a | adchero_y_pos; Apply velocity to Y screen position |
| $7E6F | 8d fd 7a | stahero_y_pos |
| $7E72 | c9 15 | cmp#$15; Min altitude threshold = $15 |
| $7E74 | b0 0d | bcsb_7E83 |
| $7E76 | ad 9e 3f | ldacurrent_room_index; Check fuel/scroll level |
| $7E79 | c9 08 | cmp#$08; If fuel >= 8, skip clamp |
| $7E7B | b0 06 | bcsb_7E83 |
| $7E7D | a9 15 | lda#$15; Clamp Y pos to minimum altitude |
| $7E7F | 8d fd 7a | stahero_y_pos |
| $7E82 | 60 | rts |
| $7E83 | 20 62 7f | b_7E83jsrcheck_entity_collision; Check platform/entity collision ; x-ref: $7E74, $7E7B |
| $7E86 | f0 01 | beqb_7E89; Z=1 means collision handled, skip movement |
| $7E88 | 60 | rts |
| $7E89 | ad 02 7b | b_7E89ldahero_y_velocity; Check velocity direction ; x-ref: $7E86 |
| $7E8C | f0 19 | beqb_7EA7; Zero velocity: skip tile check |
| $7E8E | 10 0d | bplb_7E9D; Negative = moving up |
| $7E90 | ad fd 7a | ldahero_y_pos; Moving up: check tiles 13px above |
| $7E93 | 38 | sec |
| $7E94 | e9 0d | sbc#$0d |
| $7E96 | aa | tax |
| $7E97 | 20 d4 7e | jsrcheck_vertical_collision |
| $7E9A | 4c a7 7e | jmpb_7EA7 |
| $7E9D | ad fd 7a | b_7E9Dldahero_y_pos; Moving down: check tiles 10px below ; x-ref: $7E8E |
| $7EA0 | 18 | clc |
| $7EA1 | 69 0a | adc#$0a |
| $7EA3 | aa | tax |
| $7EA4 | 20 d4 7e | jsrcheck_vertical_collision |
| $7EA7 | ad fa 7a | b_7EA7ldahero_state; Check if hero already dead ; x-ref: $7E8C, $7E9A |
| $7EAA | c9 04 | cmp#$04; State 4 = dead, exit early |
| $7EAC | d0 01 | bneb_7EAF |
| $7EAE | 60 | rts |
| $7EAF | ad fd 7a | b_7EAFldahero_y_pos; Check Y pos against screen bounds ; x-ref: $7EAC |
| $7EB2 | c9 fc | cmp#$fc; Upper bound = $FC |
| $7EB4 | b0 1d | bcsr_7ED3 |
| $7EB6 | c9 8c | cmp#$8c; Lower bound = $8C |
| $7EB8 | 90 19 | bccr_7ED3 |
| $7EBA | ad 02 7b | ldahero_y_velocity; At boundary: check direction |
| $7EBD | 10 0a | bplb_7EC9 |
| $7EBF | a9 8b | lda#$8b; Moving up: clamp to top ($8B) |
| $7EC1 | 8d fd 7a | stahero_y_pos |
| $7EC4 | a9 03 | lda#$03; Scroll screen down (state 3) |
| $7EC6 | 4c f7 4f | jmpj_4FF7 |
| $7EC9 | a9 fc | b_7EC9lda#$fc; Moving down: clamp to bottom ($FC) ; x-ref: $7EBD |
| $7ECB | 8d fd 7a | stahero_y_pos |
| $7ECE | a9 04 | lda#$04; Scroll screen up (state 4) |
| $7ED0 | 4c f7 4f | jmpj_4FF7 |
| $7ED3 | 60 | r_7ED3rts; x-ref: $7EB4, $7EB8 |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| ; Checks for vertical collisions by probing three horizontal positions |
| ; (left, right, far-right) at the current vertical offset. Reads map |
| ; tiles at each probe point and branches based on tile type: |
| ; - Tile >= $1A (solid wall): snap Y to grid boundary |
| ; - Tile >= $0D (hazard): trigger player death |
| ; - Otherwise: no collision, return |
| ; |
| ; Inputs: X = vertical pixel offset (adjusted Y position from caller) |
| ; a_7AFB/a_7AFC = player horizontal position (16-bit) |
| ; Outputs: a_7B03 = set to $FF on entry (vertical collision flag) |
| ; a_7AFD = adjusted Y position on wall collision |
| ; a_7B0D = cleared on tile $80 collision |
| ; Side Effects: Triggers death via j_8185 on hazard tiles |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| check_vertical_collision |
| $7ED4 | a9 ff | lda#$ff; Set vertical collision flag ; x-ref: $7E97, $7EA4 |
| $7ED6 | 8d 03 7b | stahero_airborne_flag |
| $7ED9 | ad fb 7a | ldahero_x_lo; Player X position low byte |
| $7EDC | 38 | sec; Probe left: pos - 8 |
| $7EDD | e9 08 | sbc#$08 |
| $7EDF | 85 fd | stazp_ptr_dst_lo; Store probe address low byte |
| $7EE1 | ad fc 7a | ldahero_x_hi; Player X position high byte |
| $7EE4 | e9 00 | sbc#$00; Propagate borrow |
| $7EE6 | 85 fe | stazp_ptr_dst_hi; Store probe address high byte |
| $7EE8 | 8a | txa; Y offset to A for get_map_tile |
| $7EE9 | 20 ca 50 | jsrget_map_tile; Get tile ID at left probe |
| $7EEC | 85 02 | stazp_work0; Store left tile ID |
| $7EEE | ad fb 7a | ldahero_x_lo; Probe right: pos + 1 |
| $7EF1 | 18 | clc |
| $7EF2 | 69 01 | adc#$01 |
| $7EF4 | 85 fd | stazp_ptr_dst_lo; Store probe address high byte |
| $7EF6 | ad fc 7a | ldahero_x_hi; Get tile ID at right probe |
| $7EF9 | 69 00 | adc#$00; Store right tile ID |
| $7EFB | 85 fe | stazp_ptr_dst_hi |
| $7EFD | 8a | txa |
| $7EFE | 20 ca 50 | jsrget_map_tile |
| $7F01 | 85 03 | stazp_work1 |
| $7F03 | ad fb 7a | ldahero_x_lo; Probe far-right: pos + 7 |
| $7F06 | 18 | clc |
| $7F07 | 69 07 | adc#$07 |
| $7F09 | 85 fd | stazp_ptr_dst_lo |
| $7F0B | ad fc 7a | ldahero_x_hi |
| $7F0E | 69 00 | adc#$00 |
| $7F10 | 85 fe | stazp_ptr_dst_hi |
| $7F12 | 8a | txa |
| $7F13 | 20 ca 50 | jsrget_map_tile; Get tile ID at far-right probe |
| $7F16 | 85 04 | stazp_work2; Store far-right tile ID |
| $7F18 | a5 02 | ldazp_work0; Check left tile |
| $7F1A | c9 1a | cmp#$1a; Tile >= $1A? (solid wall) |
| $7F1C | b0 1f | bcsb_7F3D; Yes → wall collision |
| $7F1E | a5 03 | ldazp_work1; Check right tile |
| $7F20 | c9 1a | cmp#$1a |
| $7F22 | b0 19 | bcsb_7F3D; Yes → wall collision |
| $7F24 | a5 04 | ldazp_work2; Check far-right tile |
| $7F26 | c9 1a | cmp#$1a |
| $7F28 | b0 13 | bcsb_7F3D; Yes → wall collision |
| $7F2A | a5 02 | ldazp_work0; Re-check left tile |
| $7F2C | c9 0d | cmp#$0d; Tile >= $0D? (hazard) |
| $7F2E | b0 2f | bcsb_7F5F; Yes → trigger death |
| $7F30 | a5 03 | ldazp_work1 |
| $7F32 | c9 0d | cmp#$0d |
| $7F34 | b0 29 | bcsb_7F5F; Yes → trigger death |
| $7F36 | a5 04 | ldazp_work2 |
| $7F38 | c9 0d | cmp#$0d; Check far-right hazard |
| $7F3A | b0 23 | bcsb_7F5F; Yes → trigger death |
| $7F3C | 60 | rts; No collision — return |
| $7F3D | c9 80 | b_7F3Dcmp#$80; Is tile $80? (special solid) ; x-ref: $7F1C, $7F22, $7F28 |
| $7F3F | d0 08 | bneb_7F49 |
| $7F41 | a9 00 | lda#$00; Clear collision counter |
| $7F43 | 8d 0d 7b | stahero_death_substep |
| $7F46 | 4c 85 81 | jmpj_8185; Trigger death for special solid |
| $7F49 | ad fd 7a | b_7F49ldahero_y_pos; Snap Y to 8-pixel grid boundary ; x-ref: $7F3F |
| $7F4C | 29 f8 | and#$f8 |
| $7F4E | 18 | clc |
| $7F4F | 69 05 | adc#$05 |
| $7F51 | 8d fd 7a | stahero_y_pos |
| $7F54 | ad 02 7b | ldahero_y_velocity; Moving up? |
| $7F57 | 30 05 | bmir_7F5E; Yes → skip clearing |
| $7F59 | a9 00 | lda#$00; Clear vertical velocity |
| $7F5B | 8d 03 7b | stahero_airborne_flag |
| $7F5E | 60 | r_7F5Erts; x-ref: $7F57 |
| $7F5F | 4c 85 81 | b_7F5Fjmpj_8185; Trigger death for hazard tile ; x-ref: $7F2E, $7F34, $7F3A |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| ; Checks whether the hero collides with the secondary entity ($82AB-$82AE). |
| ; Compares X and Y pixel distances between the hero and the entity; |
| ; if within range, snaps the hero X to the entity position, clears movement |
| ; state, and sets the collision flag. Otherwise, restores hero Y from the |
| ; saved position if the collision flag was previously active. |
| ; |
| ; Inputs: Hero position ($7AFB/$7AFC = Y lo/hi, $7AFD = X), entity position |
| ; ($82AB = active flag, $82AC/$82AD = Y lo/hi, $82AE = X) |
| ; Outputs: A = 0 if no collision / entity inactive; A != 0 if collision. |
| ; Hero X ($7AFD), movement state ($7B00, $7B03, $7B05) modified on hit. |
| ; Side Effects: On collision, hero snaps to entity X - 2 and movement is halted. |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| check_entity_collision |
| $7F62 | ad ab 82 | ldatile13_active_flag; entity active? ; x-ref: $7E83 |
| $7F65 | f0 45 | beqb_7FAC; inactive -> no collision |
| $7F67 | ad fd 7a | ldahero_y_pos; hero_x |
| $7F6A | 38 | sec |
| $7F6B | ed ae 82 | sbctile13_column; hero_x - entity_x |
| $7F6E | c9 01 | cmp#$01; X dist >= 1? (too far right) |
| $7F70 | 10 3a | bplb_7FAC |
| $7F72 | c9 fe | cmp#$fe; X dist < -2? (too far left) |
| $7F74 | 30 36 | bmib_7FAC |
| $7F76 | ad fb 7a | ldahero_x_lo; hero_y_lo |
| $7F79 | 38 | sec |
| $7F7A | ed ac 82 | sbctile13_scroll_pos_lo; hero_y - entity_y (lo) |
| $7F7D | a8 | tay; Y distance low byte -> Y reg |
| $7F7E | ad fc 7a | ldahero_x_hi |
| $7F81 | ed ad 82 | sbctile13_scroll_pos_hi; hero_y - entity_y (hi, w/ borrow) |
| $7F84 | d0 07 | bneb_7F8D; hi != 0 -> check if negative |
| $7F86 | c0 0e | cpy#$0e; Y dist < 14px? -> collision! |
| $7F88 | b0 22 | bcsb_7FAC; too far -> no collision |
| $7F8A | 4c 95 7f | jmpj_7F95; collision: skip sign check |
| $7F8D | c9 ff | b_7F8Dcmp#$ff; hi == $FF? (negative Y dist) ; x-ref: $7F84 |
| $7F8F | d0 1b | bneb_7FAC; not $FF -> too far, no collision |
| $7F91 | c0 f3 | cpy#$f3; lo >= $F3? (-13 signed) |
| $7F93 | 90 17 | bccb_7FAC; in range -> fall to collision |
| $7F95 | ad ae 82 | j_7F95ldatile13_column; --- collision response --- ; x-ref: $7F8A |
| $7F98 | 38 | sec |
| $7F99 | e9 02 | sbc#$02; hero_x = entity_x - 2 |
| $7F9B | 8d fd 7a | stahero_y_pos; store new hero_x |
| $7F9E | a9 00 | lda#$00 |
| $7FA0 | 8d 00 7b | stahero_direction; clear horiz movement |
| $7FA3 | 8d 03 7b | stahero_airborne_flag; clear vert movement |
| $7FA6 | a9 ff | lda#$ff; set collision active flag |
| $7FA8 | 8d 05 7b | stahero_entity_collision |
| $7FAB | 60 | rts |
| $7FAC | ad 05 7b | b_7FACldahero_entity_collision; --- no collision path --- ; x-ref: $7F65, $7F70, $7F74, $7F88, $7F8F, ... |
| $7FAF | f0 0b | beqr_7FBC; was collision flag clear? done |
| $7FB1 | ad fb 7a | ldahero_x_lo; restore hero_y from saved pos |
| $7FB4 | 8d fe 7a | stahero_x_target; -> hero_y_saved |
| $7FB7 | a9 00 | lda#$00 |
| $7FB9 | 8d 05 7b | stahero_entity_collision; clear collision flag |
| $7FBC | 60 | r_7FBCrts; x-ref: $7FAF |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| ; Checks collision between the player and tile-14 (destructible wall/object). |
| ; Compares player X position (a_7AFD) against tile-14 X (tile14_screen_x) and |
| ; player Y position (a_7AFB/a_7AFC) against tile-14 Y (tile14_screen_y_lo/hi). |
| ; On hit: sets player state to 3 (hit), awards 1000 points, increments tile-14 |
| ; render counter, stops fire SFX, and silences SID voice 1. |
| ; |
| ; Inputs: tile14_active_flag, tile14_screen_x, tile14_screen_y_lo/hi, |
| ; a_7AFB/a_7AFC (player Y 16-bit), a_7AFD (player X) |
| ; Outputs: a_7AFA = #$03 on collision (hit state) |
| ; Side Effects: Awards 1000 BCD points, stops SFX, silences SID voice 1 |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| check_tile14_collision |
| $7FBD | ad 73 7a | ldatile14_active_flag; tile14 active? ; x-ref: $7C03 |
| $7FC0 | f0 50 | beqr_8012; Not active -> exit |
| $7FC2 | ad fd 7a | ldahero_y_pos; delta_x = player_x - tile14_x |
| $7FC5 | 38 | sec |
| $7FC6 | ed 76 7a | sbctile14_screen_x |
| $7FC9 | c9 1c | cmp#$1c; delta_x >= 28? too far right |
| $7FCB | 10 45 | bplr_8012 |
| $7FCD | c9 e5 | cmp#$e5; delta_x < -27? too far left |
| $7FCF | 30 41 | bmir_8012 |
| $7FD1 | ad fb 7a | ldahero_x_lo; delta_y_lo = player_y_lo - tile14_y_lo |
| $7FD4 | 38 | sec |
| $7FD5 | ed 74 7a | sbctile14_screen_y_lo |
| $7FD8 | a8 | tay; Y = delta_y lo |
| $7FD9 | ad fc 7a | ldahero_x_hi; delta_y_hi = player_y_hi - tile14_y_hi |
| $7FDC | ed 75 7a | sbctile14_screen_y_hi |
| $7FDF | d0 07 | bneb_7FE8; hi byte nonzero? check negative |
| $7FE1 | c0 16 | cpy#$16; delta_y_lo >= 22? too far below |
| $7FE3 | b0 2d | bcsr_8012 |
| $7FE5 | 4c f0 7f | jmpj_7FF0 |
| $7FE8 | c9 ff | b_7FE8cmp#$ff; hi == $FF? (negative delta) ; x-ref: $7FDF |
| $7FEA | d0 26 | bner_8012; delta_y_lo < $EB? too far above |
| $7FEC | c0 eb | cpy#$eb |
| $7FEE | 90 22 | bccr_8012 |
| $7FF0 | a9 03 | j_7FF0lda#$03; Collision! Set player state = hit ; x-ref: $7FE5 |
| $7FF2 | 8d fa 7a | stahero_state |
| $7FF5 | a9 00 | lda#$00; Clear tile14 state |
| $7FF7 | 8d 00 7b | stahero_direction |
| $7FFA | ee 77 7a | inctile14_render_param; Increment tile14 render counter |
| $7FFD | a9 00 | lda#$00; Y < $15? Above visible area |
| $7FFF | 85 fb | stazp_ptr_src_lo; yes -> skip to anim update |
| $8001 | a9 10 | lda#$10; Y < floor limit? |
| $8003 | 85 fc | stazp_ptr_src_hi |
| $8005 | a9 00 | lda#$00; Score hi = $00 |
| $8007 | 85 fd | stazp_ptr_dst_lo |
| $8009 | 20 d8 51 | jsrj_51D8; Add BCD score |
| $800C | 20 12 79 | jsrdeactivate_fire; Stop fire SFX if active |
| $800F | 4c 58 8b | jmpsilence_sfx6_voice1; Silence SID voice 1 (tail call) |
| $8012 | 60 | r_8012rts; x-ref: $7FC0, $7FCB, $7FCF, $7FE3, $7FEA, ... |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| ; Snaps the hero's X position to the nearest 8-pixel tile boundary. |
| ; Adds 4 (half a tile) and masks with $F8 to round to the nearest |
| ; aligned position. Also updates the X movement target. |
| ; |
| ; Inputs: hero_x_lo, hero_x_hi |
| ; Outputs: hero_x_lo, hero_x_hi, hero_x_target |
| ; Side Effects: None |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| $8013 | ad fb 7a | snap_hero_x_to_tileldahero_x_lo; x-ref: $7B5F, $7DDB |
| $8016 | 18 | clc; prepare for addition |
| $8017 | 69 04 | adc#$04; add half a tile width (4 pixels) |
| $8019 | 29 f8 | and#$f8; mask to 8-pixel boundary (round to nearest tile) |
| $801B | 8d fb 7a | stahero_x_lo; store snapped X low byte |
| $801E | 8d fe 7a | stahero_x_target; also set as movement target |
| $8021 | ad fc 7a | ldahero_x_hi |
| $8024 | 69 00 | adc#$00; propagate carry to high byte |
| $8026 | 8d fc 7a | stahero_x_hi; store updated X high byte |
| $8029 | 60 | rts |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| ; Dispatches fire-button detection across input modes. |
| ; Checks whether the fire button was newly pressed this frame. |
| ; - If transition_active != 0: checks joystick port 1 fire (bit 1 falling edge). |
| ; - If input_mode == 0: same joystick port 1 check. |
| ; - If input_mode == 1: double-tap fire detection on joystick port 1, |
| ; using a 25-frame ($19) timer and a 3-state tap state machine. |
| ; - If input_mode == 2: keyboard row 7, key $EF ("2" key). |
| ; - Otherwise: joystick port 2 fire (bit 5 falling edge). |
| ; |
| ; Inputs: None (reads transition_active, input_mode, joystick_state, joystick_prev_state) |
| ; Outputs: A = $FF if fire just pressed, $00 otherwise |
| ; Side Effects: Modifies hero_fire_tap_state and hero_fire_tap_timer (in double-tap mode) |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| check_hero_fire_input |
| $802A | ad 08 1d | ldatransition_active; is a screen transition active? ; x-ref: $7C1E |
| $802D | d0 05 | bneb_8034; yes → skip to joystick port 1 check |
| $802F | ad d7 60 | ldainput_mode; 0=joy1, 1=double-tap, 2=keyboard, other=joy2 |
| $8032 | d0 11 | bneb_8045; mode != 0 → branch to mode dispatch |
| $8034 | ad 80 3e | b_8034ldajoystick_state; --- Mode 0 / transition: joystick port 1 fire --- ; x-ref: $802D |
| $8037 | 29 02 | and#$02; bit 1 = fire button |
| $8039 | d0 78 | bnefire_not_detected; fire held → not pressed (need release first) |
| $803B | ad 81 3e | ldajoystick_prev_state |
| $803E | 29 02 | and#$02; bit 1 of prev state |
| $8040 | f0 71 | beqfire_not_detected; was also released → no edge → not pressed |
| $8042 | 4c b6 80 | jmpfire_detected; falling edge: was up, now down → fire! |
| $8045 | c9 01 | b_8045cmp#$01; --- Mode 1: double-tap fire detection --- ; x-ref: $8032 |
| $8047 | d0 46 | bnecheck_fire_pressed; mode != 1 → check keyboard/joy2 |
| $8049 | ad 0f 7b | ldahero_fire_tap_state; tap_state: 0=idle, 1=first tap, 2=second tap |
| $804C | f0 0a | beqb_8058; idle → skip timer countdown |
| $804E | ce 10 7b | dechero_fire_tap_timer; count down 25-frame window |
| $8051 | d0 05 | bneb_8058; timer not expired → keep waiting |
| $8053 | a9 00 | lda#$00; timer expired → reset tap state to idle |
| $8055 | 8d 0f 7b | stahero_fire_tap_state |
| $8058 | ad 80 3e | b_8058ldajoystick_state; check current joystick fire button ; x-ref: $804C, $8051 |
| $805B | 29 02 | and#$02; bit 1 = fire button |
| $805D | d0 23 | bneb_8082; fire held this frame → check if release needed |
| $805F | ad 81 3e | ldajoystick_prev_state |
| $8062 | 29 02 | and#$02; check if fire was held last frame |
| $8064 | f0 4d | beqfire_not_detected; no falling edge → not pressed |
| $8066 | ad 0f 7b | ldahero_fire_tap_state; check current tap state |
| $8069 | d0 0b | bneb_8076; not idle → check for 2nd tap |
| $806B | ee 0f 7b | inchero_fire_tap_state; 1st tap detected → advance state |
| $806E | a9 19 | lda#$19; start 25-frame ($19) timer window |
| $8070 | 8d 10 7b | stahero_fire_tap_timer |
| $8073 | 4c b3 80 | jmpfire_not_detected; 1st tap registered, don't fire yet |
| $8076 | c9 02 | b_8076cmp#$02; is this the 2nd tap (state == 2)? ; x-ref: $8069 |
| $8078 | d0 39 | bnefire_not_detected; not 2nd tap → ignore |
| $807A | a9 00 | lda#$00; 2nd tap confirmed → reset state |
| $807C | 8d 0f 7b | stahero_fire_tap_state |
| $807F | 4c b6 80 | jmpfire_detected; double-tap complete → fire! |
| $8082 | ad 0f 7b | b_8082ldahero_fire_tap_state; fire held: if 1st tap, advance to state 2 ; x-ref: $805D |
| $8085 | c9 01 | cmp#$01 |
| $8087 | d0 2a | bnefire_not_detected; not in 1st-tap state → no action |
| $8089 | ee 0f 7b | inchero_fire_tap_state; advance 1→2 (awaiting 2nd tap release) |
| $808C | 4c b3 80 | jmpfire_not_detected; still waiting, don't fire yet |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| ; Checks if the fire button was newly pressed this frame. |
| ; Branched to from the input dispatcher when input mode is not joystick port 1. |
| ; If A=2, checks keyboard row 7 for the fire key ($EF = "2" key). |
| ; Otherwise, checks joystick port 2 fire button (bit 5 falling edge). |
| ; Returns A=$FF if fire was just pressed, A=$00 otherwise. |
| ; |
| ; Inputs: A = input mode (2 = keyboard, other = joystick port 2) |
| ; Outputs: A = $FF (fire pressed) or $00 (not pressed) |
| ; Side Effects: None |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| $808F | c9 02 | check_fire_pressedcmp#$02; keyboard mode? ; x-ref: $8047 |
| $8091 | d0 0f | bnecheck_fire_joystick; not keyboard -> check joystick |
| $8093 | ad 16 3f | ldakb_row7_cur; read current keyboard row 7 |
| $8096 | cd 17 3f | cmpkb_row7_prev; changed since last frame? |
| $8099 | f0 18 | beqfire_not_detected; no change -> not pressed |
| $809B | c9 ef | cmp#$ef; $EF = fire key ("2") pressed |
| $809D | d0 14 | bnefire_not_detected; wrong key -> not pressed |
| $809F | 4c b6 80 | jmpfire_detected; fire key detected! |
| $80A2 | ad 80 3e | check_fire_joystickldajoystick_state; read joystick port 2 state ; x-ref: $8091 |
| $80A5 | 29 20 | and#$20; bit 5 = fire button |
| $80A7 | d0 0a | bnefire_not_detected; fire not held -> no press |
| $80A9 | ad 81 3e | ldajoystick_prev_state; read previous joystick state |
| $80AC | 29 20 | and#$20 |
| $80AE | f0 03 | beqfire_not_detected; was also held last frame -> not new |
| $80B0 | 4c b6 80 | jmpfire_detected; new fire press detected! |
| $80B3 | a9 00 | fire_not_detectedlda#$00; return: fire NOT pressed ; x-ref: $8039, $8040, $8064, $8073, $8078, ... |
| $80B5 | 60 | rts |
| $80B6 | a9 ff | fire_detectedlda#$ff; return: fire WAS pressed ; x-ref: $8042, $807F, $809F, $80B0 |
| $80B8 | 60 | rts |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| ; Advances the hero walk animation by one sub-frame tick. |
| ; Decrements the sub-frame counter; when it wraps below zero, resets it |
| ; to 3 and increments the frame index. Frame index wraps from 4 back to 0, |
| ; giving a 5-frame walk cycle (0–4) with 4 sub-frame ticks per frame. |
| ; |
| ; Inputs: hero_walk_subframe (sub-frame counter), hero_walk_frame (frame index) |
| ; Outputs: hero_walk_subframe (decremented/reset), hero_walk_frame (advanced/wrapped) |
| ; Side Effects: None |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| $80B9 | ce 09 7b | advance_walk_animdechero_walk_subframe; sub-frame tick-- ; x-ref: $7CFF, $7D34 |
| $80BC | 10 14 | bplr_80D2; still counting down? skip |
| $80BE | a9 03 | lda#$03; reset sub-frame to 3 (4 ticks/frame) |
| $80C0 | 8d 09 7b | stahero_walk_subframe |
| $80C3 | ee 08 7b | inchero_walk_frame; next animation frame |
| $80C6 | ad 08 7b | ldahero_walk_frame |
| $80C9 | c9 05 | cmp#$05; reached frame 5? |
| $80CB | d0 05 | bner_80D2; no -> keep current frame |
| $80CD | a9 00 | lda#$00; wrap frame back to 0 |
| $80CF | 8d 08 7b | stahero_walk_frame |
| $80D2 | 60 | r_80D2rts; x-ref: $80BC, $80CB |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| ; Advances the hero hover animation timer. Increments the tick counter |
| ; and, when it reaches the animation delay threshold, resets the tick |
| ; and advances to the next frame (cycling 0-3). |
| ; |
| ; Inputs: hero_hover_tick ($7B0B), hero_anim_delay ($7B09), hero_hover_frame ($7B0A) |
| ; Outputs: hero_hover_tick (incremented/reset), hero_hover_frame (incremented/reset) |
| ; Side Effects: None |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| advance_hero_anim_frame |
| $80D3 | ee 0b 7b | inchero_hover_tick; tick++ ; x-ref: $7BAE, $7BC4, $7C81, $813F |
| $80D6 | ad 0b 7b | ldahero_hover_tick; load current tick |
| $80D9 | cd 0c 7b | cmphero_anim_delay; reached delay threshold? |
| $80DC | 90 14 | bccr_80F2; no -> return early |
| $80DE | a9 00 | lda#$00; reset tick to 0 |
| $80E0 | 8d 0b 7b | stahero_hover_tick |
| $80E3 | ee 0a 7b | inchero_hover_frame; advance to next frame |
| $80E6 | ad 0a 7b | ldahero_hover_frame; load current frame |
| $80E9 | c9 04 | cmp#$04; frame >= 4? (max frames) |
| $80EB | d0 05 | bner_80F2; no -> return |
| $80ED | a9 00 | lda#$00; wrap frame back to 0 |
| $80EF | 8d 0a 7b | stahero_hover_frame |
| $80F2 | 60 | r_80F2rts; x-ref: $80DC, $80EB |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| ; Advances the hero downward by incrementing the vertical descent |
| ; counter (a_7AFD). Checks vertical bounds ($F0 max, $15 min) and |
| ; whether the hero has passed the floor limit (a_7AFF). |
| ; If within bounds, probes the map tiles 8 pixels above and 7 pixels |
| ; below the hero at the adjusted X offset (X-15) using get_map_tile. |
| ; If both tiles are non-solid (tile ID < $0D), transitions the hero |
| ; movement state (a_7AFA) to 2 (hovering). Otherwise exits to the |
| ; animation frame update (s_80D3). |
| ; |
| ; Inputs: a_7AFB/a_7AFC = hero Y pos (lo/hi), a_7AFD = descent counter, a_7AFF = floor limit |
| ; Outputs: a_7AFA = hero movement state (set to 2 if path clear) |
| ; Side Effects: Calls get_map_tile (overwrites $FB/$FC), advances animation via s_80D3 |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| handle_falling_movement |
| $80F3 | ee fd 7a | inchero_y_pos; descent counter++ ; x-ref: $7BA7 |
| $80F6 | ad fd 7a | ldahero_y_pos; load updated descent pos |
| $80F9 | c9 f0 | cmp#$f0; Y >= $F0? out of bounds |
| $80FB | b0 42 | bcsb_813F; yes -> skip to anim update |
| $80FD | c9 15 | cmp#$15; Y < $15? above visible area |
| $80FF | 90 3e | bccb_813F; yes -> skip to anim update |
| $8101 | cd ff 7a | cmphero_y_floor_limit; Y < floor limit? |
| $8104 | 90 39 | bccb_813F; yes -> skip to anim update |
| $8106 | ad fb 7a | ldahero_x_lo; hero Y position low byte |
| $8109 | 38 | sec; compute Y - 8 (8 px above) |
| $810A | e9 08 | sbc#$08 |
| $810C | 85 fd | stazp_ptr_dst_lo; store as map query Y-lo |
| $810E | ad fc 7a | ldahero_x_hi; Y high byte |
| $8111 | e9 00 | sbc#$00; subtract borrow |
| $8113 | 85 fe | stazp_ptr_dst_hi; store as map query Y-hi |
| $8115 | ad fd 7a | ldahero_y_pos; load X position for tile check |
| $8118 | 38 | sec |
| $8119 | e9 0f | sbc#$0f; X - 15 (left edge offset) |
| $811B | aa | tax; X = adjusted X for map query |
| $811C | 20 ca 50 | jsrget_map_tile; get tile at (X-15, Y-8) |
| $811F | c9 0d | cmp#$0d; tile >= $0D? (solid) |
| $8121 | b0 1c | bcsb_813F; solid above -> stop descent |
| $8123 | ad fb 7a | ldahero_x_lo; hero Y pos low byte again |
| $8126 | 18 | clc |
| $8127 | 69 07 | adc#$07; Y + 7 (7 px below) |
| $8129 | 85 fd | stazp_ptr_dst_lo; store as map query Y-lo |
| $812B | ad fc 7a | ldahero_x_hi; Y high byte |
| $812E | 69 00 | adc#$00; add carry |
| $8130 | 85 fe | stazp_ptr_dst_hi; store as map query Y-hi |
| $8132 | 8a | txa; restore adjusted X position |
| $8133 | 20 ca 50 | jsrget_map_tile; get tile at (X-15, Y+7) |
| $8136 | c9 0d | cmp#$0d; tile >= $0D? (solid) |
| $8138 | b0 05 | bcsb_813F; solid below -> stop descent |
| $813A | a9 02 | lda#$02; both clear: set state = 2 (hovering) |
| $813C | 8d fa 7a | stahero_state; update hero movement state |
| $813F | 4c d3 80 | b_813Fjmpadvance_hero_anim_frame; advance animation frame and return ; x-ref: $80FB, $80FF, $8104, $8121, $8138 |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| ; Selects the hero's sprite pointer based on current state, direction, |
| ; and animation frame. Computes a VIC-II sprite pointer index and |
| ; stores it in a_7B07. |
| ; |
| ; a_7AFA >= 4 -> death/special sprite ($98) |
| ; a_7B03 != 0 -> airborne/attack set: frame*7 + $88 |
| ; a_7B00 == 0 -> ground facing-left set: frame*7 + $82 |
| ; a_7B00 != 0 -> ground facing-right: lookup f_7B12[a_7B08], |
| ; +7 if a_7B00 > 1 (multi-dir variant) |
| ; |
| ; Inputs: a_7AFA (entity state), a_7B00 (direction), a_7B01 (frame), |
| ; a_7B03 (airborne flag), a_7B08 (table index) |
| ; Outputs: a_7B07 (sprite pointer) |
| ; Side Effects: None |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| select_hero_sprite_ptr |
| $8142 | ad fa 7a | ldahero_state; Get entity state ; x-ref: $61EF |
| $8145 | c9 04 | cmp#$04; State >= 4? (death/special) |
| $8147 | 90 06 | bccb_814F; Yes: skip to death sprite |
| $8149 | a9 98 | lda#$98; Death/special sprite pointer = $98 |
| $814B | 8d 07 7b | stahero_sprite_ptr; Store sprite pointer |
| $814E | 60 | rts |
| $814F | ad 03 7b | b_814Fldahero_airborne_flag; Airborne/attack flag set? ; x-ref: $8147 |
| $8152 | f0 0c | beqb_8160; No: check direction |
| $8154 | ad 01 7b | ldahero_scroll_dir; Get animation frame index |
| $8157 | 20 ac 21 | jsrmultiply_by_7; A = frame * 7 |
| $815A | 69 88 | adc#$88; Airborne sprite base = $88 |
| $815C | 8d 07 7b | stahero_sprite_ptr; Store sprite pointer |
| $815F | 60 | rts |
| $8160 | ad 00 7b | b_8160ldahero_direction; Get direction (0=left) ; x-ref: $8152 |
| $8163 | d0 0c | bneb_8171; Non-zero: use lookup table |
| $8165 | ad 01 7b | ldahero_scroll_dir; Get animation frame index |
| $8168 | 20 ac 21 | jsrmultiply_by_7; A = frame * 7 |
| $816B | 69 82 | adc#$82; Ground-left sprite base = $82 |
| $816D | 8d 07 7b | stahero_sprite_ptr; Store sprite pointer |
| $8170 | 60 | rts |
| $8171 | ae 08 7b | b_8171ldxhero_walk_frame; Get frame table index ; x-ref: $8163 |
| $8174 | bd 12 7b | ldahero_sprite_table,x; Lookup sprite ptr from table |
| $8177 | ae 00 7b | ldxhero_direction; Re-check direction |
| $817A | e0 01 | cpx#$01; Direction == 1? Use as-is |
| $817C | f0 03 | beqb_8181; Direction > 1: skip ahead |
| $817E | 18 | clc; Clear carry for addition |
| $817F | 69 07 | adc#$07; Add 7 for alt direction variant |
| $8181 | 8d 07 7b | b_8181stahero_sprite_ptr; Store final sprite pointer ; x-ref: $817C |
| $8184 | 60 | rts |
| $8185 | a9 04 | j_8185lda#$04; x-ref: $1F53, $1F5E, $1F95, $1FAE, $1FB9, ... |
| $8187 | 8d fa 7a | stahero_state |
| $818A | ad fd 7a | ldahero_y_pos |
| $818D | 29 f8 | and#$f8 |
| $818F | 38 | sec |
| $8190 | e9 08 | sbc#$08 |
| $8192 | 8d ff 7a | stahero_y_floor_limit |
| $8195 | a9 50 | lda#$50 |
| $8197 | 8d 0e 7b | stahero_death_timer |
| $819A | 20 12 79 | jsrdeactivate_fire |
| $819D | a9 00 | lda#$00 |
| $819F | 8d f0 8a | stasfx6_enable |
| $81A2 | a9 01 | lda#$01 |
| $81A4 | 8d 1a 8a | stasfx_ch4_state |
| $81A7 | 60 | rts |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| ; Positions the bomb/dynamite sprite relative to the hero's current location. |
| ; If rendering is in progress, hides the sprite by setting Y to $FF. |
| ; Otherwise, copies the hero's X/Y position (with offsets) into the bomb's |
| ; sprite slot ZP variables, selects the sprite frame based on hero state |
| ; and hover animation, and handles the invulnerability override frame. |
| ; |
| ; Inputs: hero_x_lo/hi, hero_y_pos, hero_state, hero_scroll_dir, |
| ; hero_sprite_ptr, hero_hover_frame, hero_invulnerable, |
| ; rendering_in_progress |
| ; Outputs: zp_spr_x_lo/hi, zp_spr_y_pos, zp_spr_frame, |
| ; zpa_47, zpa_5A, zpa_34, zpa_6D |
| ; Side Effects: None |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| $81A8 | ad a7 3f | setup_bomb_spriteldarendering_in_progress; Check if rendering is active ; x-ref: $6486 |
| $81AB | f0 07 | beqb_81B4; If not rendering, proceed to position |
| $81AD | a9 ff | lda#$ff; Hide sprite: Y = $FF (offscreen) |
| $81AF | 85 33 | stazp_spr_y_pos |
| $81B1 | 85 34 | stazp_mux_y_bomb; Also hide collision Y |
| $81B3 | 60 | rts |
| $81B4 | ad fb 7a | b_81B4ldahero_x_lo; Base X = hero_x_lo ; x-ref: $81AB |
| $81B7 | 18 | clc |
| $81B8 | 69 0c | adc#$0c; Offset +12 pixels right |
| $81BA | 85 46 | stazp_spr_x_lo |
| $81BC | ad fc 7a | ldahero_x_hi |
| $81BF | 69 00 | adc#$00 |
| $81C1 | 85 59 | stazp_spr_x_hi |
| $81C3 | ad fa 7a | ldahero_state; Check hero state |
| $81C6 | c9 04 | cmp#$04; State >= 4? (crouching/special) |
| $81C8 | b0 17 | bcsb_81E1; Yes: skip X offset adjustment |
| $81CA | ad 01 7b | ldahero_scroll_dir; Check scroll direction |
| $81CD | c9 01 | cmp#$01; Facing right? (dir == 1) |
| $81CF | f0 10 | beqb_81E1; Yes: use base X without nudge |
| $81D1 | a5 46 | ldazp_spr_x_lo; Facing left: nudge X back 6px |
| $81D3 | 38 | sec |
| $81D4 | e9 06 | sbc#$06; X - 6 for left-facing offset |
| $81D6 | 85 47 | stazp_mux_x_lo_bomb |
| $81D8 | a5 59 | ldazp_spr_x_hi |
| $81DA | e9 00 | sbc#$00 |
| $81DC | 85 5a | stazp_mux_x_hi_bomb |
| $81DE | 4c e9 81 | jmpj_81E9 |
| $81E1 | a5 46 | b_81E1ldazp_spr_x_lo; x-ref: $81C8, $81CF |
| $81E3 | 85 47 | stazp_mux_x_lo_bomb |
| $81E5 | a5 59 | ldazp_spr_x_hi |
| $81E7 | 85 5a | stazp_mux_x_hi_bomb |
| $81E9 | ad fd 7a | j_81E9ldahero_y_pos; Base Y = hero Y pos ; x-ref: $81DE |
| $81EC | 18 | clc |
| $81ED | 69 25 | adc#$25; Offset +37 pixels down (near feet) |
| $81EF | 85 33 | stazp_spr_y_pos |
| $81F1 | 38 | sec |
| $81F2 | e9 03 | sbc#$03; Collision Y = sprite Y - 3 |
| $81F4 | 85 34 | stazp_mux_y_bomb |
| $81F6 | ad 11 7b | ldahero_invulnerable; Is hero invulnerable? |
| $81F9 | d0 17 | bneb_8212; Yes: use invulnerability frame |
| $81FB | ad 07 7b | ldahero_sprite_ptr; Normal: load hero sprite pointer |
| $81FE | 85 6c | stazp_spr_frame |
| $8200 | ae 0a 7b | ldxhero_hover_frame; Index into hover animation table |
| $8203 | bd 17 7b | ldahero_hover_frames,x; Get hover frame from f_7B17 table |
| $8206 | ae fa 7a | ldxhero_state; Re-check hero state |
| $8209 | e0 04 | cpx#$04; State >= 4? |
| $820B | 90 02 | bccb_820F; No: use hover frame |
| $820D | a9 9b | lda#$9b; Override: crouching frame = $9B |
| $820F | 85 6d | b_820Fstazp_mux_frame_bomb; Store secondary sprite frame ; x-ref: $820B |
| $8211 | 60 | rts |
| $8212 | a9 9c | b_8212lda#$9c; Invulnerable: frame = $9C (flash) ; x-ref: $81F9 |
| $8214 | 85 6c | stazp_spr_frame |
| $8216 | a9 89 | lda#$89; Invulnerable secondary frame = $89 |
| $8218 | 85 6d | stazp_mux_frame_bomb |
| $821A | 60 | rts |
| ; Current energy (0-128). Decremented by energy drain; used as SID freq for SFX |
| $821B | | energy_level.byte$00; x-ref: $6206, $6228, $622D, $824A, $8286, ... |
| ; Energy drain 16-bit fractional accumulator, lo-byte |
| $821C | | energy_drain_frac_lo.byte$00; x-ref: $824F, $8271, $8278 |
| ; Energy drain fractional accumulator, hi-byte. Carry triggers energy_level decrement |
| $821D | | energy_drain_frac_hi.byte$00; x-ref: $8252, $827B, $8281 |
| ; Energy drain speed per frame, lo-byte (loaded from table by level) |
| energy_drain_speed_lo |
| $821E | | .byte$00; x-ref: $825D, $8275 |
| ; Energy drain speed per frame, hi-byte |
| energy_drain_speed_hi |
| $821F | | .byte$00; x-ref: $8263, $827E |
| ; 16-bit drain rate table indexed by level (higher = faster drain) |
| energy_drain_rate_tbl |
| $8220 | | .byte$70; x-ref: $825A |
| ; Hi-bytes of energy drain rate table |
| energy_drain_rate_tbl_hi |
| $8221 | | .byte$0d, $b8, $06, $d7, $03, $b0, $02, $3d; x-ref: $8260 |
| $8229 | | .byte$02, $eb, $01, $94, $01, $7e, $01, $73 |
| $8231 | | .byte$01, $60, $01, $58, $01, $58, $01, $58 |
| $8239 | | .byte$01, $2b, $01, $58, $01, $58, $01, $58 |
| $8241 | | .byte$01, $58, $01, $1e, $01, $24, $01 |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| ; Initializes energy for the current level. Sets energy_level to the |
| ; maximum value ($80 = 128) and configures the per-level drain speed |
| ; from a lookup table indexed by current_level. |
| ; |
| ; Inputs: current_level (used to index the drain rate table) |
| ; Outputs: energy_level = $80, energy_drain_frac_lo/hi = 0, |
| ; energy_drain_speed_lo/hi = table value for current level |
| ; Side Effects: None |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| $8248 | a9 80 | init_energylda#$80; Energy starts at max (128) ; x-ref: $6137 |
| $824A | 8d 1b 82 | staenergy_level; Store initial energy |
| $824D | a9 00 | lda#$00; Zero the fractional drain accumulator |
| $824F | 8d 1c 82 | staenergy_drain_frac_lo |
| $8252 | 8d 1d 82 | staenergy_drain_frac_hi |
| $8255 | ad d9 60 | ldacurrent_level; current_level * 2 = word table index |
| $8258 | 0a | asla |
| $8259 | aa | tax; Look up drain rate for current level |
| $825A | bd 20 82 | ldaenergy_drain_rate_tbl,x; Load drain rate lo for this level |
| $825D | 8d 1e 82 | staenergy_drain_speed_lo |
| $8260 | bd 21 82 | ldaenergy_drain_rate_tbl_hi,x; Load drain rate hi for this level |
| $8263 | 8d 1f 82 | staenergy_drain_speed_hi |
| $8266 | 60 | rts |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| ; Drains the hero's energy over time using a 16-bit fractional accumulator. |
| ; When the accumulator overflows, energy_level is decremented. If energy |
| ; reaches zero, triggers hero death via j_8185. After each drain tick, |
| ; updates the on-screen energy bar by writing tile characters to scr_lava_row. |
| ; Skipped entirely if hero is dead (hero_state != 0) or invulnerable. |
| ; |
| ; Inputs: energy_drain_speed_lo/hi (drain rate), energy_level |
| ; Outputs: energy_drain_frac_lo/hi (updated), energy_level (decremented on overflow) |
| ; Side Effects: Updates energy bar display on screen; may trigger hero death |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| $8267 | ad fa 7a | update_energy_drainldahero_state; skip if hero is dead ; x-ref: $61E9 |
| $826A | d0 33 | bner_829F |
| $826C | ad 11 7b | ldahero_invulnerable; skip if hero is invulnerable |
| $826F | d0 2e | bner_829F |
| $8271 | ad 1c 82 | ldaenergy_drain_frac_lo; add drain speed to 16-bit fractional counter |
| $8274 | 18 | clc; carry = overflow, drain 1 energy unit |
| $8275 | 6d 1e 82 | adcenergy_drain_speed_lo |
| $8278 | 8d 1c 82 | staenergy_drain_frac_lo |
| $827B | ad 1d 82 | ldaenergy_drain_frac_hi; Accumulate drain hi-byte |
| $827E | 6d 1f 82 | adcenergy_drain_speed_hi |
| $8281 | 8d 1d 82 | staenergy_drain_frac_hi |
| $8284 | 90 19 | bccr_829F |
| $8286 | ce 1b 82 | decenergy_level; Drain overflow: decrement energy |
| $8289 | d0 03 | bneupdate_energy_bar_display |
| $828B | 20 85 81 | jsrj_8185; energy depleted: trigger hero death |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| ; Updates the on-screen energy bar by writing the appropriate tile character |
| ; at the correct column of the HUD lava row. The energy value (0-128) is |
| ; divided by 4 to find the character column, and the 2-bit remainder selects |
| ; one of 4 tile phases ($5A-$5D) to show a smooth depletion animation. |
| ; |
| ; Inputs: energy_level (current energy, 0-128) |
| ; Outputs: scr_lava_row updated at column (energy_level / 4) |
| ; Side Effects: Modifies one character cell on the HUD row |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| update_energy_bar_display |
| $828E | ad 1b 82 | ldaenergy_level; A = energy level (0-128) ; x-ref: $6230, $8289 |
| $8291 | 4a | lsra; energy / 4 (step 1) |
| $8292 | 4a | lsra; energy / 4 (step 2) |
| $8293 | aa | tax; X = column index in bar (0-32) |
| $8294 | ad 1b 82 | ldaenergy_level; reload energy for sub-cell phase |
| $8297 | 29 03 | and#$03; A = phase within cell (0-3) |
| $8299 | 18 | clc |
| $829A | 69 5a | adc#$5a; $5A = base tile for energy bar |
| $829C | 9d d7 06 | staSCREEN_RAM_R18C7,x; draw tile at bar column X |
| $829F | 60 | r_829Frts; x-ref: $826A, $826F, $8284 |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| ; Fills the entire energy bar row on screen with the "full" tile character ($5E). |
| ; Used during HUD initialization to display a full energy bar. |
| ; |
| ; Inputs: None |
| ; Outputs: scr_lava_row[0..31] = $5E |
| ; Side Effects: Updates the on-screen energy bar display row |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| $82A0 | a2 1f | fill_energy_barldx#$1f; loop counter: 31 down to 0 (32 bytes) ; x-ref: $62CC |
| $82A2 | a9 5e | lda#$5e; tile $5E = full energy bar character |
| $82A4 | 9d d7 06 | b_82A4staSCREEN_RAM_R18C7,x; fill energy bar row with full tile ; x-ref: $82A8 |
| $82A7 | ca | dex; next column |
| $82A8 | 10 fa | bplb_82A4; loop until all 32 bytes filled |
| $82AA | 60 | rts |
| $82AB | | tile13_active_flag.byte$00; x-ref: $4AFB, $7F62, $82B2, $82BC, $82FA, ... |
| $82AC | | tile13_scroll_pos_lo.byte$00; x-ref: $7F7A, $82CD, $82E9, $830C, $8312, ... |
| $82AD | | tile13_scroll_pos_hi.byte$00; x-ref: $7F81, $82D4, $82E4, $8318, $831D, ... |
| $82AE | | tile13_column.byte$00; x-ref: $7F6B, $7F95, $82DF, $8332, $8368, ... |
| $82AF | | tile13_scroll_dir.byte$00; x-ref: $82F2, $8305, $833E, $8374 |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| ; Disables tile 13 scrolling by clearing the active flag. |
| ; Called during room initialization to reset the scroll subsystem. |
| ; |
| ; Inputs: None |
| ; Outputs: tile13_active_flag = 0 |
| ; Side Effects: None |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| $82B0 | a9 00 | reset_tile13_scrolllda#$00; disable tile 13 scroll ; x-ref: $4B10 |
| $82B2 | 8d ab 82 | statile13_active_flag; clear active flag |
| $82B5 | 60 | rts |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| ; Initializes tile 13 horizontal scroll parameters. |
| ; Converts tile grid position (X=row, Y=column) into a pixel-based scroll |
| ; target and determines initial scroll direction based on viewport position. |
| ; |
| ; Inputs: X = tile row, Y = tile column |
| ; Outputs: tile13_scroll_pos_lo/hi = target pixel position, |
| ; tile13_column = pixel column offset, |
| ; tile13_scroll_dir = $01 (left) or $02 (right) |
| ; Side Effects: Sets tile13_active_flag to $FF (enabled) |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| $82B6 | 86 1e | init_tile13_scrollstxzp_temp_x; save tile row ; x-ref: $4FD3 |
| $82B8 | 84 1f | styzp_temp_y; save tile column |
| $82BA | a9 ff | lda#$ff; mark scrolling as active |
| $82BC | 8d ab 82 | statile13_active_flag; enable active flag |
| $82BF | a9 00 | lda#$00; clear high byte for multiply |
| $82C1 | 85 1d | stazp_ptr_map_hi |
| $82C3 | a5 1f | ldazp_temp_y; column * 8 = pixel X position |
| $82C5 | 0a | asla |
| $82C6 | 0a | asla |
| $82C7 | 0a | asla |
| $82C8 | 26 1d | rolzp_ptr_map_hi; carry from column*8 into hi byte |
| $82CA | 18 | clc |
| $82CB | 69 0c | adc#$0c; add 12 pixel offset |
| $82CD | 8d ac 82 | statile13_scroll_pos_lo; store target scroll pos lo |
| $82D0 | a5 1d | ldazp_ptr_map_hi |
| $82D2 | 69 00 | adc#$00; add carry to hi byte |
| $82D4 | 8d ad 82 | statile13_scroll_pos_hi; store target scroll pos hi |
| $82D7 | a5 1e | ldazp_temp_x; row |
| $82D9 | 0a | asla; row * 8 = pixel Y position |
| $82DA | 0a | asla |
| $82DB | 0a | asla |
| $82DC | 38 | sec; subtract 3 to center vertically |
| $82DD | e9 03 | sbc#$03 |
| $82DF | 8d ae 82 | statile13_column; store column pixel offset |
| $82E2 | a9 01 | lda#$01; assume scroll left (dir=$01) |
| $82E4 | ae ad 82 | ldxtile13_scroll_pos_hi; check if pos hi > 0 |
| $82E7 | d0 09 | bneb_82F2 |
| $82E9 | ae ac 82 | ldxtile13_scroll_pos_lo; check if pos lo >= $A0 (160) |
| $82EC | e0 a0 | cpx#$a0 |
| $82EE | b0 02 | bcsb_82F2 |
| $82F0 | a9 02 | lda#$02; below 160: scroll right (dir=$02) |
| $82F2 | 8d af 82 | b_82F2statile13_scroll_dir; store scroll direction ; x-ref: $82E7, $82EE |
| $82F5 | a6 1e | ldxzp_temp_x; restore tile row in X |
| $82F7 | a4 1f | ldyzp_temp_y; restore tile column in Y |
| $82F9 | 60 | rts |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| ; Per-frame update for tile 13 scrolling. |
| ; Scrolls the viewport 2 pixels per frame toward the tile 13 target position. |
| ; Checks map tile boundaries and reverses direction if blocked by a wall |
| ; (tile ID >= $1A). Updates the shared scroll position at a_7AFB/a_7AFC. |
| ; |
| ; Inputs: tile13_active_flag, tile13_scroll_dir, a_7B05 |
| ; Outputs: tile13_scroll_pos_lo/hi updated, a_7AFB/a_7AFC updated |
| ; Side Effects: May reverse scroll direction if a wall tile is encountered |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| $82FA | ad ab 82 | update_tile13_scrollldatile13_active_flag; check if tile 13 scroll is active ; x-ref: $61E3 |
| $82FD | f0 05 | beqr_8304; inactive: skip update |
| $82FF | ad 05 7b | ldahero_entity_collision; check if scroll-needed flag is set |
| $8302 | d0 01 | bneb_8305; scroll needed: continue |
| $8304 | 60 | r_8304rts; x-ref: $82FD |
| $8305 | ad af 82 | b_8305ldatile13_scroll_dir; check direction: $01=left, $02=right ; x-ref: $8302 |
| $8308 | c9 01 | cmp#$01 |
| $830A | d0 36 | bneb_8342; not left: jump to scroll-right branch |
| $830C | ad ac 82 | ldatile13_scroll_pos_lo; load current scroll pos lo |
| $830F | 38 | sec |
| $8310 | e9 02 | sbc#$02 |
| $8312 | 8d ac 82 | statile13_scroll_pos_lo; store updated pos lo |
| $8315 | 8d fb 7a | stahero_x_lo; copy to shared scroll register |
| $8318 | ad ad 82 | ldatile13_scroll_pos_hi; borrow from hi byte |
| $831B | e9 00 | sbc#$00 |
| $831D | 8d ad 82 | statile13_scroll_pos_hi |
| $8320 | 8d fc 7a | stahero_x_hi |
| $8323 | ad ac 82 | ldatile13_scroll_pos_lo; store updated pos hi to shared register |
| $8326 | 38 | sec; compute left boundary: pos - 14 |
| $8327 | e9 0e | sbc#$0e |
| $8329 | 85 fd | stazp_ptr_dst_lo |
| $832B | ad ad 82 | ldatile13_scroll_pos_hi |
| $832E | e9 00 | sbc#$00 |
| $8330 | 85 fe | stazp_ptr_dst_hi |
| $8332 | ad ae 82 | ldatile13_column; subtract 14 to get left edge for boundary check |
| $8335 | 20 ca 50 | jsrget_map_tile |
| $8338 | c9 1a | cmp#$1a |
| $833A | 90 05 | bccr_8341 |
| $833C | a9 02 | lda#$02 |
| $833E | 8d af 82 | statile13_scroll_dir; get tile at left boundary |
| $8341 | 60 | r_8341rts; x-ref: $833A |
| $8342 | ad ac 82 | b_8342ldatile13_scroll_pos_lo; no wall: keep scrolling left ; x-ref: $830A |
| $8345 | 18 | clc |
| $8346 | 69 02 | adc#$02; set direction = right |
| $8348 | 8d ac 82 | statile13_scroll_pos_lo; load current scroll pos lo |
| $834B | 8d fb 7a | stahero_x_lo |
| $834E | ad ad 82 | ldatile13_scroll_pos_hi; add 2 pixels (scroll right) |
| $8351 | 69 00 | adc#$00 |
| $8353 | 8d ad 82 | statile13_scroll_pos_hi; copy to shared scroll register lo |
| $8356 | 8d fc 7a | stahero_x_hi |
| $8359 | ad ac 82 | ldatile13_scroll_pos_lo; compute right boundary: pos + 12 |
| $835C | 18 | clc |
| $835D | 69 0c | adc#$0c |
| $835F | 85 fd | stazp_ptr_dst_lo |
| $8361 | ad ad 82 | ldatile13_scroll_pos_hi |
| $8364 | 69 00 | adc#$00 |
| $8366 | 85 fe | stazp_ptr_dst_hi |
| $8368 | ad ae 82 | ldatile13_column |
| $836B | 20 ca 50 | jsrget_map_tile; get tile at right boundary |
| $836E | c9 1a | cmp#$1a; tile >= $1A is a wall? |
| $8370 | 90 05 | bccr_8377; no wall: keep scrolling right |
| $8372 | a9 01 | lda#$01; wall hit: reverse to scroll left |
| $8374 | 8d af 82 | statile13_scroll_dir; set direction = left |
| $8377 | 60 | r_8377rts; x-ref: $8370 |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| ; Sets up the sprite parameters for tile 13 (scrolling tile entity). |
| ; Checks if tile 13 is active and rendering is not locked, then writes |
| ; the sprite X/Y position, frame pointer, and color into the shared |
| ; ZP sprite slots for the multiplexer to pick up. |
| ; |
| ; Inputs: tile13_active_flag, tile13_scroll_pos_lo/hi, tile13_column |
| ; Outputs: zpa_58/zpa_6B (sprite X lo/hi), zp_screen_dirty (sprite Y), |
| ; zpa_7E (sprite frame), zp_spr_color_extra (sprite color) |
| ; Side Effects: None |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| $8378 | ad ab 82 | setup_tile13_spriteldatile13_active_flag; tile 13 active? ; x-ref: $648C |
| $837B | f0 24 | beqr_83A1; no → skip |
| $837D | ad a7 3f | ldarendering_in_progress; renderer busy? |
| $8380 | d0 1f | bner_83A1; yes → skip to avoid conflict |
| $8382 | ad ac 82 | ldatile13_scroll_pos_lo; tile 13 X position lo |
| $8385 | 18 | clc |
| $8386 | 69 0c | adc#$0c; add 12-pixel X offset |
| $8388 | 85 58 | stazp_mux_x_lo_hazard; → sprite X lo |
| $838A | ad ad 82 | ldatile13_scroll_pos_hi; tile 13 X position hi |
| $838D | 69 00 | adc#$00; propagate carry |
| $838F | 85 6b | stazp_mux_x_hi_hazard; → sprite X hi |
| $8391 | ad ae 82 | ldatile13_column; tile 13 Y position |
| $8394 | 18 | clc |
| $8395 | 69 25 | adc#$25; add 37-pixel Y offset |
| $8397 | 85 45 | stazp_screen_dirty; → sprite Y |
| $8399 | a9 bb | lda#$bb; sprite frame $BB = tile 13 shape |
| $839B | 85 7e | stazp_mux_frame_hazard; → sprite frame |
| $839D | a9 07 | lda#VicIIColors.YELLOW; $07 = yellow |
| $839F | 85 91 | stazp_spr_color_extra; → sprite color |
| $83A1 | 60 | r_83A1rts; x-ref: $837B, $8380 |
| ; Raft/tile-15 active flag ($00=inactive, $FF=active) |
| $83A2 | | raft_active.byte$00; x-ref: $1F65, $847D, $8487, $84C8, $84F4, ... |
| ; Raft pixel Y position, lo-byte (row*8 + 8) |
| $83A3 | | raft_pixel_y_lo.byte$00; x-ref: $1F7D, $849B |
| ; Raft pixel Y position, hi-byte |
| $83A4 | | raft_pixel_y_hi.byte$00; x-ref: $1F84, $84A2 |
| ; Raft pixel X position (col*8 + $14) |
| $83A5 | | raft_pixel_x.byte$00; x-ref: $1F6E, $84B0 |
| ; Raft tile row index (used for screen address calculation) |
| $83A6 | | raft_tile_row.byte$00; x-ref: $8490, $8501, $852F |
| ; Raft tile column index (used for screen address calculation) |
| $83A7 | | raft_tile_col.byte$00; x-ref: $84A7, $84FA, $8528 |
| ; Current raft animation frame (tile index from bounce table, 0-4) |
| $83A8 | | raft_anim_frame.byte$00; x-ref: $1F89, $1F9F, $84BB, $84ED, $853B, ... |
| ; Index into raft bounce sequence table (0-7, wraps around) |
| $83A9 | | raft_anim_seq_idx.byte$00; x-ref: $84B5, $84DD, $84E7 |
| ; Raft animation tick counter (0-7, advances frame when reaching 8) |
| $83AA | | raft_anim_tick.byte$00; x-ref: $84C0, $84CE, $84D1, $84DA |
| ; Ping-pong animation sequence: {0,1,2,3,4,3,2,1} |
| $83AB | | raft_anim_bounce_tbl.byte$00, $01, $02, $03, $04, $03, $02, $01; x-ref: $84B8, $84EA |
| $83B3 | | .byte$01, $02, $00, $01, $14, $02, $00, $01 |
| $83BB | | .byte$16, $14, $00, $01, $15, $16, $14, $01 |
| $83C3 | | .byte$14, $15, $16, $14, $00, $02, $00, $02 |
| $83CB | | .byte$00, $02, $00, $14, $00, $02, $14, $15 |
| $83D3 | | .byte$00, $14, $15, $16, $14, $15, $16, $14 |
| $83DB | | .byte$00, $01, $02, $00, $15, $01, $02, $00 |
| $83E3 | | .byte$14, $15, $02, $00, $18, $14, $15, $00 |
| $83EB | | .byte$17, $18, $14, $15, $02, $01, $01, $00 |
| $83F3 | | .byte$02, $01, $01, $17, $02, $01, $17, $18 |
| $83FB | | .byte$02, $17, $18, $14, $17, $18, $14, $15 |
| $8403 | | .byte$01, $00, $00, $02, $15, $00, $00, $02 |
| $840B | | .byte$16, $15, $00, $02, $15, $16, $15, $02 |
| $8413 | | .byte$15, $15, $16, $15, $00, $01, $00, $02 |
| $841B | | .byte$00, $01, $00, $15, $00, $01, $15, $15 |
| $8423 | | .byte$00, $15, $15, $16, $15, $15, $16, $15 |
| $842B | | .byte$00, $02, $01, $00, $19, $02, $01, $00 |
| $8433 | | .byte$17, $19, $01, $00, $18, $17, $19, $00 |
| $843B | | .byte$14, $18, $17, $19, $01, $00, $02, $01 |
| $8443 | | .byte$01, $00, $02, $14, $01, $00, $14, $18 |
| $844B | | .byte$01, $14, $18, $17, $14, $18, $17, $19 |
| $8453 | | .byte$02, $00, $00, $01, $14, $00, $00, $01 |
| $845B | | .byte$14, $14, $00, $01, $17, $14, $14, $01 |
| $8463 | | .byte$16, $17, $14, $14, $02, $00, $02, $00 |
| $846B | | .byte$02, $00, $02, $16, $02, $00, $16, $17 |
| $8473 | | .byte$02, $16, $17, $14, $16, $17, $14, $14 |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| ; Deactivates the raft/vehicle by clearing its active flag. |
| ; Called during level reset to ensure the raft starts inactive. |
| ; |
| ; Inputs: None |
| ; Outputs: None |
| ; Side Effects: Clears a_83A2 (raft active flag) |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| $847B | a9 00 | reset_raftlda#$00; A = 0 (inactive) ; x-ref: $4B13 |
| $847D | 8d a2 83 | staraft_active; clear raft active flag |
| $8480 | 60 | rts |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| ; Initializes animation state for tile type 15. Computes pixel coordinates |
| ; from the tile's column (X) and row (Y) positions, sets the initial |
| ; animation frame from a ping-pong sequence table, and enables the |
| ; animation flag so the per-frame updater (s_84C8) will animate it. |
| ; |
| ; Inputs: X = tile column, Y = tile row |
| ; Outputs: X = tile column (preserved), Y = tile row (preserved) |
| ; Side Effects: Writes animation state vars at $83A2-$83AA |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| $8481 | 86 1e | init_tile15_animstxzp_temp_x; save tile column ; x-ref: $4FE1 |
| $8483 | 84 1f | styzp_temp_y; save tile row |
| $8485 | a9 ff | lda#$ff; $FF = animation enabled |
| $8487 | 8d a2 83 | staraft_active; $FF = enable raft animation |
| $848A | a9 00 | lda#$00; clear hi-byte for Y*8 calc |
| $848C | 85 1d | stazp_ptr_map_hi |
| $848E | a5 1f | ldazp_temp_y; A = tile row |
| $8490 | 8d a6 83 | staraft_tile_row; Store tile row for screen addr calc |
| $8493 | 0a | asla; row * 2 |
| $8494 | 0a | asla; row * 4 |
| $8495 | 0a | asla; row * 8 |
| $8496 | 26 1d | rolzp_ptr_map_hi; capture carry into hi-byte |
| $8498 | 18 | clc |
| $8499 | 69 08 | adc#$08; row*8 + 8 = pixel Y offset |
| $849B | 8d a3 83 | staraft_pixel_y_lo; Pixel Y lo = row*8 + 8 |
| $849E | a5 1d | ldazp_ptr_map_hi |
| $84A0 | 69 00 | adc#$00 |
| $84A2 | 8d a4 83 | staraft_pixel_y_hi; Pixel Y hi (carry from lo) |
| $84A5 | a5 1e | ldazp_temp_x; A = tile column |
| $84A7 | 8d a7 83 | staraft_tile_col; Store column for screen addr calc |
| $84AA | 0a | asla; col * 2 |
| $84AB | 0a | asla; col * 4 |
| $84AC | 0a | asla; col * 8 |
| $84AD | 18 | clc |
| $84AE | 69 14 | adc#$14; col*8 + $14 = pixel X coord |
| $84B0 | 8d a5 83 | staraft_pixel_x; Pixel X = col*8 + $14 |
| $84B3 | a2 02 | ldx#$02; start at frame index 2 |
| $84B5 | 8e a9 83 | stxraft_anim_seq_idx; Start at sequence index 2 |
| $84B8 | bd ab 83 | ldaraft_anim_bounce_tbl,x; Load initial frame from bounce table |
| $84BB | 8d a8 83 | staraft_anim_frame; Set initial animation frame |
| $84BE | a9 00 | lda#$00; reset animation tick counter |
| $84C0 | 8d aa 83 | staraft_anim_tick; Reset tick counter |
| $84C3 | a6 1e | ldxzp_temp_x; restore tile column |
| $84C5 | a4 1f | ldyzp_temp_y; restore tile row |
| $84C7 | 60 | rts |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| ; Advances the raft's animation frame at a fixed rate. Every 8 ticks, |
| ; the sequence index advances through an 8-entry bounce table to select |
| ; the next animation frame, then tail-calls j_8528 to redraw the raft tiles. |
| ; If the raft is inactive (raft_active == 0), returns immediately. |
| ; |
| ; Inputs: raft_active, raft_anim_tick, raft_anim_seq_idx, raft_anim_bounce_tbl |
| ; Outputs: raft_anim_tick, raft_anim_seq_idx, raft_anim_frame |
| ; Side Effects: Redraws raft tiles on screen via j_8528 |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| update_raft_animation |
| $84C8 | ad a2 83 | ldaraft_active; Skip if raft is inactive ; x-ref: $61E6, $629B |
| $84CB | d0 01 | bneb_84CE; Active: continue to animation update |
| $84CD | 60 | rts; Raft inactive: bail out |
| $84CE | ee aa 83 | b_84CEincraft_anim_tick; Increment animation tick ; x-ref: $84CB |
| $84D1 | ad aa 83 | ldaraft_anim_tick |
| $84D4 | c9 08 | cmp#$08; Every 8 ticks, advance frame |
| $84D6 | d0 1b | bner_84F3; Not yet: return without frame change |
| $84D8 | a9 00 | lda#$00; Reset tick counter to 0 |
| $84DA | 8d aa 83 | staraft_anim_tick |
| $84DD | ae a9 83 | ldxraft_anim_seq_idx; Advance to next sequence index |
| $84E0 | e8 | inx |
| $84E1 | e0 08 | cpx#$08; Wrap sequence index at 8 entries |
| $84E3 | d0 02 | bneb_84E7 |
| $84E5 | a2 00 | ldx#$00; Wrap to first entry |
| $84E7 | 8e a9 83 | b_84E7stxraft_anim_seq_idx; Wrap index back to 0 ; x-ref: $84E3 |
| $84EA | bd ab 83 | ldaraft_anim_bounce_tbl,x; Look up frame from bounce pattern |
| $84ED | 8d a8 83 | staraft_anim_frame; Update current animation frame |
| $84F0 | 4c 28 85 | jmpj_8528; Tail-call: redraw raft tiles on screen |
| $84F3 | 60 | r_84F3rts; x-ref: $84D6 |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| ; Draws the raft (tile 15) onto screen RAM and color RAM using the current |
| ; animation frame. First clears the raft's 4x6 tile area in color RAM to |
| ; red ($02), then copies the current animation frame's tile data from the |
| ; raft tile table ($83B3+) to screen RAM, and finally copies corresponding |
| ; attribute data to a secondary screen region. |
| ; |
| ; Inputs: raft_active, raft_tile_col, raft_tile_row, raft_anim_frame |
| ; Outputs: None (screen updated in place) |
| ; Side Effects: Writes 4x6 tile region to screen RAM and color RAM |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| $84F4 | ad a2 83 | draw_raft_tilesldaraft_active; skip if raft not active ; x-ref: $4CC5 |
| $84F7 | d0 01 | bneb_84FA |
| $84F9 | 60 | rts |
| $84FA | ac a7 83 | b_84FAldyraft_tile_col; Y = column index for screen row table ; x-ref: $84F7 |
| $84FD | b9 17 8c | ldarow_to_screen_lo,y; get screen row base addr lo-byte |
| $8500 | 18 | clc |
| $8501 | 6d a6 83 | adcraft_tile_row; add tile row offset |
| $8504 | 85 fb | stazp_ptr_src_lo |
| $8506 | b9 28 8c | ldarow_to_screen_hi,y |
| $8509 | 69 d4 | adc#$d4; offset to color RAM ($D400) |
| $850B | 85 fc | stazp_ptr_src_hi |
| $850D | a2 05 | ldx#$05; 6 rows to fill |
| $850F | a0 07 | b_850Fldy#$07; 8 columns per row ; x-ref: $8526 |
| $8511 | a9 02 | lda#VicIIColors.RED; color = red ($02) |
| $8513 | 91 fb | b_8513sta(zp_ptr_src_lo),y; fill color RAM cell ; x-ref: $8516 |
| $8515 | 88 | dey |
| $8516 | 10 fb | bplb_8513 |
| $8518 | a5 fb | ldazp_ptr_src_lo |
| $851A | 18 | clc |
| $851B | 69 28 | adc#$28; advance to next screen row (+40 cols) |
| $851D | 85 fb | stazp_ptr_src_lo |
| $851F | a5 fc | ldazp_ptr_src_hi |
| $8521 | 69 00 | adc#$00 |
| $8523 | 85 fc | stazp_ptr_src_hi |
| $8525 | ca | dex |
| $8526 | d0 e7 | bneb_850F |
| $8528 | ac a7 83 | j_8528ldyraft_tile_col; --- part 2: draw raft tiles to screen --- ; x-ref: $84F0, $85C5 |
| $852B | b9 17 8c | ldarow_to_screen_lo,y |
| $852E | 18 | clc |
| $852F | 6d a6 83 | adcraft_tile_row; add tile row offset to screen base |
| $8532 | 85 fb | stazp_ptr_src_lo |
| $8534 | b9 28 8c | ldarow_to_screen_hi,y |
| $8537 | 69 00 | adc#$00 |
| $8539 | 85 fc | stazp_ptr_src_hi |
| $853B | ad a8 83 | ldaraft_anim_frame; get current animation frame |
| $853E | 0a | asla; frame * 4 (4 bytes per tile row) |
| $853F | 0a | asla |
| $8540 | 18 | clc |
| $8541 | 69 b3 | adc#$b3; lo-byte of raft tile data ($83B3) |
| $8543 | 85 fd | stazp_ptr_dst_lo |
| $8545 | a9 00 | lda#$00 |
| $8547 | 69 83 | adc#$83; hi-byte of raft tile data ($83xx) |
| $8549 | 85 fe | stazp_ptr_dst_hi |
| $854B | a2 05 | ldx#$05; 6 rows of tile data |
| $854D | a0 03 | b_854Dldy#$03; 4 columns per tile row ; x-ref: $8571 |
| $854F | b1 fd | b_854Flda(zp_ptr_dst_lo),y; read tile data byte ; x-ref: $8554 |
| $8551 | 91 fb | sta(zp_ptr_src_lo),y; write to screen RAM |
| $8553 | 88 | dey |
| $8554 | 10 f9 | bplb_854F |
| $8556 | a5 fb | ldazp_ptr_src_lo |
| $8558 | 18 | clc |
| $8559 | 69 28 | adc#$28; next screen row (+40) |
| $855B | 85 fb | stazp_ptr_src_lo |
| $855D | a5 fc | ldazp_ptr_src_hi |
| $855F | 69 00 | adc#$00 |
| $8561 | 85 fc | stazp_ptr_src_hi |
| $8563 | a5 fd | ldazp_ptr_dst_lo |
| $8565 | 18 | clc |
| $8566 | 69 28 | adc#$28; next tile data row (+40) |
| $8568 | 85 fd | stazp_ptr_dst_lo |
| $856A | a5 fe | ldazp_ptr_dst_hi |
| $856C | 69 00 | adc#$00 |
| $856E | 85 fe | stazp_ptr_dst_hi |
| $8570 | ca | dex |
| $8571 | d0 da | bneb_854D |
| $8573 | a5 fb | ldazp_ptr_src_lo; --- part 3: draw to secondary screen area --- |
| $8575 | 38 | sec |
| $8576 | e9 c4 | sbc#$c4; rewind src ptr by $C4 (back 5 rows-4) |
| $8578 | 85 fb | stazp_ptr_src_lo |
| $857A | a5 fc | ldazp_ptr_src_hi |
| $857C | e9 00 | sbc#$00 |
| $857E | 85 fc | stazp_ptr_src_hi |
| $8580 | a5 fd | ldazp_ptr_dst_lo |
| $8582 | 38 | sec |
| $8583 | e9 b4 | sbc#$b4; rewind dst ptr by $B4 (back 4 rows+20) |
| $8585 | 85 fd | stazp_ptr_dst_lo |
| $8587 | a5 fe | ldazp_ptr_dst_hi |
| $8589 | e9 00 | sbc#$00 |
| $858B | 85 fe | stazp_ptr_dst_hi |
| $858D | a2 05 | ldx#$05; 6 rows again |
| $858F | a0 03 | b_858Fldy#$03; 4 columns per row ; x-ref: $85B3 |
| $8591 | b1 fd | b_8591lda(zp_ptr_dst_lo),y; copy from secondary tile data ; x-ref: $8596 |
| $8593 | 91 fb | sta(zp_ptr_src_lo),y; write to secondary screen area |
| $8595 | 88 | dey |
| $8596 | 10 f9 | bplb_8591 |
| $8598 | a5 fb | ldazp_ptr_src_lo |
| $859A | 18 | clc |
| $859B | 69 28 | adc#$28 |
| $859D | 85 fb | stazp_ptr_src_lo |
| $859F | a5 fc | ldazp_ptr_src_hi |
| $85A1 | 69 00 | adc#$00 |
| $85A3 | 85 fc | stazp_ptr_src_hi |
| $85A5 | a5 fd | ldazp_ptr_dst_lo |
| $85A7 | 18 | clc |
| $85A8 | 69 28 | adc#$28 |
| $85AA | 85 fd | stazp_ptr_dst_lo |
| $85AC | a5 fe | ldazp_ptr_dst_hi |
| $85AE | 69 00 | adc#$00 |
| $85B0 | 85 fe | stazp_ptr_dst_hi |
| $85B2 | ca | dex |
| $85B3 | d0 da | bneb_858F |
| $85B5 | 60 | rts |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| ; Deactivates the raft entity and redraws its screen area to remove it visually. |
| ; Checks `raft_active`; if already inactive, returns immediately. Otherwise, |
| ; clears the active flag and animation frame, then calls the raft tile redraw |
| ; routine to restore the background tiles where the raft was displayed. |
| ; Called during hero death/respawn to clean up the raft state. |
| ; |
| ; Inputs: None (reads raft_active global) |
| ; Outputs: None |
| ; Side Effects: Clears raft_active and raft_anim_frame; redraws raft screen area |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| $85B6 | ad a2 83 | deactivate_raftldaraft_active; check if raft is currently active ; x-ref: $7B65 |
| $85B9 | f0 0d | beqr_85C8; not active → nothing to do |
| $85BB | a9 00 | lda#$00 |
| $85BD | 8d a2 83 | staraft_active; deactivate the raft |
| $85C0 | a9 00 | lda#$00 |
| $85C2 | 8d a8 83 | staraft_anim_frame; reset animation to frame 0 |
| $85C5 | 4c 28 85 | jmpj_8528; redraw raft area to remove it from screen |
| $85C8 | 60 | r_85C8rts; x-ref: $85B9 |
| ; Dynamic tile ID / active flag (0=inactive). 3-byte array indexed by dynamic_tile_count. |
| $85C9 | | dtile_id.byte$00, $00, $00; x-ref: $6FA9, $787C, $860C, $8652, $876E |
| ; Dynamic tile type variant (0=normal 2x5 tile, nonzero=alternate rendering). 3-byte array. |
| $85CC | | dtile_type.byte$00, $00, $00; x-ref: $85F3, $8677, $8863 |
| ; Dynamic tile pixel Y position, low byte. Computed as (column * 8) + 8. 3-byte array. |
| $85CF | | dtile_y_lo.byte$00, $00, $00; x-ref: $6FB9, $701E, $789B, $78AE, $8622 |
| ; Dynamic tile pixel Y position, high byte. 3-byte array. |
| $85D2 | | dtile_y_hi.byte$00, $00, $00; x-ref: $6FC1, $7024, $78A2, $78B6, $8629 |
| ; Dynamic tile pixel X position. Computed as (row * 8) + $14. 3-byte array. |
| $85D5 | | dtile_x.byte$00, $00, $00; x-ref: $6FAE, $702A, $7885, $8637 |
| ; Dynamic tile screen column offset. Used as Y-index for indirect screen writes. 3-byte array. |
| $85D8 | | dtile_scr_col.byte$00, $00, $00; x-ref: $8617, $8673, $8795, $885F |
| ; Dynamic tile screen row index. Indexes into row_to_screen_lo/hi tables. 3-byte array. |
| $85DB | | dtile_scr_row.byte$00, $00, $00; x-ref: $862E, $865E, $8773, $8851 |
| ; Dynamic tile hit countdown timer, low byte. Init=$12. When timer reaches 0, tile is destroyed. 3-byte array. |
| $85DE | | dtile_timer_lo.byte$00, $00, $00; x-ref: $863C, $881E, $8826, $8829, $8841 |
| ; Dynamic tile hit countdown timer, high byte. Init=$02. Forms 16-bit timer with dtile_timer_lo ($0212=530 frames). 3-byte array. |
| $85E1 | | dtile_timer_hi.byte$00, $00, $00; x-ref: $8641, $8823, $882C, $883A |
| $85E4 | | dynamic_tile_count.byte$00; x-ref: $6FA2, $7875, $85E8, $85F0, $8603, ... |
| ; Dynamic tile color attribute for color RAM. $0F=white (normal), $00=invisible/cleared. |
| $85E5 | | dtile_color.byte$00; x-ref: $4E2A, $4E65, $8680, $868A, $8698, ... |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| ; Resets the dynamic tile count to zero, clearing all tile 5/tile 6 objects. |
| ; Called during room initialization to prepare the dynamic tile subsystem |
| ; for the new room. The count (a_85E4) is used as an index into parallel |
| ; arrays (f_85C9–f_85E1) that track active dynamic tile state. |
| ; |
| ; Inputs: None |
| ; Outputs: None |
| ; Side Effects: Clears dynamic_tile_count (a_85E4) to 0 |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| $85E6 | a9 00 | reset_dynamic_tileslda#$00; clear accumulator ; x-ref: $4B16 |
| $85E8 | 8d e4 85 | stadynamic_tile_count; reset dynamic tile count to 0 |
| $85EB | 60 | rts |
| $85EC | 86 1e | j_85ECstxzp_temp_x; x-ref: $4FBC, $4FC5 |
| $85EE | 84 1f | styzp_temp_y |
| $85F0 | ae e4 85 | ldxdynamic_tile_count |
| $85F3 | 9d cc 85 | stadtile_type,x |
| $85F6 | ac 9e 3f | ldycurrent_room_index |
| $85F9 | b9 09 49 | ldalevel_map_ptr_lo,y |
| $85FC | 85 1c | stazp_ptr_map_lo |
| $85FE | b9 69 49 | ldalevel_map_ptr_hi,y |
| $8601 | 85 1d | stazp_ptr_map_hi |
| $8603 | ad e4 85 | ldadynamic_tile_count |
| $8606 | 18 | clc |
| $8607 | 69 0f | adc#$0f |
| $8609 | a8 | tay |
| $860A | b1 1c | lda(zp_ptr_map_lo),y |
| $860C | 9d c9 85 | stadtile_id,x; Load tile ID from map data |
| $860F | f0 33 | beqb_8644 |
| $8611 | a9 00 | lda#$00 |
| $8613 | 85 1d | stazp_ptr_map_hi |
| $8615 | a5 1f | ldazp_temp_y |
| $8617 | 9d d8 85 | stadtile_scr_col,x; Store screen column |
| $861A | 0a | asla |
| $861B | 0a | asla |
| $861C | 0a | asla |
| $861D | 26 1d | rolzp_ptr_map_hi |
| $861F | 18 | clc |
| $8620 | 69 08 | adc#$08 |
| $8622 | 9d cf 85 | stadtile_y_lo,x; Store pixel Y lo (col*8+8) |
| $8625 | a5 1d | ldazp_ptr_map_hi |
| $8627 | 69 00 | adc#$00 |
| $8629 | 9d d2 85 | stadtile_y_hi,x; Store pixel Y hi |
| $862C | a5 1e | ldazp_temp_x |
| $862E | 9d db 85 | stadtile_scr_row,x; Store screen row index |
| $8631 | 0a | asla |
| $8632 | 0a | asla |
| $8633 | 0a | asla |
| $8634 | 18 | clc |
| $8635 | 69 14 | adc#$14 |
| $8637 | 9d d5 85 | stadtile_x,x; Store pixel X (row*8+$14) |
| $863A | a9 12 | lda#$12 |
| $863C | 9d de 85 | stadtile_timer_lo,x; Init timer lo = $12 |
| $863F | a9 02 | lda#$02 |
| $8641 | 9d e1 85 | stadtile_timer_hi,x; Init timer hi = $02 |
| $8644 | ee e4 85 | b_8644incdynamic_tile_count; x-ref: $860F |
| $8647 | a6 1e | ldxzp_temp_x |
| $8649 | a4 1f | ldyzp_temp_y |
| $864B | 60 | rts |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| ; Iterates over all dynamic tiles (from `dynamic_tile_count` down to 0). |
| ; For each active tile (where `dtile_id` != 0), it calls `draw_dynamic_tile_2x5` |
| ; to draw it onto the screen. |
| ; |
| ; Inputs: `dynamic_tile_count` (global) |
| ; Outputs: None |
| ; Side Effects: Modifies screen and color RAM by drawing the active dynamic tiles. |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| draw_all_dynamic_tiles |
| $864C | ae e4 85 | ldxdynamic_tile_count; Load total number of dynamic tiles ; x-ref: $4CC8 |
| $864F | f0 0c | beqr_865D; If zero, exit |
| $8651 | ca | dex; Adjust count to 0-based index for X |
| $8652 | bd c9 85 | b_8652ldadtile_id,x; Check if tile is active (id != 0) ; x-ref: $865B |
| $8655 | f0 03 | beqb_865A; If not active, skip drawing |
| $8657 | 20 5e 86 | jsrdraw_dynamic_tile_2x5 |
| $865A | ca | b_865Adex; Decrement index ; x-ref: $8655 |
| $865B | 10 f5 | bplb_8652; Loop until all tiles processed (X < 0) |
| $865D | 60 | r_865Drts; x-ref: $864F |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| ; Draws a 2x5 meta-tile on screen for a dynamic tile. Uses `dtile_type` to select |
| ; the character set and color (either dynamic `dtile_color` or fixed red). |
| ; |
| ; Inputs: X = dynamic tile index |
| ; Outputs: None |
| ; Side Effects: Modifies screen and color RAM (10 bytes each) |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| draw_dynamic_tile_2x5 |
| $865E | bd db 85 | ldadtile_scr_row,x; Get screen row for tile ; x-ref: $8657 |
| $8661 | a8 | tay |
| $8662 | b9 17 8c | ldarow_to_screen_lo,y |
| $8665 | 85 fb | stazp_ptr_src_lo; zp_ptr_src = screen RAM address |
| $8667 | 85 fd | stazp_ptr_dst_lo |
| $8669 | b9 28 8c | ldarow_to_screen_hi,y |
| $866C | 85 fc | stazp_ptr_src_hi |
| $866E | 18 | clc; Add $D4 to high byte for Color RAM |
| $866F | 69 d4 | adc#$d4 |
| $8671 | 85 fe | stazp_ptr_dst_hi |
| $8673 | bd d8 85 | ldadtile_scr_col,x; Get screen col for tile |
| $8676 | a8 | tay |
| $8677 | bd cc 85 | ldadtile_type,x |
| $867A | d0 74 | bnedraw_dtile_type_1; If type != 0, draw alternate tile |
| $867C | a9 34 | lda#$34; Row 1 |
| $867E | 91 fb | sta(zp_ptr_src_lo),y |
| $8680 | ad e5 85 | ldadtile_color |
| $8683 | 91 fd | sta(zp_ptr_dst_lo),y |
| $8685 | c8 | iny |
| $8686 | a9 35 | lda#$35 |
| $8688 | 91 fb | sta(zp_ptr_src_lo),y |
| $868A | ad e5 85 | ldadtile_color |
| $868D | 91 fd | sta(zp_ptr_dst_lo),y |
| $868F | 98 | tya |
| $8690 | 18 | clc |
| $8691 | 69 27 | adc#$27 |
| $8693 | a8 | tay |
| $8694 | a9 36 | lda#$36 |
| $8696 | 91 fb | sta(zp_ptr_src_lo),y |
| $8698 | ad e5 85 | ldadtile_color |
| $869B | 91 fd | sta(zp_ptr_dst_lo),y |
| $869D | c8 | iny |
| $869E | a9 37 | lda#$37 |
| $86A0 | 91 fb | sta(zp_ptr_src_lo),y |
| $86A2 | ad e5 85 | ldadtile_color |
| $86A5 | 91 fd | sta(zp_ptr_dst_lo),y |
| $86A7 | 98 | tya |
| $86A8 | 18 | clc |
| $86A9 | 69 27 | adc#$27 |
| $86AB | a8 | tay |
| $86AC | a9 34 | lda#$34 |
| $86AE | 91 fb | sta(zp_ptr_src_lo),y |
| $86B0 | ad e5 85 | ldadtile_color |
| $86B3 | 91 fd | sta(zp_ptr_dst_lo),y |
| $86B5 | c8 | iny |
| $86B6 | a9 35 | lda#$35 |
| $86B8 | 91 fb | sta(zp_ptr_src_lo),y |
| $86BA | ad e5 85 | ldadtile_color |
| $86BD | 91 fd | sta(zp_ptr_dst_lo),y |
| $86BF | 98 | tya |
| $86C0 | 18 | clc |
| $86C1 | 69 27 | adc#$27 |
| $86C3 | a8 | tay |
| $86C4 | a9 36 | lda#$36 |
| $86C6 | 91 fb | sta(zp_ptr_src_lo),y |
| $86C8 | ad e5 85 | ldadtile_color |
| $86CB | 91 fd | sta(zp_ptr_dst_lo),y |
| $86CD | c8 | iny |
| $86CE | a9 37 | lda#$37 |
| $86D0 | 91 fb | sta(zp_ptr_src_lo),y |
| $86D2 | ad e5 85 | ldadtile_color |
| $86D5 | 91 fd | sta(zp_ptr_dst_lo),y |
| $86D7 | 98 | tya |
| $86D8 | 18 | clc |
| $86D9 | 69 27 | adc#$27 |
| $86DB | a8 | tay |
| $86DC | a9 34 | lda#$34 |
| $86DE | 91 fb | sta(zp_ptr_src_lo),y |
| $86E0 | ad e5 85 | ldadtile_color |
| $86E3 | 91 fd | sta(zp_ptr_dst_lo),y |
| $86E5 | c8 | iny |
| $86E6 | a9 35 | lda#$35 |
| $86E8 | 91 fb | sta(zp_ptr_src_lo),y |
| $86EA | ad e5 85 | ldadtile_color |
| $86ED | 91 fd | sta(zp_ptr_dst_lo),y |
| $86EF | 60 | rts |
| $86F0 | a9 0d | draw_dtile_type_1lda#$0d; Row 1, alternate tile ; x-ref: $867A |
| $86F2 | 91 fb | sta(zp_ptr_src_lo),y |
| $86F4 | a9 02 | lda#$02 |
| $86F6 | 91 fd | sta(zp_ptr_dst_lo),y |
| $86F8 | c8 | iny |
| $86F9 | a9 0e | lda#$0e |
| $86FB | 91 fb | sta(zp_ptr_src_lo),y |
| $86FD | a9 02 | lda#$02 |
| $86FF | 91 fd | sta(zp_ptr_dst_lo),y |
| $8701 | 98 | tya |
| $8702 | 18 | clc |
| $8703 | 69 27 | adc#$27 |
| $8705 | a8 | tay |
| $8706 | a9 0f | lda#$0f |
| $8708 | 91 fb | sta(zp_ptr_src_lo),y |
| $870A | a9 02 | lda#$02 |
| $870C | 91 fd | sta(zp_ptr_dst_lo),y |
| $870E | c8 | iny |
| $870F | a9 10 | lda#$10 |
| $8711 | 91 fb | sta(zp_ptr_src_lo),y |
| $8713 | a9 02 | lda#$02 |
| $8715 | 91 fd | sta(zp_ptr_dst_lo),y |
| $8717 | 98 | tya |
| $8718 | 18 | clc |
| $8719 | 69 27 | adc#$27 |
| $871B | a8 | tay |
| $871C | a9 0d | lda#$0d |
| $871E | 91 fb | sta(zp_ptr_src_lo),y |
| $8720 | a9 02 | lda#$02 |
| $8722 | 91 fd | sta(zp_ptr_dst_lo),y |
| $8724 | c8 | iny |
| $8725 | a9 0e | lda#$0e |
| $8727 | 91 fb | sta(zp_ptr_src_lo),y |
| $8729 | a9 02 | lda#$02 |
| $872B | 91 fd | sta(zp_ptr_dst_lo),y |
| $872D | 98 | tya |
| $872E | 18 | clc |
| $872F | 69 27 | adc#$27 |
| $8731 | a8 | tay |
| $8732 | a9 0f | lda#$0f |
| $8734 | 91 fb | sta(zp_ptr_src_lo),y |
| $8736 | a9 02 | lda#$02 |
| $8738 | 91 fd | sta(zp_ptr_dst_lo),y |
| $873A | c8 | iny |
| $873B | a9 10 | lda#$10 |
| $873D | 91 fb | sta(zp_ptr_src_lo),y |
| $873F | a9 02 | lda#$02 |
| $8741 | 91 fd | sta(zp_ptr_dst_lo),y |
| $8743 | 98 | tya |
| $8744 | 18 | clc |
| $8745 | 69 27 | adc#$27 |
| $8747 | a8 | tay |
| $8748 | a9 0d | lda#$0d |
| $874A | 91 fb | sta(zp_ptr_src_lo),y |
| $874C | a9 02 | lda#$02 |
| $874E | 91 fd | sta(zp_ptr_dst_lo),y |
| $8750 | c8 | iny |
| $8751 | a9 0e | lda#$0e |
| $8753 | 91 fb | sta(zp_ptr_src_lo),y |
| $8755 | a9 02 | lda#$02 |
| $8757 | 91 fd | sta(zp_ptr_dst_lo),y |
| $8759 | 60 | rts |
| $875A | ac 9e 3f | j_875Aldycurrent_room_index; x-ref: $6FCD, $6FD8, $8831 |
| $875D | b9 09 49 | ldalevel_map_ptr_lo,y |
| $8760 | 85 1c | stazp_ptr_map_lo |
| $8762 | b9 69 49 | ldalevel_map_ptr_hi,y |
| $8765 | 85 1d | stazp_ptr_map_hi |
| $8767 | 8a | txa |
| $8768 | 18 | clc |
| $8769 | 69 0f | adc#$0f |
| $876B | a8 | tay |
| $876C | a9 00 | lda#$00 |
| $876E | 9d c9 85 | stadtile_id,x; Tile active? (update loop) |
| $8771 | 91 1c | sta(zp_ptr_map_lo),y |
| $8773 | bd db 85 | ldadtile_scr_row,x; Get screen row for rendering |
| $8776 | a8 | tay |
| $8777 | b9 17 8c | ldarow_to_screen_lo,y |
| $877A | 85 fb | stazp_ptr_src_lo |
| $877C | 85 fd | stazp_ptr_dst_lo |
| $877E | b9 28 8c | ldarow_to_screen_hi,y |
| $8781 | 85 fc | stazp_ptr_src_hi |
| $8783 | 18 | clc |
| $8784 | 69 d4 | adc#$d4 |
| $8786 | 85 fe | stazp_ptr_dst_hi |
| $8788 | a5 fb | ldazp_ptr_src_lo |
| $878A | 18 | clc |
| $878B | 69 68 | adc#$68 |
| $878D | 85 02 | stazp_work0 |
| $878F | a5 fc | ldazp_ptr_src_hi |
| $8791 | 69 df | adc#$df |
| $8793 | 85 03 | stazp_work1 |
| $8795 | bd d8 85 | ldadtile_scr_col,x; Get screen column for rendering |
| $8798 | a8 | tay |
| $8799 | b1 02 | lda(zp_work0),y |
| $879B | 91 fb | sta(zp_ptr_src_lo),y |
| $879D | ad a3 3f | ldaactive_bg_color |
| $87A0 | 91 fd | sta(zp_ptr_dst_lo),y |
| $87A2 | c8 | iny |
| $87A3 | b1 02 | lda(zp_work0),y |
| $87A5 | 91 fb | sta(zp_ptr_src_lo),y |
| $87A7 | ad a3 3f | ldaactive_bg_color |
| $87AA | 91 fd | sta(zp_ptr_dst_lo),y |
| $87AC | 98 | tya |
| $87AD | 18 | clc |
| $87AE | 69 27 | adc#$27 |
| $87B0 | a8 | tay |
| $87B1 | b1 02 | lda(zp_work0),y |
| $87B3 | 91 fb | sta(zp_ptr_src_lo),y |
| $87B5 | ad a3 3f | ldaactive_bg_color |
| $87B8 | 91 fd | sta(zp_ptr_dst_lo),y |
| $87BA | c8 | iny |
| $87BB | b1 02 | lda(zp_work0),y |
| $87BD | 91 fb | sta(zp_ptr_src_lo),y |
| $87BF | ad a3 3f | ldaactive_bg_color |
| $87C2 | 91 fd | sta(zp_ptr_dst_lo),y |
| $87C4 | 98 | tya |
| $87C5 | 18 | clc |
| $87C6 | 69 27 | adc#$27 |
| $87C8 | a8 | tay |
| $87C9 | b1 02 | lda(zp_work0),y |
| $87CB | 91 fb | sta(zp_ptr_src_lo),y |
| $87CD | ad a3 3f | ldaactive_bg_color |
| $87D0 | 91 fd | sta(zp_ptr_dst_lo),y |
| $87D2 | c8 | iny |
| $87D3 | b1 02 | lda(zp_work0),y |
| $87D5 | 91 fb | sta(zp_ptr_src_lo),y |
| $87D7 | ad a3 3f | ldaactive_bg_color |
| $87DA | 91 fd | sta(zp_ptr_dst_lo),y |
| $87DC | 98 | tya |
| $87DD | 18 | clc |
| $87DE | 69 27 | adc#$27 |
| $87E0 | a8 | tay |
| $87E1 | b1 02 | lda(zp_work0),y |
| $87E3 | 91 fb | sta(zp_ptr_src_lo),y |
| $87E5 | ad a3 3f | ldaactive_bg_color |
| $87E8 | 91 fd | sta(zp_ptr_dst_lo),y |
| $87EA | c8 | iny |
| $87EB | b1 02 | lda(zp_work0),y |
| $87ED | 91 fb | sta(zp_ptr_src_lo),y |
| $87EF | ad a3 3f | ldaactive_bg_color |
| $87F2 | 91 fd | sta(zp_ptr_dst_lo),y |
| $87F4 | 98 | tya |
| $87F5 | 18 | clc |
| $87F6 | 69 27 | adc#$27 |
| $87F8 | a8 | tay |
| $87F9 | b1 02 | lda(zp_work0),y |
| $87FB | 91 fb | sta(zp_ptr_src_lo),y |
| $87FD | ad a3 3f | ldaactive_bg_color |
| $8800 | 91 fd | sta(zp_ptr_dst_lo),y |
| $8802 | c8 | iny |
| $8803 | b1 02 | lda(zp_work0),y |
| $8805 | 91 fb | sta(zp_ptr_src_lo),y |
| $8807 | ad a3 3f | ldaactive_bg_color |
| $880A | 91 fd | sta(zp_ptr_dst_lo),y |
| $880C | 20 0f 70 | jsrstart_explosion_from_hit |
| $880F | a9 75 | lda#$75 |
| $8811 | 85 fb | stazp_ptr_src_lo |
| $8813 | a9 00 | lda#$00 |
| $8815 | 85 fc | stazp_ptr_src_hi |
| $8817 | a9 00 | lda#$00 |
| $8819 | 85 fd | stazp_ptr_dst_lo |
| $881B | 4c d8 51 | jmpj_51D8 |
| $881E | bd de 85 | j_881Eldadtile_timer_lo,x; Check timer lo (hit countdown) ; x-ref: $78D4 |
| $8821 | d0 03 | bneb_8826 |
| $8823 | de e1 85 | decdtile_timer_hi,x |
| $8826 | de de 85 | b_8826decdtile_timer_lo,x; Decrement timer lo ; x-ref: $8821 |
| $8829 | bd de 85 | ldadtile_timer_lo,x |
| $882C | 1d e1 85 | oradtile_timer_hi,x; Timer expired? Destroy tile |
| $882F | d0 09 | bneb_883A |
| $8831 | 20 5a 87 | jsrj_875A |
| $8834 | a9 01 | lda#$01 |
| $8836 | 8d ec 88 | stasfx_hit_state |
| $8839 | 60 | rts |
| $883A | bd e1 85 | b_883Aldadtile_timer_hi,x; x-ref: $882F |
| $883D | c9 01 | cmp#$01 |
| $883F | d0 0f | bner_8850 |
| $8841 | bd de 85 | ldadtile_timer_lo,x |
| $8844 | c9 18 | cmp#$18 |
| $8846 | d0 08 | bner_8850 |
| $8848 | 20 51 88 | jsrdraw_dtile_anim_frame2 |
| $884B | a9 01 | lda#$01 |
| $884D | 8d cf 8b | stasfx_ch8_state |
| $8850 | 60 | r_8850rts; x-ref: $883F, $8846 |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| ; Draws the second animation frame for a dynamic tile onto the screen. |
| ; Unlike the initial draw, this routine only updates Screen RAM (characters) |
| ; and skips Color RAM updates to save cycles. |
| ; |
| ; Inputs: X = dynamic tile index |
| ; Outputs: None |
| ; Side Effects: Modifies screen RAM (10 bytes) |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| draw_dtile_anim_frame2 |
| $8851 | bd db 85 | ldadtile_scr_row,x; Get screen row for tile ; x-ref: $8848 |
| $8854 | a8 | tay |
| $8855 | b9 17 8c | ldarow_to_screen_lo,y |
| $8858 | 85 fb | stazp_ptr_src_lo; zp_ptr_src = screen RAM address |
| $885A | b9 28 8c | ldarow_to_screen_hi,y |
| $885D | 85 fc | stazp_ptr_src_hi |
| $885F | bd d8 85 | ldadtile_scr_col,x; Get screen col for tile |
| $8862 | a8 | tay |
| $8863 | bd cc 85 | ldadtile_type,x |
| $8866 | d0 42 | bnedraw_dtile_type_1_anim2; If type != 0, draw alternate tile frame 2 |
| $8868 | a9 38 | lda#$38; Row 1, characters $38/$39 |
| $886A | 91 fb | sta(zp_ptr_src_lo),y |
| $886C | c8 | iny |
| $886D | a9 39 | lda#$39 |
| $886F | 91 fb | sta(zp_ptr_src_lo),y |
| $8871 | 98 | tya |
| $8872 | 18 | clc |
| $8873 | 69 27 | adc#$27 |
| $8875 | a8 | tay |
| $8876 | a9 3a | lda#$3a |
| $8878 | 91 fb | sta(zp_ptr_src_lo),y |
| $887A | c8 | iny |
| $887B | a9 3b | lda#$3b |
| $887D | 91 fb | sta(zp_ptr_src_lo),y |
| $887F | 98 | tya |
| $8880 | 18 | clc |
| $8881 | 69 27 | adc#$27 |
| $8883 | a8 | tay |
| $8884 | a9 38 | lda#$38 |
| $8886 | 91 fb | sta(zp_ptr_src_lo),y |
| $8888 | c8 | iny |
| $8889 | a9 39 | lda#$39 |
| $888B | 91 fb | sta(zp_ptr_src_lo),y |
| $888D | 98 | tya |
| $888E | 18 | clc |
| $888F | 69 27 | adc#$27 |
| $8891 | a8 | tay |
| $8892 | a9 3a | lda#$3a |
| $8894 | 91 fb | sta(zp_ptr_src_lo),y |
| $8896 | c8 | iny |
| $8897 | a9 3b | lda#$3b |
| $8899 | 91 fb | sta(zp_ptr_src_lo),y |
| $889B | 98 | tya |
| $889C | 18 | clc |
| $889D | 69 27 | adc#$27 |
| $889F | a8 | tay |
| $88A0 | a9 38 | lda#$38 |
| $88A2 | 91 fb | sta(zp_ptr_src_lo),y |
| $88A4 | c8 | iny |
| $88A5 | a9 39 | lda#$39 |
| $88A7 | 91 fb | sta(zp_ptr_src_lo),y |
| $88A9 | 60 | rts |
| draw_dtile_type_1_anim2 |
| $88AA | a9 11 | lda#$11; Row 1, alternate tile frame 2 ; x-ref: $8866 |
| $88AC | 91 fb | sta(zp_ptr_src_lo),y |
| $88AE | c8 | iny |
| $88AF | a9 12 | lda#$12 |
| $88B1 | 91 fb | sta(zp_ptr_src_lo),y |
| $88B3 | 98 | tya |
| $88B4 | 18 | clc |
| $88B5 | 69 27 | adc#$27 |
| $88B7 | a8 | tay |
| $88B8 | a9 13 | lda#$13 |
| $88BA | 91 fb | sta(zp_ptr_src_lo),y |
| $88BC | c8 | iny |
| $88BD | a9 12 | lda#$12 |
| $88BF | 91 fb | sta(zp_ptr_src_lo),y |
| $88C1 | 98 | tya |
| $88C2 | 18 | clc |
| $88C3 | 69 27 | adc#$27 |
| $88C5 | a8 | tay |
| $88C6 | a9 11 | lda#$11 |
| $88C8 | 91 fb | sta(zp_ptr_src_lo),y |
| $88CA | c8 | iny |
| $88CB | a9 12 | lda#$12 |
| $88CD | 91 fb | sta(zp_ptr_src_lo),y |
| $88CF | 98 | tya |
| $88D0 | 18 | clc |
| $88D1 | 69 27 | adc#$27 |
| $88D3 | a8 | tay |
| $88D4 | a9 13 | lda#$13 |
| $88D6 | 91 fb | sta(zp_ptr_src_lo),y |
| $88D8 | c8 | iny |
| $88D9 | a9 12 | lda#$12 |
| $88DB | 91 fb | sta(zp_ptr_src_lo),y |
| $88DD | 98 | tya |
| $88DE | 18 | clc |
| $88DF | 69 27 | adc#$27 |
| $88E1 | a8 | tay |
| $88E2 | a9 11 | lda#$11 |
| $88E4 | 91 fb | sta(zp_ptr_src_lo),y |
| $88E6 | c8 | iny |
| $88E7 | a9 12 | lda#$12 |
| $88E9 | 91 fb | sta(zp_ptr_src_lo),y |
| $88EB | 60 | rts |
| $88EC | | sfx_hit_state.byte$00; x-ref: $1E57, $627F, $6F9E, $8836, $88EE, ... |
| $88ED | | sfx_hit_delay.byte$00; x-ref: $88FA, $890C, $892E |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| ; Ticks the hit/destroy noise sound effect on SID Voice 3. |
| ; Uses a 3-state machine driven by sfx_hit_state: |
| ; State 0: Idle — returns immediately. |
| ; State 1: Init — sets delay counter to $FE, silences Voice 3, advances to state 2. |
| ; State 2: Delay — increments counter until it reaches 0, then triggers a noise |
| ; burst (freq=$0300, ADSR=$10/$F9, waveform=noise+gate) for 3 frames |
| ; before gating off and resetting to idle. |
| ; Triggered by entity destruction, explosion activation, and life bonus scoring. |
| ; |
| ; Inputs: sfx_hit_state ($88EC), sfx_hit_delay ($88ED) |
| ; Outputs: sfx_hit_state, sfx_hit_delay |
| ; Side Effects: Writes to SID Voice 3 registers ($D40E-$D414) |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| $88EE | ad ec 88 | tick_sfx_hitldasfx_hit_state; Load current state (0=idle, 1=init, 2=delay) ; x-ref: $1E3A |
| $88F1 | d0 01 | bneb_88F4; State 0 → nothing to do |
| $88F3 | 60 | rts |
| $88F4 | c9 01 | b_88F4cmp#$01; State 1? → initialize voice ; x-ref: $88F1 |
| $88F6 | d0 14 | bneb_890C |
| $88F8 | a9 fe | lda#$fe; $FE = -2, counts up to 0 (2-frame delay) |
| $88FA | 8d ed 88 | stasfx_hit_delay |
| $88FD | a9 00 | lda#$00; Silence Voice 3: clear waveform |
| $88FF | 8d 12 d4 | sta$d412; Voice 3: Control Register |
| $8902 | 8d 13 d4 | sta$d413; Zero attack/decay; Voice 3: Attack / Decay Cycle Control |
| $8905 | 8d 14 d4 | sta$d414; Zero sustain/release; Voice 3: Sustain / Release Cycle Control |
| $8908 | ee ec 88 | incsfx_hit_state; Advance to state 2 (delay phase) |
| $890B | 60 | rts |
| $890C | ee ed 88 | b_890Cincsfx_hit_delay; State 2: increment delay counter ; x-ref: $88F6 |
| $890F | 10 01 | bplb_8912; Counter < 0 → still waiting |
| $8911 | 60 | rts |
| $8912 | d0 1a | b_8912bneb_892E; Counter > 0 → check for gate-off ; x-ref: $890F |
| $8914 | a9 03 | lda#$03; Counter == 0: trigger noise burst |
| $8916 | 8d 0f d4 | sta$d40f; Freq hi=$03 → low-pitched noise; Voice 3: Frequency Control - High-Byte |
| $8919 | a9 00 | lda#$00; Freq lo=$00 |
| $891B | 8d 0e d4 | sta$d40e; Voice 3: Frequency Control - Low-Byte |
| $891E | a9 10 | lda#$10; Attack=1, Decay=0 (fast attack) |
| $8920 | 8d 13 d4 | sta$d413; Voice 3: Attack / Decay Cycle Control |
| $8923 | a9 f9 | lda#$f9; Sustain=$F, Release=$9 |
| $8925 | 8d 14 d4 | sta$d414; Voice 3: Sustain / Release Cycle Control |
| $8928 | a9 81 | lda#$81; $81 = noise waveform + gate on |
| $892A | 8d 12 d4 | sta$d412; Voice 3: Control Register |
| $892D | 60 | rts |
| $892E | ad ed 88 | b_892Eldasfx_hit_delay; Counter > 0: check if time to gate off ; x-ref: $8912 |
| $8931 | c9 03 | cmp#$03; Wait 3 frames after trigger |
| $8933 | d0 0a | bner_893F |
| $8935 | a9 80 | lda#$80; $80 = noise waveform, gate OFF |
| $8937 | 8d 12 d4 | sta$d412; Voice 3: Control Register |
| $893A | a9 00 | lda#$00; Reset to state 0 (idle) |
| $893C | 8d ec 88 | stasfx_hit_state |
| $893F | 60 | r_893Frts; x-ref: $8933 |
| $8940 | | sfx_explosion_state.byte$00; x-ref: $1E5A, $706B, $8942, $895C, $8984 |
| $8941 | | sfx_explosion_delay.byte$00; x-ref: $894E, $8960 |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| ; Ticks the explosion/blast noise sound effect on SID Voice 3. |
| ; Uses a 3-state machine driven by sfx_explosion_state: |
| ; State 0: Idle — returns immediately. |
| ; State 1: Init — sets delay counter to $FE, silences Voice 3, advances to state 2. |
| ; State 2: Delay — increments counter until it reaches 0, then triggers a noise |
| ; burst (freq=$3000, ADSR=$61/$10, waveform=noise+gate) and resets to idle. |
| ; Triggered by init_hero_explosion when the hero's dynamite detonates. |
| ; |
| ; Inputs: sfx_explosion_state ($8940), sfx_explosion_delay ($8941) |
| ; Outputs: sfx_explosion_state, sfx_explosion_delay |
| ; Side Effects: Writes to SID Voice 3 registers ($D40E-$D414) |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| $8942 | ad 40 89 | tick_sfx_explosionldasfx_explosion_state; Load current state (0=idle, 1=init, 2=delay) ; x-ref: $1E3D |
| $8945 | d0 01 | bneb_8948; State 0 → nothing to do |
| $8947 | 60 | rts |
| $8948 | c9 01 | b_8948cmp#$01; State 1? → initialize voice ; x-ref: $8945 |
| $894A | d0 14 | bneb_8960 |
| $894C | a9 fe | lda#$fe; $FE = -2, counts up to 0 (2-frame delay) |
| $894E | 8d 41 89 | stasfx_explosion_delay |
| $8951 | a9 00 | lda#$00 |
| $8953 | 8d 12 d4 | sta$d412; Clear waveform (silence Voice 3); Voice 3: Control Register |
| $8956 | 8d 13 d4 | sta$d413; Clear ADSR attack/decay; Voice 3: Attack / Decay Cycle Control |
| $8959 | 8d 14 d4 | sta$d414; Clear ADSR sustain/release; Voice 3: Sustain / Release Cycle Control |
| $895C | ee 40 89 | incsfx_explosion_state; Advance to state 2 (delay phase) |
| $895F | 60 | rts |
| $8960 | ee 41 89 | b_8960incsfx_explosion_delay; Increment delay counter ; x-ref: $894A |
| $8963 | 10 01 | bplb_8966; Counter >= 0? → ready to proceed |
| $8965 | 60 | rts; Counter still negative → keep waiting |
| $8966 | d0 1a | b_8966bneb_8982; Counter nonzero (overflow) → reset to idle ; x-ref: $8963 |
| $8968 | a9 30 | lda#$30; Freq hi = $30 → frequency $3000 |
| $896A | 8d 0f d4 | sta$d40f; Freq hi = $30 → frequency $3000; Voice 3: Frequency Control - High-Byte |
| $896D | a9 00 | lda#$00 |
| $896F | 8d 0e d4 | sta$d40e; Voice 3: Frequency Control - Low-Byte |
| $8972 | a9 61 | lda#$61; Attack=6, Decay=1 |
| $8974 | 8d 13 d4 | sta$d413; Voice 3: Attack / Decay Cycle Control |
| $8977 | a9 10 | lda#$10 |
| $8979 | 8d 14 d4 | sta$d414; Sustain=1, Release=0; Voice 3: Sustain / Release Cycle Control |
| $897C | a9 81 | lda#$81; $81 = Noise waveform + Gate on → trigger burst |
| $897E | 8d 12 d4 | sta$d412; Voice 3: Control Register |
| $8981 | 60 | rts |
| $8982 | a9 00 | b_8982lda#$00; Reset state to 0 (idle) — effect complete ; x-ref: $8966 |
| $8984 | 8d 40 89 | stasfx_explosion_state |
| $8987 | 60 | rts |
| $8988 | | sfx_fire_phase.byte$00; x-ref: $1E5D, $790E, $8992, $89AC, $89DF, ... |
| $8989 | | sfx_fire_timer.byte$00; x-ref: $899E, $89B0, $89D8, $89F1 |
| $898A | | sfx_fire_freq_table.byte$1b, $1c, $1e, $20, $22, $24, $26, $28; x-ref: $89B8, $89F4 |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| ; Tick SFX: Fire sound effect (SID Voice 2). |
| ; Plays a rising-pitch pulse wave sweep to produce a "fire/shoot" sound. |
| ; |
| ; Phase 0: Idle, returns immediately. |
| ; Phase 1: Init — clears Voice 2 registers, starts 2-tick delay. |
| ; Phase 2: Plays the effect — sweeps through 8 frequency values with |
| ; increasing pulse width. After one sweep, loops or silences. |
| ; Phase 3: Final — silences Voice 2 and resets to idle. |
| ; |
| ; Inputs: sfx_fire_phase ($8988) = effect state (0=idle, 1=trigger, 2=playing, 3=stop) |
| ; Outputs: SID Voice 2 registers ($D407–$D40D) |
| ; Side Effects: Modifies SID Voice 2 output (frequency, pulse width, ADSR, gate) |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| $8992 | ad 88 89 | tick_sfx_fireldasfx_fire_phase; Check SFX phase (0=idle) ; x-ref: $1E40 |
| $8995 | d0 01 | bneb_8998; Phase 0? → return (no SFX active) |
| $8997 | 60 | rts |
| $8998 | c9 01 | b_8998cmp#$01; Phase 1? → initialize Voice 2 ; x-ref: $8995 |
| $899A | d0 14 | bneb_89B0 |
| $899C | a9 fe | lda#$fe; Timer = -2 (2-tick init delay) |
| $899E | 8d 89 89 | stasfx_fire_timer |
| $89A1 | a9 00 | lda#$00; Clear Voice 2: gate off |
| $89A3 | 8d 0b d4 | sta$d40b; Voice 2: Control Register |
| $89A6 | 8d 0c d4 | sta$d40c; Voice 2: Attack / Decay Cycle Control |
| $89A9 | 8d 0d d4 | sta$d40d; Voice 2: Sustain / Release Cycle Control |
| $89AC | ee 88 89 | incsfx_fire_phase; Advance to phase 2 (playing) |
| $89AF | 60 | rts |
| $89B0 | ee 89 89 | b_89B0incsfx_fire_timer; Increment frame timer ; x-ref: $899A |
| $89B3 | 10 01 | bplb_89B6; Still negative? → wait (init delay) |
| $89B5 | 60 | rts |
| $89B6 | d0 20 | b_89B6bneb_89D8; Timer > 0? → sweep phase ; x-ref: $89B3 |
| $89B8 | ad 8a 89 | ldasfx_fire_freq_table; Load first freq from table |
| $89BB | 8d 08 d4 | sta$d408; Voice 2: Frequency Control - High-Byte |
| $89BE | a9 00 | lda#$00 |
| $89C0 | 8d 07 d4 | sta$d407; Voice 2: Frequency Control - Low-Byte |
| $89C3 | a9 08 | lda#$08; Pulse width high nybble = $08 |
| $89C5 | 8d 0a d4 | sta$d40a; Voice 2: Pulse Waveform Width - High-Nybble |
| $89C8 | a9 10 | lda#$10; Attack=1, Decay=0 |
| $89CA | 8d 0c d4 | sta$d40c; Voice 2: Attack / Decay Cycle Control |
| $89CD | a9 40 | lda#$40; Sustain=$4, Release=0 |
| $89CF | 8d 0d d4 | sta$d40d; Voice 2: Sustain / Release Cycle Control |
| $89D2 | a9 41 | lda#$41; Pulse waveform + gate on |
| $89D4 | 8d 0b d4 | sta$d40b; Voice 2: Control Register |
| $89D7 | 60 | rts |
| $89D8 | ae 89 89 | b_89D8ldxsfx_fire_timer; X = current timer position ; x-ref: $89B6 |
| $89DB | e0 08 | cpx#$08; Reached end of sweep (8 steps)? |
| $89DD | d0 15 | bneb_89F4 |
| $89DF | ad 88 89 | ldasfx_fire_phase; Check if phase = 3 (stop requested) |
| $89E2 | c9 03 | cmp#$03 |
| $89E4 | d0 09 | bneb_89EF |
| $89E6 | a9 00 | lda#$00; Silence Voice 2 and reset to idle |
| $89E8 | 8d 0b d4 | sta$d40b; Voice 2: Control Register |
| $89EB | 8d 88 89 | stasfx_fire_phase |
| $89EE | 60 | rts |
| $89EF | a2 00 | b_89EFldx#$00; Reset timer for another sweep cycle ; x-ref: $89E4 |
| $89F1 | 8e 89 89 | stxsfx_fire_timer |
| $89F4 | bd 8a 89 | b_89F4ldasfx_fire_freq_table,x; Load freq[X] from sweep table ; x-ref: $89DD |
| $89F7 | 8d 08 d4 | sta$d408; Voice 2: Frequency Control - High-Byte |
| $89FA | 8a | txa; Pulse width = X * 256 + $800 (rising) |
| $89FB | 18 | clc |
| $89FC | 69 08 | adc#$08 |
| $89FE | 8d 0a d4 | sta$d40a; Voice 2: Pulse Waveform Width - High-Nybble |
| $8A01 | 60 | rts |
| $8A02 | ad 88 89 | j_8A02ldasfx_fire_phase; x-ref: $791C |
| $8A05 | c9 01 | cmp#$01 |
| $8A07 | d0 09 | bneb_8A12 |
| $8A09 | a9 00 | lda#$00 |
| $8A0B | 8d 0b d4 | sta$d40b; Voice 2: Control Register |
| $8A0E | 8d 88 89 | stasfx_fire_phase |
| $8A11 | 60 | rts |
| $8A12 | c9 02 | b_8A12cmp#$02; x-ref: $8A07 |
| $8A14 | d0 03 | bner_8A19 |
| $8A16 | ee 88 89 | incsfx_fire_phase |
| $8A19 | 60 | r_8A19rts; x-ref: $8A14 |
| $8A1A | | sfx_ch4_state.byte$00; x-ref: $1E60, $81A4, $8A25, $8A42, $8A8C |
| $8A1B | | sfx_ch4_delay.byte$00; x-ref: $8A31, $8A46, $8A6F, $8A78 |
| $8A1C | | sfx_ch4_freq_step.byte$00; x-ref: $8A3F, $8A7B, $8A7E |
| $8A1D | | sfx_ch4_freq_tbl.byte$30, $20, $10, $00; x-ref: $8A4E, $8A90 |
| $8A21 | | sfx_ch4_pulse_tbl.byte$06, $04, $02, $00; x-ref: $8A59, $8A96 |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| ; Tick SFX channel 4 on SID Voice 1. State machine with two phases: |
| ; State 1: Initialize voice — gate off, clear ADSR, reset frequency step. |
| ; State 2+: Cycle through 4-entry frequency/pulse-width tables, producing a |
| ; descending pitch sweep. Each sweep iteration decrements freq/pulse values; |
| ; after 15 full sweeps the effect ends and the channel is silenced. |
| ; |
| ; Inputs: sfx_ch4_state ($8A1A), sfx_ch4_delay ($8A1B), sfx_ch4_freq_step ($8A1C) |
| ; Outputs: None |
| ; Side Effects: Writes SID Voice 1 registers $D400-$D406 |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| $8A25 | ad 1a 8a | tick_sfx_ch4_voice1ldasfx_ch4_state; Check if channel is active ; x-ref: $1E43 |
| $8A28 | d0 01 | bneb_8A2B; Inactive (state=0), exit |
| $8A2A | 60 | rts |
| $8A2B | c9 01 | b_8A2Bcmp#$01; State 1 = init phase? ; x-ref: $8A28 |
| $8A2D | d0 17 | bneb_8A46 |
| $8A2F | a9 fe | lda#$fe; Delay counter = -2 (wait 2 frames before playing) |
| $8A31 | 8d 1b 8a | stasfx_ch4_delay |
| $8A34 | a9 00 | lda#$00; Gate off Voice 1, clear ADSR |
| $8A36 | 8d 04 d4 | sta$d404; Voice 1: Control Register |
| $8A39 | 8d 05 d4 | sta$d405; Voice 1: Attack / Decay Cycle Control |
| $8A3C | 8d 06 d4 | sta$d406; Voice 1: Sustain / Release Cycle Control |
| $8A3F | 8d 1c 8a | stasfx_ch4_freq_step; Reset frequency table index |
| $8A42 | ee 1a 8a | incsfx_ch4_state; Advance to state 2 (playing) |
| $8A45 | 60 | rts |
| $8A46 | ee 1b 8a | b_8A46incsfx_ch4_delay; Increment delay counter ; x-ref: $8A2D |
| $8A49 | 10 01 | bplb_8A4C; Still negative? Wait more frames |
| $8A4B | 60 | rts |
| $8A4C | d0 21 | b_8A4Cbneb_8A6F; Delay=0: start new sweep iteration ; x-ref: $8A49 |
| $8A4E | ad 1d 8a | ldasfx_ch4_freq_tbl; Load initial freq hi from table[0]=$30 |
| $8A51 | 8d 01 d4 | sta$d401; Voice 1: Frequency Control - High-Byte |
| $8A54 | a9 00 | lda#$00 |
| $8A56 | 8d 00 d4 | sta$d400; Voice 1: Frequency Control - Low-Byte |
| $8A59 | ad 21 8a | ldasfx_ch4_pulse_tbl; Load initial pulse width hi from table[0]=$06 |
| $8A5C | 8d 03 d4 | sta$d403; Voice 1: Pulse Waveform Width - High-Nybble |
| $8A5F | a9 1a | lda#$1a; Attack=1, Decay=10 |
| $8A61 | 8d 05 d4 | sta$d405; Voice 1: Attack / Decay Cycle Control |
| $8A64 | a9 00 | lda#$00; Sustain=0, Release=0 (sharp decay) |
| $8A66 | 8d 06 d4 | sta$d406; Voice 1: Sustain / Release Cycle Control |
| $8A69 | a9 41 | lda#$41; Pulse waveform + gate on |
| $8A6B | 8d 04 d4 | sta$d404; Voice 1: Control Register |
| $8A6E | 60 | rts |
| $8A6F | ae 1b 8a | b_8A6Fldxsfx_ch4_delay; Get current delay (also table index) ; x-ref: $8A4C |
| $8A72 | e0 04 | cpx#$04; Finished all 4 table entries? |
| $8A74 | d0 1a | bneb_8A90 |
| $8A76 | a2 00 | ldx#$00; Reset table index to 0 |
| $8A78 | 8e 1b 8a | stxsfx_ch4_delay |
| $8A7B | ee 1c 8a | incsfx_ch4_freq_step; Next sweep iteration |
| $8A7E | ad 1c 8a | ldasfx_ch4_freq_step |
| $8A81 | c9 0f | cmp#$0f; Done 15 sweeps? End effect |
| $8A83 | d0 0b | bneb_8A90 |
| $8A85 | a9 40 | lda#$40; Gate off (pulse waveform, no gate) |
| $8A87 | 8d 04 d4 | sta$d404; Voice 1: Control Register |
| $8A8A | a9 00 | lda#$00 |
| $8A8C | 8d 1a 8a | stasfx_ch4_state; Deactivate channel (state=0) |
| $8A8F | 60 | rts |
| $8A90 | bd 1d 8a | b_8A90ldasfx_ch4_freq_tbl,x; Update freq/pulse from table[X] ; x-ref: $8A74, $8A83 |
| $8A93 | 8d 01 d4 | sta$d401; Voice 1: Frequency Control - High-Byte |
| $8A96 | bd 21 8a | ldasfx_ch4_pulse_tbl,x |
| $8A99 | 8d 03 d4 | sta$d403; Voice 1: Pulse Waveform Width - High-Nybble |
| $8A9C | 60 | rts |
| $8A9D | | sfx_ch5_state.byte$00; x-ref: $1E63, $621D, $8A9F, $8AB9, $8AEC |
| $8A9E | | sfx_ch5_delay.byte$00; x-ref: $8AAB, $8ABD |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| ; Ticks SFX channel 5 (energy bonus countdown sound, Voice 1). |
| ; Plays a noise waveform whose frequency tracks the remaining energy value |
| ; while it is converted to score points during the level-complete sequence. |
| ; |
| ; Phase 0: Inactive (state = 0), returns immediately. |
| ; Phase 1: Silence Voice 1, reset ADSR, set delay counter, advance to phase 2. |
| ; Phase 2: Wait for delay, then gate noise waveform at energy-based frequency. |
| ; Phase 3+: Update frequency each tick from current energy value. |
| ; |
| ; Inputs: sfx_ch5_state (trigger flag set to 1 to start) |
| ; Outputs: None |
| ; Side Effects: Writes to SID Voice 1 registers ($D400-$D406) |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| $8A9F | ad 9d 8a | tick_sfx_ch5_voice1ldasfx_ch5_state; Check channel state (0=off, 1=init, 2+=playing) ; x-ref: $1E46 |
| $8AA2 | d0 01 | bneb_8AA5; State 0: channel inactive, skip |
| $8AA4 | 60 | rts; State 0: nothing to do |
| $8AA5 | c9 01 | b_8AA5cmp#$01; State 1: begin initialization? ; x-ref: $8AA2 |
| $8AA7 | d0 14 | bneb_8ABD; Not phase 1 -> skip to playback |
| $8AA9 | a9 fe | lda#$fe; Delay = -2 (count up to 0) |
| $8AAB | 8d 9e 8a | stasfx_ch5_delay; Store initial delay |
| $8AAE | a9 00 | lda#$00; Silence Voice 1: gate off |
| $8AB0 | 8d 04 d4 | sta$d404; Voice 1: Control Register |
| $8AB3 | 8d 05 d4 | sta$d405; Clear Attack/Decay; Voice 1: Attack / Decay Cycle Control |
| $8AB6 | 8d 06 d4 | sta$d406; Clear Sustain/Release; Voice 1: Sustain / Release Cycle Control |
| $8AB9 | ee 9d 8a | incsfx_ch5_state; Advance state to phase 2 |
| $8ABC | 60 | rts |
| $8ABD | ee 9e 8a | b_8ABDincsfx_ch5_delay; Increment delay counter toward 0 ; x-ref: $8AA7 |
| $8AC0 | 10 01 | bplb_8AC3; Still negative: not ready yet |
| $8AC2 | 60 | rts |
| $8AC3 | d0 1b | b_8AC3bneb_8AE0; Delay = 0: set up voice; >0: update freq ; x-ref: $8AC0 |
| $8AC5 | ad 1b 82 | ldaenergy_level; Use energy level as SID voice 1 freq |
| $8AC8 | 8d 01 d4 | sta$d401; Set frequency high byte; Voice 1: Frequency Control - High-Byte |
| $8ACB | a9 00 | lda#$00; Freq lo = 0 |
| $8ACD | 8d 00 d4 | sta$d400; Voice 1: Frequency Control - Low-Byte |
| $8AD0 | a9 10 | lda#$10; Attack=1, Decay=0 (fast attack) |
| $8AD2 | 8d 05 d4 | sta$d405; Voice 1: Attack / Decay Cycle Control |
| $8AD5 | a9 50 | lda#$50; Sustain=5, Release=0 |
| $8AD7 | 8d 06 d4 | sta$d406; Voice 1: Sustain / Release Cycle Control |
| $8ADA | a9 81 | lda#$81; $81 = gate + noise waveform |
| $8ADC | 8d 04 d4 | sta$d404; Voice 1: Control Register |
| $8ADF | 60 | rts |
| $8AE0 | ad 1b 82 | b_8AE0ldaenergy_level; Update SID freq to current energy ; x-ref: $8AC3 |
| $8AE3 | 8d 01 d4 | sta$d401; Refresh frequency high byte; Voice 1: Frequency Control - High-Byte |
| $8AE6 | 60 | rts |
| $8AE7 | a9 00 | stop_sfx_ch5lda#$00; Silence Voice 1 and reset channel ; x-ref: $624A |
| $8AE9 | 8d 04 d4 | sta$d404; Gate off, waveform off; Voice 1: Control Register |
| $8AEC | 8d 9d 8a | stasfx_ch5_state; Clear state -> channel inactive |
| $8AEF | 60 | rts |
| $8AF0 | | sfx6_enable.byte$00; x-ref: $1E66, $7C5D, $7C77, $7C7E, $819F, ... |
| $8AF1 | | sfx6_timer.byte$00; x-ref: $8AFE, $8B10, $8B32, $8B4F |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| ; Ticks SFX channel 6 state machine on SID Voice 1. Two-phase noise burst: |
| ; Phase 1: Silence Voice 1, clear ADSR, start 2-frame delay. |
| ; Phase 2: On timer=0, set noise waveform at freq $0500 with fast |
| ; attack/decay. On timer=4, release gate. On timer=6, either |
| ; restart the burst cycle or end if state was advanced to 3. |
| ; |
| ; Inputs: sfx6_enable — non-zero to activate, 0 = idle |
| ; Outputs: sfx6_enable — cleared to 0 when effect finishes |
| ; Side Effects: Writes SID Voice 1 registers ($D400–$D406) |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| $8AF2 | ad f0 8a | tick_sfx6_voice1ldasfx6_enable; Check if channel is active ; x-ref: $1E49 |
| $8AF5 | d0 01 | bneb_sfx6_active; State 0 = idle, skip |
| $8AF7 | 60 | rts; Idle — return immediately |
| $8AF8 | c9 01 | b_sfx6_activecmp#$01; State 1 = initialization phase? ; x-ref: $8AF5 |
| $8AFA | d0 14 | bneb_sfx6_advance_timer; Not state 1, skip to timer advance |
| $8AFC | a9 fe | lda#$fe; Initial delay = -2 (2 frames before trigger) |
| $8AFE | 8d f1 8a | stasfx6_timer |
| $8B01 | a9 00 | lda#$00; Gate off — silence voice |
| $8B03 | 8d 04 d4 | sta$d404; Voice 1: Control Register |
| $8B06 | 8d 05 d4 | sta$d405; Voice 1: Attack / Decay Cycle Control |
| $8B09 | 8d 06 d4 | sta$d406; Voice 1: Sustain / Release Cycle Control |
| $8B0C | ee f0 8a | b_sfx6_phase1_initincsfx6_enable |
| $8B0F | 60 | rts |
| $8B10 | ee f1 8a | b_sfx6_advance_timerincsfx6_timer; Increment delay timer ; x-ref: $8AFA |
| $8B13 | 10 01 | bplb_sfx6_set_freq; Timer < 0 — still in initial delay |
| $8B15 | 60 | rts |
| $8B16 | d0 1a | b_sfx6_set_freqbneb_sfx6_check_gate_off; Timer > 0 — check later phases ; x-ref: $8B13 |
| $8B18 | a9 05 | lda#$05; Freq hi = $05 → freq $0500 |
| $8B1A | 8d 01 d4 | sta$d401; Voice 1: Frequency Control - High-Byte |
| $8B1D | a9 00 | lda#$00; Freq lo = $00 |
| $8B1F | 8d 00 d4 | sta$d400; Voice 1: Frequency Control - Low-Byte |
| $8B22 | a9 52 | lda#$52; ADSR: Attack=$5, Decay=$2 |
| $8B24 | 8d 05 d4 | sta$d405; Voice 1: Attack / Decay Cycle Control |
| $8B27 | a9 00 | lda#$00; ADSR: Sustain=$0, Release=$0 |
| $8B29 | 8d 06 d4 | sta$d406; Voice 1: Sustain / Release Cycle Control |
| $8B2C | a9 81 | lda#$81; Noise waveform + gate on |
| $8B2E | 8d 04 d4 | sta$d404; Voice 1: Control Register |
| $8B31 | 60 | rts |
| b_sfx6_check_gate_off |
| $8B32 | ad f1 8a | ldasfx6_timer; Check timer value ; x-ref: $8B16 |
| $8B35 | c9 04 | cmp#$04; Timer == 4? |
| $8B37 | d0 06 | bneb_sfx6_check_end; Not 4, check for end phase |
| $8B39 | a9 80 | lda#$80; Noise waveform, gate OFF (release) |
| $8B3B | 8d 04 d4 | sta$d404; Voice 1: Control Register |
| $8B3E | 60 | rts |
| $8B3F | c9 06 | b_sfx6_check_endcmp#$06; Timer == 6? ; x-ref: $8B37 |
| $8B41 | d0 14 | bner_8B57; Not 6 yet — wait |
| $8B43 | ad f0 8a | ldasfx6_enable; State == 3? (cancel requested) |
| $8B46 | c9 03 | cmp#$03; If state 3, silence and end |
| $8B48 | d0 03 | bneb_sfx6_restart_cycle; Otherwise jump to silence/end |
| $8B4A | 4c 58 8b | jmpsilence_sfx6_voice1 |
| $8B4D | a9 00 | b_sfx6_restart_cyclelda#$00; Reset timer to 0 for next burst cycle ; x-ref: $8B48 |
| $8B4F | 8d f1 8a | stasfx6_timer |
| $8B52 | a9 81 | lda#$81; Noise + gate on, restart burst |
| $8B54 | 8d 04 d4 | sta$d404; Voice 1: Control Register |
| $8B57 | 60 | r_8B57rts; x-ref: $8B41 |
| $8B58 | a9 00 | silence_sfx6_voice1lda#$00; Clear gate — silence voice ; x-ref: $800F, $8B4A |
| $8B5A | 8d 04 d4 | sta$d404; Voice 1: Control Register |
| $8B5D | 8d f0 8a | stasfx6_enable; Mark channel as idle |
| $8B60 | 60 | rts |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| ; Cancels SFX channel 6. If in state 1 (init), reverts to idle. |
| ; If in state 2 (running), advances to state 3 so the tick routine |
| ; will silence the voice on the next timer=6 check. |
| ; |
| ; Inputs: sfx6_enable — current channel state |
| ; Outputs: sfx6_enable — modified to cancel the effect |
| ; Side Effects: None (actual silencing deferred to tick_sfx6_voice1) |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| $8B61 | ad f0 8a | cancel_sfx6ldasfx6_enable; Read current SFX6 state ; x-ref: $7C62 |
| $8B64 | c9 01 | cmp#$01; State == 1 (init phase)? |
| $8B66 | d0 04 | bneb_8B6C; No, check if running |
| $8B68 | ce f0 8a | decsfx6_enable; Revert to 0 (idle) — cancel init |
| $8B6B | 60 | rts |
| $8B6C | c9 02 | b_8B6Ccmp#$02; State == 2 (running)? ; x-ref: $8B66 |
| $8B6E | d0 05 | bner_8B75; Not 1 or 2, ignore |
| $8B70 | a9 03 | lda#$03; Advance to state 3 (pending cancel) |
| $8B72 | 8d f0 8a | stasfx6_enable |
| $8B75 | 60 | r_8B75rts; x-ref: $8B6E |
| $8B76 | | sfx7_enable.byte$00; x-ref: $1E69, $37CB, $8B78, $8B92, $8BCB |
| $8B77 | | sfx7_timer.byte$00; x-ref: $8B84, $8B96, $8BBD |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| ; Ticks SFX channel 7 state machine on SID Voice 1. Three-phase sound effect: |
| ; Phase 1: Silence Voice 1 and start a 2-frame delay. |
| ; Phase 2 (timer=0): Configure pulse waveform at freq $0A00, gate on. |
| ; Phase 2 (timer=1): Gate off, mark channel inactive. |
| ; |
| ; Inputs: sfx7_enable — non-zero to activate, 0 = idle |
| ; Outputs: sfx7_enable — cleared to 0 when effect finishes |
| ; Side Effects: Writes SID Voice 1 registers ($D400–$D406) |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| $8B78 | ad 76 8b | tick_sfx7_voice1ldasfx7_enable; Check if channel is active ; x-ref: $1E4C |
| $8B7B | d0 01 | bneb_8B7E; Inactive (0) → return |
| $8B7D | 60 | rts |
| $8B7E | c9 01 | b_8B7Ecmp#$01; Phase 1? (init) ; x-ref: $8B7B |
| $8B80 | d0 14 | bneb_8B96 |
| $8B82 | a9 fe | lda#$fe; Timer = -2 (2-frame delay) |
| $8B84 | 8d 77 8b | stasfx7_timer |
| $8B87 | a9 00 | lda#$00; Silence Voice 1 |
| $8B89 | 8d 04 d4 | sta$d404; Voice 1: Control Register |
| $8B8C | 8d 05 d4 | sta$d405; Voice 1: Attack / Decay Cycle Control |
| $8B8F | 8d 06 d4 | sta$d406; Voice 1: Sustain / Release Cycle Control |
| $8B92 | ee 76 8b | incsfx7_enable; Advance to phase 2 |
| $8B95 | 60 | rts |
| $8B96 | ee 77 8b | b_8B96incsfx7_timer; Increment delay timer ; x-ref: $8B80 |
| $8B99 | 10 01 | bplb_8B9C; Timer < 0? Still waiting |
| $8B9B | 60 | rts |
| $8B9C | d0 1f | b_8B9Cbneb_8BBD; Timer != 0 → check release ; x-ref: $8B99 |
| $8B9E | a9 0a | lda#$0a; Freq hi = $0A |
| $8BA0 | 8d 01 d4 | sta$d401; Voice 1: Frequency Control - High-Byte |
| $8BA3 | a9 00 | lda#$00; Freq lo = $00 → freq $0A00 |
| $8BA5 | 8d 00 d4 | sta$d400; Voice 1: Frequency Control - Low-Byte |
| $8BA8 | a9 08 | lda#$08; Pulse width hi-nybble = $08 |
| $8BAA | 8d 03 d4 | sta$d403; Voice 1: Pulse Waveform Width - High-Nybble |
| $8BAD | a9 10 | lda#$10; A=$1, D=$0 → fast attack, instant decay |
| $8BAF | 8d 05 d4 | sta$d405; Voice 1: Attack / Decay Cycle Control |
| $8BB2 | a9 a1 | lda#$a1; S=$A, R=$1 → high sustain, fast release |
| $8BB4 | 8d 06 d4 | sta$d406; Voice 1: Sustain / Release Cycle Control |
| $8BB7 | a9 41 | lda#$41; $41 = pulse waveform + gate on |
| $8BB9 | 8d 04 d4 | sta$d404; Voice 1: Control Register |
| $8BBC | 60 | rts |
| $8BBD | ad 77 8b | b_8BBDldasfx7_timer; x-ref: $8B9C |
| $8BC0 | c9 01 | cmp#$01; Timer == 1? (release frame) |
| $8BC2 | d0 0a | bner_8BCE |
| $8BC4 | a9 40 | lda#$40; $40 = pulse waveform, gate off |
| $8BC6 | 8d 04 d4 | sta$d404; Voice 1: Control Register |
| $8BC9 | a9 00 | lda#$00; Mark channel inactive |
| $8BCB | 8d 76 8b | stasfx7_enable |
| $8BCE | 60 | r_8BCErts; x-ref: $8BC2 |
| $8BCF | | sfx_ch8_state.byte$00; x-ref: $1E6C, $884D, $8BD1, $8BEB, $8C13 |
| $8BD0 | | sfx_ch8_delay.byte$00; x-ref: $8BDD, $8BEF |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| ; Tick SFX channel 8 — delayed noise burst (Voice 3). |
| ; State machine: 0=idle, 1=init (silence Voice 3, start delay), |
| ; 2=wait for delay then trigger noise waveform, then reset to idle. |
| ; Used for explosion-like sound effects. |
| ; |
| ; Inputs: sfx_ch8_state (channel state: 0=off, 1=init, 2=running) |
| ; Outputs: sfx_ch8_state, sfx_ch8_delay (updated each tick) |
| ; Side Effects: Programs SID Voice 3 registers ($D40E-$D414) |
| ; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- |
| $8BD1 | ad cf 8b | tick_sfx_ch8ldasfx_ch8_state; Check channel state (0=idle) ; x-ref: $1E4F |
| $8BD4 | d0 01 | bneb_8BD7 |
| $8BD6 | 60 | rts; Return if idle |
| $8BD7 | c9 01 | b_8BD7cmp#$01; State 1? (init phase) ; x-ref: $8BD4 |
| $8BD9 | d0 14 | bneb_8BEF |
| $8BDB | a9 fe | lda#$fe; Init delay counter to -2 (2-tick delay) |
| $8BDD | 8d d0 8b | stasfx_ch8_delay |
| $8BE0 | a9 00 | lda#$00; Silence Voice 3: gate off |
| $8BE2 | 8d 12 d4 | sta$d412; Voice 3: Control Register |
| $8BE5 | 8d 13 d4 | sta$d413; Zero attack/decay; Voice 3: Attack / Decay Cycle Control |
| $8BE8 | 8d 14 d4 | sta$d414; Zero sustain/release; Voice 3: Sustain / Release Cycle Control |
| $8BEB | ee cf 8b | incsfx_ch8_state; Advance state to 2 |
| $8BEE | 60 | rts |
| $8BEF | ee d0 8b | b_8BEFincsfx_ch8_delay; Increment delay counter ; x-ref: $8BD9 |
| $8BF2 | 10 01 | bplb_8BF5; Still negative? Not ready yet |
| $8BF4 | 60 | rts |
| $8BF5 | d0 1a | b_8BF5bneb_8C11; Counter > 0? Go to release phase ; x-ref: $8BF2 |
| $8BF7 | a9 05 | lda#$05; Counter == 0: trigger noise burst |
| $8BF9 | 8d 0f d4 | sta$d40f; Freq hi = $05 → ~328 Hz noise; Voice 3: Frequency Control - High-Byte |
| $8BFC | a9 00 | lda#$00; Freq lo = $00 |
| $8BFE | 8d 0e d4 | sta$d40e; Voice 3: Frequency Control - Low-Byte |
| $8C01 | a9 97 | lda#$97 |
| $8C03 | 8d 13 d4 | sta$d413; A/D=$97: fast attack, medium decay; Voice 3: Attack / Decay Cycle Control |
| $8C06 | a9 00 | lda#$00 |
| $8C08 | 8d 14 d4 | sta$d414; S/R=$00: no sustain, instant release; Voice 3: Sustain / Release Cycle Control |
| $8C0B | a9 81 | lda#$81; Ctrl=$81: noise waveform + gate on |
| $8C0D | 8d 12 d4 | sta$d412; Voice 3: Control Register |
| $8C10 | 60 | rts |
| $8C11 | a9 00 | b_8C11lda#$00; Counter == 1: effect done, reset state to 0 ; x-ref: $8BF5 |
| $8C13 | 8d cf 8b | stasfx_ch8_state; Clear channel state (idle) |
| $8C16 | 60 | rts |
| ; Screen row-to-address lookup table, low bytes. Maps row index (0-16) to screen RAM offset. Each row is 40 ($28) chars wide. |
| $8C17 | | row_to_screen_lo.byte<SCREEN_RAM, <SCREEN_RAM_R1C0, <SCREEN_RAM_R2C0, <SCREEN_RAM_R3C0, <SCREEN_RAM_R4C0; x-ref: $50DC, $84FD, $852B, $8662, $8777, ... |
| $8C1C | | .byte<SCREEN_RAM_R5C0, <SCREEN_RAM_R6C0, <SCREEN_RAM_R7C0, <SCREEN_RAM_R8C0, <SCREEN_RAM_R9C0 |
| $8C21 | | .byte<SCREEN_RAM_R10C0, <SCREEN_RAM_R11C0, <SCREEN_RAM_R12C0, <SCREEN_RAM_R13C0, <SCREEN_RAM_R14C0 |
| $8C26 | | .byte<SCREEN_RAM_R15C0, <SCREEN_RAM_R16C0 |
| $8C28 | | row_to_screen_hi.byte>SCREEN_RAM, >SCREEN_RAM_R1C0, >SCREEN_RAM_R2C0, >SCREEN_RAM_R3C0, >SCREEN_RAM_R4C0; x-ref: $50E1, $8506, $8534, $8669, $877E, ... |
| $8C2D | | .byte>SCREEN_RAM_R5C0, >SCREEN_RAM_R6C0, >SCREEN_RAM_R7C0, >SCREEN_RAM_R8C0, >SCREEN_RAM_R9C0 |
| $8C32 | | .byte>SCREEN_RAM_R10C0, >SCREEN_RAM_R11C0, >SCREEN_RAM_R12C0, >SCREEN_RAM_R13C0, >SCREEN_RAM_R14C0 |
| $8C37 | | .byte>SCREEN_RAM_R15C0, >SCREEN_RAM_R16C0 |