;=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
;
; Auto-generated by Regenerator 2000 v0.9.17
; https://github.com/ricardoquesada/regenerator2000
;
; Exported from: vic20_omega_race_cart_generic_a000.regen2000proj
;
; Assemble with 64tass:
; 64tass -o vic20_omega_race_cart_generic_a000.prg vic20_omega_race_cart_generic_a000.asm
;
;=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
; EXTERNAL LABELS
; zpf_ = Zero Page Field
; zpa_ = Zero Page Absolute Address
; zpp_ = Zero Page Pointer
; f_ = Field
; a_ = Absolute Address
; p_ = Pointer
; e_ = External Jump
; L_ = Other / User-defined
zp_score_cursor_x = $17 ; x-ref: $ACAF, $ACC4, $AD1E, $AD2D, $ADA7, $ADAC
zp_collision_type = $18 ; x-ref: $A5F6, $A610, $A617, $A61C, $A973, $A9AE, $A9C0, $A9CE, ...
zp_bullet_slots_free = $19 ; x-ref: $A346, $A472, $ADBD, $AE00, $AEAF
zp_marker_idx = $1a ; x-ref: $ABD0, $ABD2, $ABE1, $B17C, $B180, $B19C, $B1A3, $B1A7, ...
zp_collision_check_flag = $1b ; x-ref: $A63B, $AB07, $AB26, $AB28, $AB34, $AB36, $AE49, $AE93, ...
zp_temp_bcd_score = $1c ; x-ref: $ACB9, $ACCE, $ACE0, $ACF6, $AD04, $AD1A, $AD29, $AD3A, ...
zp_player_lives = $1f ; x-ref: $A05C, $A070, $AD66, $B10A, $B161, $B41A
zp_current_level = $20 ; x-ref: $A1B7, $A1BF, $A1D0, $A1DC, $A28D
zp_current_phase = $21 ; x-ref: $A1BB, $A1CC, $A1D2, $B376, $B38B
zp_irq_tick_counter = $22 ; x-ref: $A050, $A0CF, $A370
zp_hiscore_lo = $23 ; x-ref: $A0A2, $A0AC, $A180, $ACCC
zp_hiscore_mid = $24 ; x-ref: $A09A, $A0B0, $A182
zp_hiscore_hi = $25 ; x-ref: $A092, $A0B4, $A184
zp_bullet_hit_mask = $26 ; x-ref: $A538, $A542, $AE4B, $AE9C, $AE9E
zp_playfield_color = $27 ; x-ref: $A177, $A415, $A45C, $B433, $B481, $B483, $B487
zp_cur_entity_idx = $28 ; x-ref: $AFCC, $AFCE, $AFE5, $B01E, $B04C, $B074, $B17E, $B1A5
zp_prev_heading = $29 ; x-ref: $A1F6, $A924, $A930, $A93F, $A94B, $A956
zp_temp_frame_idx = $2a ; x-ref: $AB9B, $ABA1
zp_player_wall_hits = $2b ; x-ref: $A583, $A59E, $A5DE, $AA7E
zp_ptr_gfx_str = $2c ; x-ref: $B2CC, $B2D2, $B2D7, $B2DC, $B2E1, $B2E8, $B2EA
zp_ptr_gfx_str_hi = $2d ; x-ref: $B2CE, $B2EE
zp_entity_type_to_slot = $002e ; x-ref: $A857, $A867, $B0F5
zp_enemy1_slot_idx = $2f ; x-ref: $A114, $A338, $A69C, $A7BD, $A7F6
zp_enemy3_slot_idx = $30 ; x-ref: $A301, $A6EF, $A7D0, $A811
zp_enemy2_slot_idx = $31 ; x-ref: $A11C, $A336, $A6C6, $A7E3
zp_fire_cooldown = $35 ; x-ref: $A1F2, $A46E, $A8DC, $A92C, $ADBB
zp_enemy_ai_speed_mask = $36 ; x-ref: $A256, $A778
zp_frame_counter = $37 ; x-ref: $A03A, $A03C, $A040, $A342, $A496, $A519, $A70B, $A73C, ...
zp_enemy1_fire_timer = $38 ; x-ref: $A247, $A7C1
zp_enemy3_fire_timer = $39 ; x-ref: $A24C, $A7D4
zp_enemy2_fire_timer = $3a ; x-ref: $A251, $A7E7
zp_firing_entity_slot = $3b ; x-ref: $A7CB, $A7DE, $A7F1, $A800, $A81B, $AF48
zp_attract_delay_ctr = $3c ; x-ref: $ABF8, $ABFA, $ABFF, $AC06, $AC08, $AC11, $AFE3, $AFE7, ...
zp_max_enemy_count = $3d ; x-ref: $A060, $A074, $A1E8, $B0DA
zp_game_tick = $3e ; x-ref: $A042, $A1F8, $A6A0, $A6B9, $A6CA, $A6EB, $A7C7, $A7DA, ...
zp_entity_count = $40 ; x-ref: $A1EA, $A296, $A298, $A507, $A700, $A726, $A77C, $A889
zp_snd_bass_dur = $41 ; x-ref: $A0DD, $A0EE, $B129
zp_snd_alto_dur = $42 ; x-ref: $A087, $A0FC, $A10B, $A12B, $A21B, $B0E6
zp_snd_soprano_dur = $43 ; x-ref: $A139, $A14A, $A603, $ADCF, $B15A, $B373
zp_snd_noise_dur = $44 ; x-ref: $A158, $A169, $A48D, $A4B8, $B0D0, $B11F
zp_snd_bass_seq_idx = $45 ; x-ref: $A0D1, $A0E1, $A0E4, $A1FF, $B123
zp_snd_alto_seq_idx = $46 ; x-ref: $A081, $A0F0, $A101, $A112, $A213, $A6C0, $B0E0
zp_snd_soprano_seq_idx = $47 ; x-ref: $A12D, $A13D, $A140, $A201, $A5FD, $ADCB, $B154, $B36D
zp_snd_noise_seq_idx = $48 ; x-ref: $A14C, $A15C, $A15F, $A203, $A487, $B0CA, $B119
zp_snd_bass_step = $49 ; x-ref: $A0E6, $A0E9, $B125
zp_snd_alto_step = $4a ; x-ref: $A083, $A103, $A106, $A126, $A215, $B0E2
zp_snd_soprano_step = $4b ; x-ref: $A142, $A145, $A5FF, $ADCD, $B156, $B36F
zp_snd_noise_step = $4c ; x-ref: $A161, $A164, $A489, $B0CC, $B11B
zp_snd_volume_state = $4d ; x-ref: $A068, $A08C, $A1FA, $B10E
zp_game_phase = $4e ; x-ref: $A056, $A064, $A06C, $A08E, $A1EE, $B110, $B114
zp_enemy1_spawn_timer = $4f ; x-ref: $A25B, $A6A2, $A6BB
zp_enemy2_spawn_timer = $50 ; x-ref: $A260, $A6CC, $A6ED
zp_temp_entity_type = $51 ; x-ref: $A84F, $A85A, $A887, $A893
zp_enemy1_mine_timer = $52 ; x-ref: $A265, $A7FA, $A80F
zp_enemy3_mine_timer = $53 ; x-ref: $A26A, $A815, $A828
zp_extra_life_awarded = $54 ; x-ref: $A1B5, $AD71, $B147, $B15F
zp_difficulty_cap = $55 ; x-ref: $A1DA, $A242, $A6B3, $A6E5
zp_enemy_rot_dir = $56 ; x-ref: $A273, $A27B, $A2E6, $A308
zp_wave_vel_x = $57 ; x-ref: $A282, $A2D1, $A767
zp_wave_vel_y = $5c ; x-ref: $A287, $A2D7, $A752, $A76D
zp_wide_boundary_flag = $61 ; x-ref: $A96F, $A97B, $A991, $A9D6, $A9E8, $AA37, $AA59
zp_show_score_table = $62 ; x-ref: $A186, $B1EF, $B435
zp_pos_x = $a3 ; x-ref: $A319, $A54C, $A5B2, $A5D4, $A5E6, $A642, $A667, $A66E, ...
zp_pos_y = $a4 ; x-ref: $A31E, $A551, $A5B7, $A5D9, $A5EE, $A647, $A681, $A688, ...
zp_ptr_bmp_col_lo = $a5 ; x-ref: $A402, $A413, $A421, $A42B, $A434, $AAC0, $AACA, $AB21, ...
zp_ptr_bmp_col_hi = $a6 ; x-ref: $A408, $A42F, $A439, $A43B, $AAC7, $AAD0
zp_ptr_bmp_spill_lo = $a7 ; x-ref: $A404, $A417, $A423, $A454, $A45E, $AACE, $AB2F, $AB3B, ...
zp_ptr_bmp_spill_hi = $a8 ; x-ref: $A40C, $A458, $AAD4
zp_ptr_glyph = $a9 ; x-ref: $AB0E, $AB4C, $ABAF
zp_ptr_glyph_hi = $aa ; x-ref: $AB9F, $ABA4, $ABA7, $ABAA, $ABB1, $ABB5
zp_spr_row_mask = $ab ; x-ref: $AB1F, $AB24, $AB2B
zp_spr_spill_mask = $ac ; x-ref: $AB12, $AB1A, $AB32, $AB39, $AB52, $AB5A, $AB63
zp_spr_bit_offset = $ad ; x-ref: $AAB1, $AB14, $AB54, $AB70, $AB85, $AF85
zp_step_x = $ae ; x-ref: $A0C1, $A5C1, $A606, $AA77, $AA7C, $AA82, $AA8C, $AA95, ...
zp_step_y = $af ; x-ref: $A0C3, $A5C6, $A60B, $AA6D, $AA72, $AA97, $AAA1, $AAAA, ...
zp_joy_fire = $b0 ; x-ref: $A1F0, $A8D6, $A8E0, $A920, $A934, $A93B, $A947, $A952, ...
zp_player_angle = $b1 ; x-ref: $A2FA, $A479, $A8B7, $A8EA, $A8F7, $A8FE, $A913, $ADD2
zp_joy_left = $b2 ; x-ref: $A1F4, $A47B, $A8F4, $A91E, $A937, $A94D
zp_pixel_mask = $b3 ; x-ref: $AF8A, $AF91, $AF98, $B28C, $B2AF, $B2DE, $B31B, $B325, ...
zp_loop_idx = $b4 ; x-ref: $A53E, $A540, $A55B, $A576, $A57C, $A57E, $A5BC, $A5E4, ...
zp_seg_len = $bd ; x-ref: $ABC9, $AC64, $AC93, $AECD, $AEFC, $AF03, $AF2C
zp_score_lo = $f7 ; x-ref: $A0A4, $A0AA, $A1AF, $ACB7, $B134, $B136
zp_score_mid = $f8 ; x-ref: $A09C, $A0AE, $A1B1, $B13B, $B13D, $B14B
zp_score_hi = $f9 ; x-ref: $A094, $A0B2, $A1B3, $B13F, $B143
SCREEN_MEMORY_PAGE = $0288 ; x-ref: $A015
KEY_REPEAT = $028a ; x-ref: $A18A
MODIFIER_KEYS = $028d ; x-ref: $B421
SHIFT_CBM_LOCK = $0291 ; x-ref: $A18F
IRQ_VECTOR_LO = $0314 ; x-ref: $A1A3
IRQ_VECTOR_HI = $0315 ; x-ref: $A1A8
entity_types = $033c ; x-ref: $A2A0, $A2AB, $A331, $A50E, $A580, $A707, $A72D, $A851, ...
entity_headings = $034f ; x-ref: $A2B5, $A2FC, $A5A9, $A5CB, $A712, $A8F9, $B05E
entity_x_coords = $0362 ; x-ref: $A2BB, $A30E, $A316, $A51E, $A524, $A5D1, $A5E8, $A63F, ...
entity_x_coord_1 = $0363 ; x-ref: $A313
entity_y_coords = $0375 ; x-ref: $A2C4, $A2DD, $A31B, $A528, $A52E, $A5D6, $A5F0, $A644, ...
entity_old_x = $0388 ; x-ref: $A2BE, $A5AF, $A5EB
entity_old_y = $0395 ; x-ref: $A2C7, $A5B4, $A5F3
entity_velocity_indices = $03a2 ; x-ref: $A2A3, $A2CD, $A32E, $A466, $A509, $A58C, $A62A, $A65F, ...
entity_anim_timers = $03b5 ; x-ref: $A2F2, $A744, $A764, $B04E, $B0EB, $B107
entity_vx = $03c8 ; x-ref: $A2D4, $A33A, $A4A0, $A4A3, $A4BA, $A4CD, $A521, $A5BE, ...
BITMAP_COL0 = $1000 ; x-ref: $A429, $A42D, $AAD7
BITMAP_COL1 = $10a0 ; x-ref: $AAD9
BITMAP_COL2 = $1140 ; x-ref: $AADB
BITMAP_COL3 = $11e0 ; x-ref: $AADD
BITMAP_COL4 = $1280 ; x-ref: $AADF
BITMAP_COL5 = $1320 ; x-ref: $AAE1
BITMAP_COL6 = $13c0 ; x-ref: $AAE3
BITMAP_COL7 = $1460 ; x-ref: $AAE5
BITMAP_COL8 = $1500 ; x-ref: $AAE7
BITMAP_COL9 = $15a0 ; x-ref: $AAE9
BITMAP_COL10 = $1640 ; x-ref: $AAEB
BITMAP_COL11 = $16e0 ; x-ref: $AAED
BITMAP_COL12 = $1780 ; x-ref: $AAEF
BITMAP_COL13 = $1820 ; x-ref: $AAF1
BITMAP_COL14 = $18c0 ; x-ref: $AAF3
BITMAP_COL15 = $1960 ; x-ref: $AAF5
BITMAP_COL16 = $1a00 ; x-ref: $AAF7
BITMAP_COL17 = $1aa0 ; x-ref: $AAF9
BITMAP_COL18 = $1b40 ; x-ref: $AAFB
BITMAP_COL19 = $1be0 ; x-ref: $AAFD
entity_vy = $1d00 ; x-ref: $A2DA, $A33D, $A4AA, $A4AD, $A4D0, $A4E3, $A52B, $A5C3, ...
entity_sprite_frames = $1d13 ; x-ref: $A2B2, $A493, $A4B3, $A5C8, $A720, $A85F, $B061
entity_y_center_deltas = $1d26 ; x-ref: $A2E3, $A75E, $A761
entity_y_center_delta_1 = $1d27 ; x-ref: $A305
ai_pursuit_vx = $1d33 ; x-ref: $A799, $AF4F
ai_pursuit_vy = $1d40 ; x-ref: $A7B7, $AF5E
bullet_vx = $1d4d ; x-ref: $ADD8, $AE66, $AF3B, $AF52
bullet_vy = $1d55 ; x-ref: $ADE9, $AE74, $AF40, $AF61
bullet_lifetimes = $1d5d ; x-ref: $A34C, $ADC3, $ADF8, $AE53, $AE60, $AEB3, $AF4A, $AF6F
bullet_x_coords = $1d65 ; x-ref: $A549, $ADE2, $AE6B, $AE70, $AF31, $AF5B
bullet_y_coords = $1d6d ; x-ref: $A54E, $ADF3, $AE79, $AE7E, $AF36, $AF6A
bullet_owners = $1d75 ; x-ref: $A560, $A56B, $ADFD, $AEAA, $AF74
input_dispatch = $1d7d ; x-ref: $A17B, $A46B
input_dispatch_lo = $1d7e ; x-ref: $B3F9, $B409
input_dispatch_hi = $1d7f ; x-ref: $B3FE, $B40E
enemy_speed_masks = $1d80 ; x-ref: $A21F, $A512, $A735
enemy_speed_mask_type1 = $1d81 ; x-ref: $A225
enemy_speed_mask_type2 = $1d82 ; x-ref: $A22B
enemy_speed_mask_type3 = $1d83 ; x-ref: $A231
enemy_speed_mask_type4 = $1d84 ; x-ref: $A237
enemy_speed_mask_type5 = $1d85 ; x-ref: $A23C
enemy_speed_mask_type6 = $1d86 ; x-ref: $A23F
SCREEN_RAM_R0C19 = $1e13 ; x-ref: $A400, $A406
COLOR_RAM = $9600 ; x-ref: $A452, $A456
COLOR_RAM_R0C3 = $9603 ; x-ref: $B298
COLOR_RAM_R0C19 = $9613 ; x-ref: $A40A
COLOR_RAM_R1C21 = $962b ; x-ref: $B29B
COLOR_RAM_R2C16 = $963c ; x-ref: $B1CF
COLOR_RAM_R2C19 = $963f ; x-ref: $B29E
COLOR_RAM_R4C12 = $9664 ; x-ref: $B1D4
COLOR_RAM_R4C15 = $9667 ; x-ref: $B2A1
KERNAL_INITBAS = $e3a4 ; x-ref: $A01E
KERNAL_INITBASVEC = $e45b ; x-ref: $A01B
KERNAL_INITHW = $e518 ; x-ref: $A018
KERNAL_INITMEM = $fd8d ; x-ref: $A00A
KERNAL_INITVIA = $fdf9 ; x-ref: $A010
KERNAL_CRESTOR = $ff8a ; x-ref: $A00D
KERNAL_CSCNKEY = $ff9f ; x-ref: $B3D2
KERNAL_CGETL = $ffe4 ; x-ref: $B3E3
; ENUMS
; Enum: PetsciiShifted
PetsciiShifted = {
RAW_00: $00,
RAW_01: $01,
RAW_02: $02,
KEY_RUN_STOP: $03,
RAW_04: $04,
COLOR_WHITE: $05,
RAW_06: $06,
RAW_07: $07,
SHIFT_DISABLE: $08,
SHIFT_ENABLE: $09,
RAW_0A: $0a,
RAW_0B: $0b,
RAW_0C: $0c,
KEY_RETURN: $0d,
LOWER_CASE: $0e,
RAW_0F: $0f,
RAW_10: $10,
KEY_CRSR_DOWN: $11,
REVERSE_ON: $12,
KEY_HOME: $13,
KEY_DELETE: $14,
RAW_15: $15,
RAW_16: $16,
RAW_17: $17,
RAW_18: $18,
RAW_19: $19,
RAW_1A: $1a,
RAW_1B: $1b,
COLOR_RED: $1c,
KEY_CRSR_RIGHT: $1d,
COLOR_GREEN: $1e,
COLOR_BLUE: $1f,
KEY_SPACE: $20,
KEY_EXCLAMATION: $21,
KEY_QUOTE: $22,
KEY_HASH: $23,
KEY_DOLLAR: $24,
KEY_PERCENT: $25,
KEY_AMPERSAND: $26,
KEY_APOSTROPHE: $27,
KEY_PAREN_LEFT: $28,
KEY_PAREN_RIGHT: $29,
KEY_ASTERISK: $2a,
KEY_PLUS: $2b,
KEY_COMMA: $2c,
KEY_MINUS: $2d,
KEY_PERIOD: $2e,
KEY_SLASH: $2f,
KEY_0: $30,
KEY_1: $31,
KEY_2: $32,
KEY_3: $33,
KEY_4: $34,
KEY_5: $35,
KEY_6: $36,
KEY_7: $37,
KEY_8: $38,
KEY_9: $39,
KEY_COLON: $3a,
KEY_SEMICOLON: $3b,
KEY_LESS_THAN: $3c,
KEY_EQUAL: $3d,
KEY_GREATER_THAN: $3e,
KEY_QUESTION: $3f,
KEY_AT: $40,
KEY_a: $41,
KEY_b: $42,
KEY_c: $43,
KEY_d: $44,
KEY_e: $45,
KEY_f: $46,
KEY_g: $47,
KEY_h: $48,
KEY_i: $49,
KEY_j: $4a,
KEY_k: $4b,
KEY_l: $4c,
KEY_m: $4d,
KEY_n: $4e,
KEY_o: $4f,
KEY_p: $50,
KEY_q: $51,
KEY_r: $52,
KEY_s: $53,
KEY_t: $54,
KEY_u: $55,
KEY_v: $56,
KEY_w: $57,
KEY_x: $58,
KEY_y: $59,
KEY_z: $5a,
KEY_BRACKET_LEFT: $5b,
KEY_POUND: $5c,
KEY_BRACKET_RIGHT: $5d,
KEY_ARROW_UP: $5e,
KEY_ARROW_LEFT: $5f,
SHIFT_ASTERISK: $60,
KEY_A: $61,
KEY_B: $62,
KEY_C: $63,
KEY_D: $64,
KEY_E: $65,
KEY_F: $66,
KEY_G: $67,
KEY_H: $68,
KEY_I: $69,
KEY_J: $6a,
KEY_K: $6b,
KEY_L: $6c,
KEY_M: $6d,
KEY_N: $6e,
KEY_O: $6f,
KEY_P: $70,
KEY_Q: $71,
KEY_R: $72,
KEY_S: $73,
KEY_T: $74,
KEY_U: $75,
KEY_V: $76,
KEY_W: $77,
KEY_X: $78,
KEY_Y: $79,
KEY_Z: $7a,
SHIFT_PLUS: $7b,
CBM_ASTERISK: $7c,
SHIFT_MINUS: $7d,
SHIFT_ARROW_UP: $7e,
CBM_MINUS: $7f,
RAW_80: $80,
COLOR_ORANGE: $81,
RAW_82: $82,
RAW_83: $83,
RAW_84: $84,
KEY_F1: $85,
KEY_F3: $86,
KEY_F5: $87,
KEY_F7: $88,
KEY_F2: $89,
KEY_F4: $8a,
KEY_F6: $8b,
KEY_F8: $8c,
SHIFT_RETURN: $8d,
RAW_8E: $8e,
RAW_8F: $8f,
COLOR_BLACK: $90,
KEY_CRSR_UP: $91,
REVERSE_OFF: $92,
KEY_CLEAR: $93,
KEY_INSERT: $94,
COLOR_BROWN: $95,
COLOR_LIGHT_RED: $96,
COLOR_DARK_GRAY: $97,
COLOR_GRAY: $98,
COLOR_LIGHT_GREEN: $99,
COLOR_LIGHT_BLUE: $9a,
COLOR_LIGHT_GRAY: $9b,
COLOR_PURPLE: $9c,
KEY_CRSR_LEFT: $9d,
COLOR_YELLOW: $9e,
COLOR_CYAN: $9f,
SHIFT_SPACE: $a0,
CBM_K: $a1,
CBM_I: $a2,
CBM_T: $a3,
CBM_AT: $a4,
CBM_G: $a5,
CBM_PLUS: $a6,
CBM_M: $a7,
CBM_V: $a8,
SHIFT_POUND: $a9,
CBM_MINUS: $aa,
CBM_Q: $ab,
CBM_D: $ac,
CBM_Z: $ad,
CBM_S: $ae,
CBM_P: $af,
CBM_A: $b0,
CBM_E: $b1,
CBM_R: $b2,
CBM_W: $b3,
CBM_H: $b4,
CBM_J: $b5,
CBM_L: $b6,
CBM_Y: $b7,
CBM_U: $b8,
CBM_O: $b9,
SHIFT_AT: $ba,
CBM_F: $bb,
CBM_C: $bc,
CBM_X: $bd,
CBM_B: $be,
CBM_N: $bf,
ALT_SHIFT_ASTERISK: $c0,
ALT_KEY_A: $c1,
ALT_KEY_B: $c2,
ALT_KEY_C: $c3,
ALT_KEY_D: $c4,
ALT_KEY_E: $c5,
ALT_KEY_F: $c6,
ALT_KEY_G: $c7,
ALT_KEY_H: $c8,
ALT_KEY_I: $c9,
ALT_KEY_J: $ca,
ALT_KEY_K: $cb,
ALT_KEY_L: $cc,
ALT_KEY_M: $cd,
ALT_KEY_N: $ce,
ALT_KEY_O: $cf,
ALT_KEY_P: $d0,
ALT_KEY_Q: $d1,
ALT_KEY_R: $d2,
ALT_KEY_S: $d3,
ALT_KEY_T: $d4,
ALT_KEY_U: $d5,
ALT_KEY_V: $d6,
ALT_KEY_W: $d7,
ALT_KEY_X: $d8,
ALT_KEY_Y: $d9,
ALT_KEY_Z: $da,
ALT_SHIFT_PLUS: $db,
ALT_CBM_ASTERISK: $dc,
ALT_SHIFT_MINUS: $dd,
ALT_SHIFT_ARROW_UP: $de,
ALT_CBM_MINUS: $df,
ALT_SHIFT_SPACE: $e0,
ALT_CBM_K: $e1,
ALT_CBM_I: $e2,
ALT_CBM_T: $e3,
ALT_CBM_AT: $e4,
ALT_CBM_G: $e5,
ALT_CBM_PLUS: $e6,
ALT_CBM_M: $e7,
ALT_CBM_V: $e8,
ALT_SHIFT_POUND: $e9,
ALT_CBM_MINUS: $ea,
ALT_CBM_Q: $eb,
ALT_CBM_D: $ec,
ALT_CBM_Z: $ed,
ALT_CBM_S: $ee,
ALT_CBM_P: $ef,
ALT_CBM_A: $f0,
ALT_CBM_E: $f1,
ALT_CBM_R: $f2,
ALT_CBM_W: $f3,
ALT_CBM_H: $f4,
ALT_CBM_J: $f5,
ALT_CBM_L: $f6,
ALT_CBM_Y: $f7,
ALT_CBM_U: $f8,
ALT_CBM_O: $f9,
ALT_SHIFT_AT: $fa,
ALT_CBM_F: $fb,
ALT_CBM_C: $fc,
ALT_CBM_X: $fd,
ALT_CBM_B: $fe,
ALT_CBM_N: $ff
}
; Enum: VicColors
VicColors = {
BLACK: $00,
WHITE: $01,
RED: $02,
CYAN: $03,
PURPLE: $04,
GREEN: $05,
BLUE: $06,
YELLOW: $07,
ORANGE: $08,
LIGHT_ORANGE: $09,
PINK: $0a,
LIGHT_CYAN: $0b,
LIGHT_PURPLE: $0c,
LIGHT_GREEN: $0d,
LIGHT_BLUE: $0e,
LIGHT_YELLOW: $0f
}
$A000.wordcold_start; reset vector
$A002.wordignore_nmi; "RESTORE" key vector
$A004.byte$41, $30, $c3, $c2, $cd; "A0CBM"
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
; Cartridge cold-start entry point and main game loop for Omega Race.
; Pointed to by the cold-start vector at $A000.
;
; Phase 1 ($A009-$A025): One-time hardware and game initialization.
; - Clears decimal mode, restores KERNAL I/O vectors, resets the stack
; pointer to $1FF, then calls sA175 to set up the IRQ handler and
; load all game resources.
;
; Phase 2 ($A029-$A0CB): Main game loop.
; - Outer loop (jA029): drives a full game cycle.
; - Inner loop (bA037): per-frame update gated on the IRQ frame counter
; (a22 >= 2) to synchronize with the raster interrupt.
; - Branches on game-state flags (a4E, a4D, a1F, a3D) to handle active
; play, level countdown, player death, and level transitions.
; - Updates the 3-byte high score (a23/a24/a25) if the current score
; beats (aF7/aF8/aF9) before starting the next level.
;
; Inputs: None (entry from KERNAL reset vector)
; Outputs: None
; Side Effects: Resets hardware state; runs all per-frame game subsystems;
; manages level transitions and high-score updates.
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
$A009d8cold_startcld; clear decimal mode — safe cartridge start ; x-ref: $A000
$A00A20 8d fdjsrKERNAL_INITMEM
$A00D20 8a ffjsrKERNAL_CRESTOR; restore default KERNAL I/O vectors
$A01020 f9 fdjsrKERNAL_INITVIA
$A013a9 1elda#$1e
$A0158d 88 02staSCREEN_MEMORY_PAGE
$A01820 18 e5jsrKERNAL_INITHW
$A01B20 5b e4jsrKERNAL_INITBASVEC
$A01E20 a4 e3jsrKERNAL_INITBAS
$A02178sei
$A022a2 ffldx#$ff
$A0249atxs; reset stack pointer to $FF (top of stack)
$A02558cli
$A02620 75 a1jsrinit_game_and_hardware; one-time init: IRQ setup, load resources
$A02920 c8 b1j_A029jsrattract_mode; --- OUTER LOOP: full game cycle --- ; x-ref: $A0CB
$A02C20 ad a1jsrinit_new_game
$A02F20 be a1b_A02Fjsrinit_level; x-ref: $A06E
$A032a9 0fj_A032lda#$0f; x-ref: $A07B
$A0348d 0e 90sta$900e
$A03720 6d a3b_A037jsrreset_frame_timer; --- INNER LOOP: per-frame update --- ; x-ref: $A062, $A06A, $A090
$A03Ae6 37inczp_frame_counter; a37 = frame counter, wraps mod 8
$A03Ca5 37ldazp_frame_counter
$A03E29 07and#$07
$A04085 37stazp_frame_counter
$A042e6 3einczp_game_tick
$A04420 66 a4jsrupdate_player_physics; player/bullet physics update
$A04720 9c a6jsrupdate_enemies; enemy AI / movement update
$A04A20 07 a5jsrapply_enemy_velocities; collision detection
$A04D20 35 a5jsrupdate_display_and_collisions; sprite / display update
$A050a5 22b_A050ldazp_irq_tick_counter; --- FRAME SYNC: spin until 2 IRQ ticks elapsed --- ; x-ref: $A054
$A052c9 02cmp#$02; wait until a22 >= 2 (2 IRQ ticks = 1 frame)
$A05490 fabccb_A050; spin-wait for frame gate
$A056a5 4eldazp_game_phase; a4E: game state (0=play, 1=countdown, $C8=new level, neg=game over)
$A058c9 01cmp#$01
$A05Af0 0cbeqb_A068; a4E==1: life/level countdown active
$A05Ca5 1fldazp_player_lives; a1F<0: player dead -> game-over path
$A05E30 32bmib_A092
$A060a5 3dldazp_max_enemy_count; a3D!=0: enemies remain, keep looping
$A062d0 d3bneb_A037
$A064a5 4eldazp_game_phase; a4E==0: level cleared -> level transition
$A066f0 16beqtrigger_level_transition
$A068c6 4db_A068deczp_snd_volume_state; a4D: life/countdown timer; decrement each pass ; x-ref: $A05A
$A06Ad0 cbbneb_A037; countdown not done, keep looping
$A06Ca5 4eldazp_game_phase; a4E<0: new-level flag -> restart inner loop
$A06E30 bfbmib_A02F
$A070a5 1fldazp_player_lives; a1F<0: game-over path
$A07230 1ebmib_A092
$A074a5 3dldazp_max_enemy_count; a3D!=0: wave not cleared, keep going
$A076f0 06beqtrigger_level_transition
$A07820 d2 a1jsrrestart_current_level; display score / wave-complete sequence
$A07B4c 32 a0jmpj_A032
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
; Initiates the level transition delay.
;
; Inputs: None
; Outputs: None
; Side Effects: Called when the wave is cleared. Sets up a 200-frame countdown
; timer (a4D) and sets the level-advance flag (a4E to $C8).
; Disables and re-enables IRQs during variable assignment.
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
trigger_level_transition
$A07E78sei; disable IRQs for safe update ; x-ref: $A066, $A076
$A07Fa9 26lda#$26; set animation/state variables
$A08185 46stazp_snd_alto_seq_idx
$A08385 4astazp_snd_alto_step
$A085a9 05lda#$05
$A08785 42stazp_snd_alto_dur
$A08958cli; re-enable IRQs
$A08Aa9 c8lda#$c8; set 200-frame delay timer ($C8)
$A08C85 4dstazp_snd_volume_state; store countdown timer
$A08E85 4estazp_game_phase; Set level-advance phase ($C8)
$A090d0 a5bneb_A037; return to inner loop to wait
$A092a5 25b_A092ldazp_hiscore_hi; --- HIGH SCORE CHECK (3-byte compare, big-endian) --- ; x-ref: $A05E, $A072
$A094c5 f9cmpzp_score_hi; compare score high byte (a25) vs stored high score (aF9)
$A09690 12bccb_A0AA
$A098d0 1cbneb_A0B6
$A09Aa5 24ldazp_hiscore_mid
$A09Cc5 f8cmpzp_score_mid
$A09E90 0abccb_A0AA
$A0A0d0 14bneb_A0B6
$A0A2a5 23ldazp_hiscore_lo
$A0A4c5 f7cmpzp_score_lo
$A0A690 02bccb_A0AA
$A0A8d0 0cbneb_A0B6
$A0AAa5 f7b_A0AAldazp_score_lo; current score > high score: copy to stored record ; x-ref: $A096, $A09E, $A0A6
$A0AC85 23stazp_hiscore_lo; Update high score from current score
$A0AEa5 f8ldazp_score_mid
$A0B085 24stazp_hiscore_mid
$A0B2a5 f9ldazp_score_hi
$A0B485 25stazp_hiscore_hi
$A0B6a9 00b_A0B6lda#$00; --- LEVEL TRANSITION: reset and start next wave --- ; x-ref: $A098, $A0A0, $A0A8
$A0B88d 0e 90sta$900e
$A0BBa2 94ldx#<wave_transition_graphic; X=$94, Y=$BE: next level init parameters
$A0BDa0 beldy#>wave_transition_graphic
$A0BFa9 06lda#$06
$A0C185 aestazp_step_x
$A0C385 afstazp_step_y
$A0C520 cc b2jsrdraw_graphic_string
$A0C820 bb b3jsrdelay_1_second
$A0CB4c 29 a0jmpj_A029; restart outer loop -> next wave begins
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
; Custom IRQ handler. Increments a frame synchronization counter and processes
; background music and sound effects across 4 channels.
;
; Inputs: None
; Outputs: None
; Side Effects: Increments irq_tick_counter (a22); updates VIC sound registers
; ($900A-$900D); acknowledges VIA 2 timer interrupt.
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
$A0CE78irq_handlersei; x-ref: $A1A1, $A1A6
$A0CFe6 22inczp_irq_tick_counter; Increment frame tick counter
$A0D1a4 45ldyzp_snd_bass_seq_idx
$A0D3f0 1bbeqb_A0F0
$A0D5b9 d3 beldasnd_bass_freq_tbl,y
$A0D88d 0a 90sta$900a; Update Bass channel frequency
$A0DBf0 13beqb_A0F0
$A0DDc6 41deczp_snd_bass_dur
$A0DFd0 0fbneb_A0F0
$A0E1a4 45ldyzp_snd_bass_seq_idx
$A0E3c8iny
$A0E484 45styzp_snd_bass_seq_idx
$A0E6a4 49ldyzp_snd_bass_step
$A0E8c8iny
$A0E984 49styzp_snd_bass_step
$A0EBb9 d5 beldasnd_bass_dur_tbl,y
$A0EE85 41stazp_snd_bass_dur
$A0F0a4 46b_A0F0ldyzp_snd_alto_seq_idx; x-ref: $A0D3, $A0DB, $A0DF
$A0F2f0 1cbeqb_A110
$A0F4b9 d7 beldasnd_alto_freq_tbl,y
$A0F78d 0b 90sta$900b; Update Alto channel frequency
$A0FAf0 14beqb_A110
$A0FCc6 42deczp_snd_alto_dur
$A0FEd0 2dbneb_A12D
$A100c8iny
$A10184 46styzp_snd_alto_seq_idx
$A103a4 4aldyzp_snd_alto_step
$A105c8iny
$A10684 4astyzp_snd_alto_step
$A108b9 17 bfldasnd_alto_dur_tbl,y
$A10B85 42stazp_snd_alto_dur
$A10D4c 2d a1jmpb_A12D
$A110a9 01b_A110lda#$01; x-ref: $A0F2, $A0FA
$A11285 46stazp_snd_alto_seq_idx
$A114a5 2fldazp_enemy1_slot_idx
$A116f0 04beqb_A11C
$A118a0 4aldy#$4a
$A11Ad0 0abneb_A126
$A11Ca5 31b_A11Cldazp_enemy2_slot_idx; x-ref: $A116
$A11Ef0 04beqb_A124
$A120a0 41ldy#$41
$A122d0 02bneb_A126
$A124a0 01b_A124ldy#$01; x-ref: $A11E
$A12684 4ab_A126styzp_snd_alto_step; x-ref: $A11A, $A122
$A128b9 17 bfldasnd_alto_dur_tbl,y
$A12B85 42stazp_snd_alto_dur
$A12Da4 47b_A12Dldyzp_snd_soprano_seq_idx; x-ref: $A0FE, $A10D
$A12Ff0 1bbeqb_A14C
$A131b9 68 bfldasnd_soprano_freq_tbl,y
$A1348d 0c 90sta$900c; Update Soprano channel frequency
$A137f0 13beqb_A14C
$A139c6 43deczp_snd_soprano_dur
$A13Bd0 0fbneb_A14C
$A13Da4 47ldyzp_snd_soprano_seq_idx
$A13Fc8iny
$A14084 47styzp_snd_soprano_seq_idx
$A142a4 4bldyzp_snd_soprano_step
$A144c8iny
$A14584 4bstyzp_snd_soprano_step
$A147b9 8d bfldasnd_soprano_dur_tbl,y
$A14A85 43stazp_snd_soprano_dur
$A14Ca4 48b_A14Cldyzp_snd_noise_seq_idx; x-ref: $A12F, $A137, $A13B
$A14Ef0 1bbeqb_A16B
$A150b9 b1 bfldasnd_noise_freq_tbl,y
$A1538d 0d 90sta$900d; Update Noise channel frequency
$A156f0 13beqb_A16B
$A158c6 44deczp_snd_noise_dur
$A15Ad0 0fbneb_A16B
$A15Ca4 48ldyzp_snd_noise_seq_idx
$A15Ec8iny
$A15F84 48styzp_snd_noise_seq_idx
$A161a4 4cldyzp_snd_noise_step
$A163c8iny
$A16484 4cstyzp_snd_noise_step
$A166b9 ca bfldasnd_noise_dur_tbl,y
$A16985 44stazp_snd_noise_dur
$A16B2c 24 91b_A16Bbit$9124; Acknowledge VIA 2 Timer 1 interrupt ; x-ref: $A14E, $A156, $A15A
$A16E68pla
$A16Fa8tay
$A17068pla
$A171aatax
$A17268pla
$A17358cli
$A17440rti
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
; Initializes game variables, video hardware, and IRQ handler.
;
; Inputs: None
; Outputs: None
; Side Effects: Zeroes scores, initializes VIC registers ($9000-$900F),
; draws the playfield ($A400), and hooks the IRQ vector ($0314)
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
init_game_and_hardware
$A175a9 01lda#VicColors.WHITE; init various zero-page variables ; x-ref: $A026
$A17785 27stazp_playfield_color
$A179a9 4clda#$4c; $4C = JMP opcode
$A17B8d 7d 1dstainput_dispatch
$A17Ea9 00lda#$00
$A18085 23stazp_hiscore_lo; reset high score
$A18285 24stazp_hiscore_mid
$A18485 25stazp_hiscore_hi
$A18685 62stazp_show_score_table
$A188a9 40lda#$40
$A18A8d 8a 02staKEY_REPEAT
$A18Da9 80lda#$80
$A18F8d 91 02staSHIFT_CBM_LOCK
$A192a2 0fldx#$0f; X = 15 (for 16 VIC registers)
$A194bd 42 a4b_A194ldavic_registers,x; read VIC init values ; x-ref: $A19B
$A1979d 00 90sta$9000,x; write to VIC chip registers ($9000-$900F)
$A19Acadex
$A19B10 f7bplb_A194
$A19D20 00 a4jsrinit_playfield; draw initial playfield / clear screen
$A1A078sei
$A1A1a9 celda#<irq_handler; setup custom IRQ vector
$A1A38d 14 03staIRQ_VECTOR_LO
$A1A6a9 a0lda#>irq_handler
$A1A88d 15 03staIRQ_VECTOR_HI
$A1AB58cli
$A1AC60rts
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
; Initializes state for a new game session.
;
; Inputs: None
; Outputs: None
; Side Effects: Resets the player score ($F7-$F9), level counter (a20), and
; phase/difficulty counter (a21).
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
$A1ADa9 00init_new_gamelda#$00; reset player score byte 0 ; x-ref: $A02C, $B3C5
$A1AF85 f7stazp_score_lo; Reset score to 0
$A1B185 f8stazp_score_mid; reset player score byte 1
$A1B385 f9stazp_score_hi; reset player score byte 2
$A1B585 54stazp_extra_life_awarded; Clear extra life flag
$A1B785 20stazp_current_level; Reset level counter for new game
$A1B9a9 01lda#$01; set phase/difficulty to 1
$A1BB85 21stazp_current_phase; Start at phase 1
$A1BD60init_new_game_rtsrts; x-ref: $B3C8
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
; Initializes the game state for the start of a level/wave.
;
; Inputs: a20 (current level), a21 (current difficulty phase)
; Outputs: None
; Side Effects: Increments level counters, clears hardware sound registers,
; looks up and initializes all enemy properties (types,
; positions, velocities, animation frames) for the current wave,
; and resets the player's position.
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
$A1BE78init_levelsei; x-ref: $A02F
$A1BFa5 20ldazp_current_level
$A1C1f0 0dbeqb_A1D0; if a20 is a multiple of 4, increment phase
$A1C329 03and#$03
$A1C5d0 09bneb_A1D0
$A1C720 67 b3jsrshow_phase_bonus_screen
$A1CA78sei
$A1CBf8sed
$A1CCe6 21inczp_current_phase; Advance phase every 4 levels (BCD increment)
$A1CEd8cld
$A1CF58cli
$A1D0e6 20b_A1D0inczp_current_level; Advance to next level ; x-ref: $A1C1, $A1C5
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
; Restarts the current level/wave (e.g., after player death).
;
; Inputs: a20 (current level), a21 (current difficulty phase)
; Outputs: None
; Side Effects: Acts as an alternate entry point to init_level ($A1BE), skipping
; the code that increments the level counters. It re-initializes
; enemy positions and player state for the same wave.
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
restart_current_level
$A1D2a5 21ldazp_current_phase; cap phase difficulty at 4 ; x-ref: $A078
$A1D4c9 03cmp#$03
$A1D690 02bccb_A1DA
$A1D8a9 04lda#$04
$A1DA85 55b_A1DAstazp_difficulty_cap; x-ref: $A1D6
$A1DCa5 20ldazp_current_level; cap level difficulty at 4
$A1DEc9 03cmp#$03
$A1E090 02bccb_A1E4
$A1E2a9 04lda#$04
$A1E4aab_A1E4tax; use level as table index ; x-ref: $A1E0
$A1E5bd 73 a3ldaenemy_count_tbl,x; load number of enemies for this level
$A1E885 3dstazp_max_enemy_count
$A1EA85 40stazp_entity_count
$A1ECa9 00lda#$00; zero out game state variables
$A1EE85 4estazp_game_phase; Reset game_phase to 'play'
$A1F085 b0stazp_joy_fire
$A1F285 35stazp_fire_cooldown
$A1F485 b2stazp_joy_left
$A1F685 29stazp_prev_heading
$A1F885 3estazp_game_tick
$A1FA85 4dstazp_snd_volume_state
$A1FC8d 0e 90sta$900e
$A1FF85 45stazp_snd_bass_seq_idx
$A20185 47stazp_snd_soprano_seq_idx
$A20385 48stazp_snd_noise_seq_idx
$A2058d 0a 90sta$900a; clear VIC audio registers
$A2088d 0b 90sta$900b
$A20B8d 0c 90sta$900c
$A20E8d 0d 90sta$900d
$A211a9 01lda#$01
$A21385 46stazp_snd_alto_seq_idx
$A21585 4astazp_snd_alto_step
$A217a8tay
$A218b9 18 bfldasnd_alto_dur_tbl_offset1,y; initialize enemy types array
$A21B85 42stazp_snd_alto_dur
$A21Da9 00lda#$00
$A21F8d 80 1dstaenemy_speed_masks
$A222bd 77 a3ldawave_config_tbl_1,x
$A2258d 81 1dstaenemy_speed_mask_type1
$A228bd 7b a3ldawave_config_tbl_2,x
$A22B8d 82 1dstaenemy_speed_mask_type2
$A22Ebd 7f a3ldawave_config_tbl_3,x
$A2318d 83 1dstaenemy_speed_mask_type3
$A234bd 83 a3ldawave_config_tbl_4,x
$A2378d 84 1dstaenemy_speed_mask_type4
$A23Aa9 fflda#$ff
$A23C8d 85 1dstaenemy_speed_mask_type5
$A23F8d 86 1dstaenemy_speed_mask_type6
$A242a6 55ldxzp_difficulty_cap
$A244bd 87 a3ldawave_config_tbl_5,x; initialize wave difficulty timers
$A24785 38stazp_enemy1_fire_timer
$A249bd 8b a3ldawave_config_tbl_6,x
$A24C85 39stazp_enemy3_fire_timer
$A24Ebd 8f a3ldawave_config_tbl_7,x
$A25185 3astazp_enemy2_fire_timer
$A253bd 93 a3ldawave_config_tbl_8,x
$A25685 36stazp_enemy_ai_speed_mask
$A258bd 97 a3ldawave_config_tbl_9,x
$A25B85 4fstazp_enemy1_spawn_timer
$A25Dbd 9b a3ldawave_config_tbl_10,x
$A26085 50stazp_enemy2_spawn_timer
$A262bd 9f a3ldawave_config_tbl_11,x
$A26585 52stazp_enemy1_mine_timer
$A267bd a3 a3ldawave_config_tbl_12,x
$A26A85 53stazp_enemy3_mine_timer
$A26Cad 24 91lda$9124
$A26F29 01and#$01
$A271d0 06bneb_A279
$A27385 56stazp_enemy_rot_dir
$A275a0 03ldy#$03
$A277d0 04bneb_A27D
$A279a0 05b_A279ldy#$05; x-ref: $A271
$A27B85 56stazp_enemy_rot_dir
$A27Da2 03b_A27Dldx#$03; x-ref: $A277
$A27Fb9 f6 a3b_A27Fldavelocity_deltas_a,y; x-ref: $A28B
$A28295 57stazp_wave_vel_x,x
$A284bd fc a3ldavelocity_deltas_b,x
$A28795 5cstazp_wave_vel_y,x
$A28988dey
$A28Acadex
$A28B10 f2bplb_A27F
$A28Da5 20ldazp_current_level; Check if level >= 2 for extra enemies
$A28Fc9 02cmp#$02
$A291b0 03bcsb_A296
$A293a2 12ldx#$12
$A295.byte$2c; bit opcode
$A296a6 40b_A296ldxzp_entity_count; x-ref: $A291
$A298e4 40b_A298cpxzp_entity_count; loop over all enemies ; x-ref: $A2F6
$A29Af0 0cbeqb_A2A8
$A29C90 0abccb_A2A8
$A29Ea9 fflda#$ff
$A2A09d 3c 03staentity_types,x
$A2A39d a2 03staentity_velocity_indices,x
$A2A6d0 4dbneb_A2F5
$A2A8bd a8 a3b_A2A8ldaenemy_init_sprite_frame_idx,x; setup enemy state arrays from ROM tables ; x-ref: $A29A, $A29C
$A2AB9d 3c 03staentity_types,x
$A2AEa8tay
$A2AFb9 2b a8ldasprite_frame_start_tbl,y
$A2B29d 13 1dstaentity_sprite_frames,x
$A2B59d 4f 03staentity_headings,x; setup enemy X/Y coords
$A2B8bd b5 a3ldaenemy_init_x_coord,x
$A2BB9d 62 03staentity_x_coords,x
$A2BE9d 88 03staentity_old_x,x
$A2C1bd c2 a3ldaenemy_init_y_coord,x
$A2C49d 75 03staentity_y_coords,x
$A2C79d 95 03staentity_old_y,x
$A2CAbd cf a3ldaenemy_init_velocity_idx,x
$A2CD9d a2 03staentity_velocity_indices,x
$A2D0a8tay
$A2D1b9 57 00lda@w zp_wave_vel_x,y; setup enemy X/Y velocities
$A2D49d c8 03staentity_vx,x
$A2D7b9 5c 00lda@w zp_wave_vel_y,y
$A2DA9d 00 1dstaentity_vy,x
$A2DDbd 75 03ldaentity_y_coords,x
$A2E038sec
$A2E1e9 64sbc#$64
$A2E39d 26 1dstaentity_y_center_deltas,x
$A2E6a5 56ldazp_enemy_rot_dir
$A2E8d0 05bneb_A2EF
$A2EAbd dc a3ldaenemy_init_data_1,x
$A2EDd0 03bneb_A2F2
$A2EFbd e9 a3b_A2EFldaenemy_init_data_2,x; x-ref: $A2E8
$A2F29d b5 03b_A2F2staentity_anim_timers,x; x-ref: $A2ED
$A2F5cab_A2F5dex; x-ref: $A2A6
$A2F610 a0bplb_A298
$A2F8a9 0clda#$0c
$A2FA85 b1stazp_player_angle
$A2FC8d 4f 03staentity_headings
$A2FFa9 01lda#$01
$A30185 30stazp_enemy3_slot_idx
$A303a9 14lda#$14
$A3058d 27 1dstaentity_y_center_delta_1
$A308a5 56ldazp_enemy_rot_dir
$A30Ad0 0abneb_A316
$A30Ca9 8clda#$8c
$A30E8d 62 03staentity_x_coords
$A311a9 14lda#$14
$A3138d 63 03staentity_x_coord_1
$A316ad 62 03b_A316ldaentity_x_coords; verify player spawn position is clear ; x-ref: $A30A
$A31985 a3stazp_pos_x
$A31Bad 75 03ldaentity_y_coords
$A31E85 a4stazp_pos_y
$A32020 5d a6jsrcheck_entity_collision
$A3238atxa
$A32430 0ebmib_A334
$A326f0 0cbeqb_A334
$A328e0 0dcpx#$0d
$A32A90 08bccb_A334
$A32Ca9 fflda#$ff
$A32E9d a2 03staentity_velocity_indices,x
$A3319d 3c 03staentity_types,x
$A334a9 00b_A334lda#$00; x-ref: $A324, $A326, $A32A
$A33685 31stazp_enemy2_slot_idx
$A33885 2fstazp_enemy1_slot_idx
$A33A8d c8 03staentity_vx
$A33D8d 00 1dstaentity_vy
$A340a9 fflda#$ff
$A34285 37stazp_frame_counter
$A344a9 04lda#$04
$A34685 19stazp_bullet_slots_free
$A348a9 00lda#$00
$A34Aa2 07ldx#$07
$A34C9d 5d 1db_A34Cstabullet_lifetimes,x; x-ref: $A350
$A34Fcadex
$A35010 fabplb_A34C
$A35220 29 a4jsrclear_char_ram
$A35520 52 a4jsrfill_color_ram
$A35820 04 acjsrdraw_arena_border
$A35B20 ad acjsrdraw_player_score
$A35E20 c2 acjsrdraw_high_score
$A36120 18 adjsrdraw_wave_indicator
$A36420 4a adjsrdraw_lives_display
$A36720 f6 abjsrerase_arena_border
$A36A20 ce abjsrdraw_markers
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
; Resets the IRQ frame tick counter.
;
; Inputs: None
; Outputs: None
; Side Effects: Zeroes out a22 (the IRQ tick counter) with interrupts disabled
; to prevent race conditions.
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
$A36D78reset_frame_timersei; disable IRQs for safe modification ; x-ref: $A037
$A36Ea9 00lda#$00; zero out the frame tick counter
$A37085 22stazp_irq_tick_counter
$A37258cli; re-enable IRQs
$A37360enemy_count_tblrts; x-ref: $A1E5
; Table of number of enemies per level.
; Note that level 0 uses the RTS opcode ($60) at $A373 as a space-saving trick.
$A374.byte$06, $08, $0a
; Wave configuration tables. Used to initialize game parameters based on difficulty phase.
$A377wave_config_tbl_1.byte$0c, $01, $01, $01; x-ref: $A222
$A37Bwave_config_tbl_2.byte$00, $03, $01, $01; x-ref: $A228
$A37Fwave_config_tbl_3.byte$01, $07, $03, $03; x-ref: $A22E
$A383wave_config_tbl_4.byte$01, $ff, $0f, $0f; x-ref: $A234
$A387wave_config_tbl_5.byte$07, $fe, $0f, $07; x-ref: $A244
$A38Bwave_config_tbl_6.byte$03, $1f, $0f, $07; x-ref: $A249
$A38Fwave_config_tbl_7.byte$07, $ff, $7f, $7f; x-ref: $A24E
$A393wave_config_tbl_8.byte$7f, $07, $03, $01; x-ref: $A253
$A397wave_config_tbl_9.byte$00, $c8, $40, $20; x-ref: $A258
$A39Bwave_config_tbl_10.byte$14, $dc, $14, $14; x-ref: $A25D
$A39Fwave_config_tbl_11.byte$0a, $ff, $ff, $c8; x-ref: $A262
$A3A3wave_config_tbl_12.byte$96, $ff, $ff, $ff, $ff; x-ref: $A267
enemy_init_sprite_frame_idx
$A3A8.byte$00, $02; x-ref: $A2A8
$A3AA.fill11, $04
$A3B5enemy_init_x_coord.byte$14, $8c, $22, $40, $4c, $4a, $4f, $54; x-ref: $A2B8
$A3BD.byte$63, $63, $6d, $70, $40
$A3C2enemy_init_y_coord.byte$28, $5a, $79, $81, $70, $86, $77, $86; x-ref: $A2C1
$A3CA.byte$77, $86, $72, $8b, $6e
enemy_init_velocity_idx
$A3CF.byte$03, $01; x-ref: $A2CA
$A3D1.fill11, $00
$A3DCenemy_init_data_1.byte$00, $32, $0f, $35, $30, $44, $3a, $4e; x-ref: $A2EA
$A3E4.byte$4e, $5d, $53, $6f, $22
$A3E9enemy_init_data_2.byte$00, $32, $6b, $55, $38, $50, $3c, $46; x-ref: $A2EF
$A3F1.byte$28, $37, $19, $2f, $42
$A3F6velocity_deltas_a.byte$ff, $00, $01, $00, $ff, $00; x-ref: $A27F
$A3FCvelocity_deltas_b.byte$00, $ff, $00, $01; x-ref: $A284
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
; Initializes the playfield by setting up a 20x10 grid of unique characters
; and clearing the character definition area ($1000-$1CFF).
;
; Inputs: a27 (Color value for the playfield)
; Outputs: None
; Side Effects: Modifies Screen and Color RAM; clears RAM from $1000 to $1CFF
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
$A400a9 13init_playfieldlda#<SCREEN_RAM_R0C19; Pointer to Screen RAM ($1E13) ; x-ref: $A19D
$A40285 a5stazp_ptr_bmp_col_lo
$A40485 a7stazp_ptr_bmp_spill_lo
$A406a9 1elda#>SCREEN_RAM_R0C19
$A40885 a6stazp_ptr_bmp_col_hi
$A40Aa9 96lda#>COLOR_RAM_R0C19; Pointer to Color RAM ($9613)
$A40C85 a8stazp_ptr_bmp_spill_hi
$A40Ea2 c7ldx#$c7; Init counter for 200 tiles
$A410a0 b4b_A410ldy#$b4; x-ref: $A427
$A4128ab_A412txa; x-ref: $A41F
$A41391 a5sta(zp_ptr_bmp_col_lo),y; Store unique char code
$A415a5 27ldazp_playfield_color
$A41791 a7sta(zp_ptr_bmp_spill_lo),y; Store color
$A419cadex
$A41A98tya
$A41B38sec
$A41Ce9 14sbc#$14; Move up one row (20 columns)
$A41Ea8tay
$A41Fb0 f1bcsb_A412
$A421c6 a5deczp_ptr_bmp_col_lo
$A423c6 a7deczp_ptr_bmp_spill_lo
$A425e0 ffcpx#$ff
$A427d0 e7bneb_A410
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
; Clears the custom character definition RAM ($1000-$1CFF) by zeroing all
; 3,072 bytes. Called before drawing any new bitmap graphic into the character
; set (title screens, phase bonus, level transitions).
;
; Inputs: None
; Outputs: None
; Side Effects: Zeroes $1000-$1CFF via pointer aA5/aA6
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
$A429a9 00clear_char_ramlda#<BITMAP_COL0; x-ref: $A352, $B1C8, $B1F6, $B20E, $B229, $B24C, $B266, $B367
$A42B85 a5stazp_ptr_bmp_col_lo; set pointer low byte = $00
$A42Da9 10lda#>BITMAP_COL0; set pointer high byte = $10 (start at $1000)
$A42F85 a6stazp_ptr_bmp_col_hi
$A431a9 00lda#$00
$A433a8tay
$A43491 a5b_A434sta(zp_ptr_bmp_col_lo),y; write zero to (aA5),Y ; x-ref: $A437, $A43F
$A436c8iny
$A437d0 fbbneb_A434
$A439e6 a6inczp_ptr_bmp_col_hi; advance to next page
$A43Ba6 a6ldxzp_ptr_bmp_col_hi
$A43De0 1dcpx#$1d; stop when high byte reaches $1D (past $1CFF)
$A43Fd0 f3bneb_A434; Clear up to $1CFF
$A44160rts
$A442vic_registers.byte$07, $1b, $94, $15, $00, $fc; x-ref: $A194
$A448.fill9, $00
$A451.byte$08
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
; Fills all 200 Color RAM cells ($9600-$96C7) with the value in a27.
; Used to paint a uniform color across the 20x10 playfield character grid.
;
; Inputs: a27 (color value to fill)
; Outputs: None
; Side Effects: Overwrites $9600-$96C7 (Color RAM) via pointer aA7/aA8
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
$A452a9 00fill_color_ramlda#<COLOR_RAM; set pointer to Color RAM ($9600) ; x-ref: $A355, $B1F3, $B20B, $B22C, $B489
$A45485 a7stazp_ptr_bmp_spill_lo
$A456a9 96lda#>COLOR_RAM
$A45885 a8stazp_ptr_bmp_spill_hi
$A45Aa0 c7ldy#$c7; Y = 199 — fill 200 cells
$A45Ca5 27ldazp_playfield_color; load fill color
$A45E91 a7b_A45Esta(zp_ptr_bmp_spill_lo),y; store color to (aA7),Y ; x-ref: $A463
$A46088dey; count down
$A461c0 ffcpy#$ff
$A463d0 f9bneb_A45E
$A46560rts
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
; Update player ship velocity, sprite frame, thruster state, and fire button.
;
; Each frame (called from main loop at $A044):
; 1. Bail if player is inactive (f03A2 < 0).
; 2. Read joystick via a1D7D; if fire cooldown (a35) is clear and a bullet
; slot is free (a19 != 0), spawn a projectile via sADB9.
; 3. Look up signed X/Y velocity deltas from 16-entry direction tables
; (fA4E7 / fA4F7) indexed by the current heading (aB1, 0-15).
; Deltas are applied every other frame (a37 odd = skip) for half-rate
; physics accumulation.
; 4. If the fire button (VIA1 $900D bit 7) is pressed, activate thruster:
; set countdown timers a48/a4C=$18 and speed timer a44=$64, and write
; the thrusting sprite frame to f1D13 (aB1 | $10).
; 5. Clamp both X (f03C8) and Y (f1D00) velocities to the range -3..+3
; ($FD..$03).
;
; Inputs: aB1 = current heading (0-15), f03A2 = player alive flag,
; a35 = fire cooldown, a19 = bullet slots free,
; aB2 = direction flip bit, a900D = VIA1 joystick/fire port
; Outputs: f03C8 = X velocity (clamped -3..+3),
; f1D00 = Y velocity (clamped -3..+3),
; f1D13 = sprite frame register
; Side Effects: May spawn bullet (sADB9); sets thruster timers a44/a48/a4C.
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
update_player_physics
$A466ad a2 03ldaentity_velocity_indices; f03A2 = player alive flag; negative = dead/inactive ; x-ref: $A044
$A46930 7bbmir_A4E6; player inactive -> skip all updates
patch_input_dispatch_hi =*+$02 ; x-ref: $B166
$A46B20 7d 1djsrinput_dispatch; read joystick, compute velocity delta from heading
$A46E24 35bitzp_fire_cooldown; a35 = fire cooldown; bit N set = cooldown active
$A47010 07bplb_A479; skip if cooldown active (N set)
$A472a5 19ldazp_bullet_slots_free; a19 = bullet slots free; 0 = none available
$A474f0 03beqb_A479; no bullet slot free -> skip fire
$A47620 b9 adjsrfire_bullet; spawn bullet: clear cooldown, fire projectile
$A479a5 b1b_A479ldazp_player_angle; aB1 = heading (0-15); aB2 bit 7 = direction flip ; x-ref: $A470, $A474
$A47B24 b2bitzp_joy_left; aB2 bit 7: direction flip (0=right, 1=left)
$A47D10 34bplb_A4B3; ship not thrusting (aB2 N clear) -> sprite-only path
$A47F2c 0d 90bit$900d; VIA1 $900D bit 7: fire button (0=pressed)
$A48230 0cbmib_A490
$A48478sei; --- THRUSTER ACTIVATED: set animation timers ---
$A485a0 18ldy#$18
$A48784 48styzp_snd_noise_seq_idx
$A48984 4cstyzp_snd_noise_step
$A48Ba0 64ldy#$64; a44 = speed timer ($64 = 100 frames)
$A48D84 44styzp_snd_noise_dur
$A48F58cli
$A490a8b_A490tay; Y = heading (0-15); set thrusting sprite frame: aB1 | $10 ; x-ref: $A482
$A49109 10ora#$10
$A4938d 13 1dstaentity_sprite_frames; write thrusting sprite frame to f1D13
$A496a5 37ldazp_frame_counter; a37 bit 0: only accumulate velocity on even frames (half-rate)
$A49829 01and#$01
$A49Ad0 1ebneb_A4BA; odd frame -> skip velocity accumulation
$A49C18clc
$A49Db9 e7 a4ldax_velocity_delta_tbl,y; look up X velocity delta based on heading; X velocity delta table (16 directions)
$A4A06d c8 03adcentity_vx; accumulate X velocity
$A4A38d c8 03staentity_vx
$A4A618clc
$A4A7b9 f7 a4lday_velocity_delta_tbl,y; look up Y velocity delta based on heading; Y velocity delta table (16 directions)
$A4AA6d 00 1dadcentity_vy; accumulate Y velocity
$A4AD8d 00 1dstaentity_vy
$A4B04c ba a4jmpb_A4BA
$A4B38d 13 1db_A4B3staentity_sprite_frames; ship not thrusting: set sprite frame without thruster ; x-ref: $A47D
$A4B6a9 01lda#$01
$A4B885 44stazp_snd_noise_dur; set speed timer to 1
$A4BAad c8 03b_A4BAldaentity_vx; --- CLAMP X VELOCITY (-3..+3) --- ; x-ref: $A49A, $A4B0
$A4BD30 08bmib_A4C7; negative velocity? branch to neg clamp
$A4BFc9 04cmp#$04; clamp positive to 3 (if >= 4)
$A4C190 0dbccb_A4D0
$A4C3a9 03lda#$03
$A4C5d0 06bneb_A4CD
$A4C7c9 fdb_A4C7cmp#$fd; clamp negative to -3 ($FD) (if < -3) ; x-ref: $A4BD
$A4C9b0 05bcsb_A4D0
$A4CBa9 fdlda#$fd
$A4CD8d c8 03b_A4CDstaentity_vx; x-ref: $A4C5
$A4D0ad 00 1db_A4D0ldaentity_vy; --- CLAMP Y VELOCITY (-3..+3) --- ; x-ref: $A4C1, $A4C9
$A4D330 08bmib_A4DD; negative velocity? branch to neg clamp
$A4D5c9 04cmp#$04; clamp positive to 3 (if >= 4)
$A4D790 0dbccr_A4E6
$A4D9a9 03lda#$03
$A4DBd0 06bneb_A4E3
$A4DDc9 fdb_A4DDcmp#$fd; clamp negative to -3 ($FD) (if < -3) ; x-ref: $A4D3
$A4DFb0 05bcsr_A4E6
$A4E1a9 fdlda#$fd
$A4E38d 00 1db_A4E3staentity_vy; x-ref: $A4DB
$A4E660r_A4E6rts; x-ref: $A469, $A4D7, $A4DF
$A4E7x_velocity_delta_tbl.byte$02, $01, $01, $01, $00, $ff, $ff, $ff; X velocity delta table (16 directions) ; x-ref: $A49D
$A4EF.byte$fe, $ff, $ff, $ff, $00, $01, $01, $01
$A4F7y_velocity_delta_tbl.byte$00, $ff, $ff, $ff, $fe, $ff, $ff, $ff; Y velocity delta table (16 directions) ; x-ref: $A4A7
$A4FF.byte$00, $01, $01, $01, $02, $01, $01, $01
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
; Applies velocity to enemy positions.
;
; Inputs: a40 (enemy count), a37 (frame counter), $03C8/$1D00 arrays (velocities)
; Outputs: $0362/$0375 arrays (positions)
; Side Effects: Updates coordinates of active enemies
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
apply_enemy_velocities
$A507a6 40ldxzp_entity_count; X = active enemy index ; x-ref: $A04A
$A509bd a2 03b_A509ldaentity_velocity_indices,x; check if enemy is active ; x-ref: $A532
$A50C30 23bmib_A531
$A50Ebd 3c 03ldaentity_types,x; get enemy type
$A511a8tay
$A512b9 80 1dldaenemy_speed_masks,y; check frame sync for type
$A515c9 ffcmp#$ff
$A517f0 18beqb_A531
$A51925 37andzp_frame_counter
$A51Bd0 14bneb_A531
$A51D18clc; apply X velocity to X position
$A51Ebd 62 03ldaentity_x_coords,x
$A5217d c8 03adcentity_vx,x
$A5249d 62 03staentity_x_coords,x
$A52718clc; apply Y velocity to Y position
$A528bd 75 03ldaentity_y_coords,x
$A52B7d 00 1dadcentity_vy,x
$A52E9d 75 03staentity_y_coords,x
$A531cab_A531dex; loop for all enemies ; x-ref: $A50C, $A517, $A51B
$A53210 d5bplb_A509
$A53460rts
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
; Updates display states and handles all entity collisions.
;
; Inputs: a26 (bullet flags), bullet positions, player position, enemy positions
; Outputs: Collision state (kills enemies or player), sprite display arrays
; Side Effects: Calls collision detection, plays sound effects, removes killed entities
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
update_display_and_collisions
$A53520 47 aejsrupdate_bullets; x-ref: $A04D
$A538a5 26ldazp_bullet_hit_mask
$A53Af0 3ebeqb_A57A
$A53Ca9 07lda#$07; bullet loop from 7 to 0
$A53E85 b4stazp_loop_idx
$A540a6 b4b_A540ldxzp_loop_idx; x-ref: $A578
$A542a5 26ldazp_bullet_hit_mask
$A5443d 93 abandbit_mask_tbl,x; check if bullet is active
$A547f0 2dbeqb_A576
$A549bd 65 1dldabullet_x_coords,x; load bullet X
$A54C85 a3stazp_pos_x
$A54Ebd 6d 1dldabullet_y_coords,x; load bullet Y
$A55185 a4stazp_pos_y
$A55320 5d a6jsrcheck_entity_collision; check collision against enemies
$A5568atxa; X=FF if no collision
$A557c9 ffcmp#$ff
$A559f0 1bbeqb_A576
$A55Ba4 b4ldyzp_loop_idx
$A55D8atxa
$A55Ed0 0bbneb_A56B
$A560b9 75 1dldabullet_owners,y
$A563f0 15beqb_A57A
$A56520 b6 b0jsrhandle_entity_hit; handle bullet hit enemy
$A5684c 7a a5jmpb_A57A
$A56Bb9 75 1db_A56Bldabullet_owners,y; x-ref: $A55E
$A56Ed0 0abneb_A57A
$A57020 b6 b0jsrhandle_entity_hit
$A5734c 7a a5jmpb_A57A
$A576c6 b4b_A576deczp_loop_idx; x-ref: $A547, $A559
$A57810 c6bplb_A540
$A57Aa9 12b_A57Alda#$12; enemy loop from 18 down to 0 ; x-ref: $A53A, $A563, $A568, $A56E, $A573
$A57C85 b4stazp_loop_idx
$A57Ea4 b4j_A57Eldyzp_loop_idx; x-ref: $A627
$A580b9 3c 03ldaentity_types,y
$A58385 2bstazp_player_wall_hits
$A585c9 ffcmp#$ff
$A587d0 03bneb_A58C
$A5894c 23 a6jmpj_A623
$A58Cb9 a2 03b_A58Cldaentity_velocity_indices,y; x-ref: $A587
$A58F10 0dbplb_A59E
$A591c9 ffcmp#$ff
$A593d0 03bneb_A598
$A5954c 23 a6jmpj_A623
$A59820 cc afb_A598jsrdraw_enemy; x-ref: $A593
$A59B4c 23 a6jmpj_A623
$A59Ea5 2bb_A59Eldazp_player_wall_hits; x-ref: $A58F
$A5A0c9 05cmp#$05
$A5A290 05bccb_A5A9
$A5A418clc
$A5A569 22adc#$22
$A5A7d0 25bneb_A5CE
$A5A9b9 4f 03b_A5A9ldaentity_headings,y; x-ref: $A5A2
$A5AC20 9b abjsrcalc_sprite_ptr
$A5AFb9 88 03ldaentity_old_x,y
$A5B285 a3stazp_pos_x
$A5B4b9 95 03ldaentity_old_y,y
$A5B785 a4stazp_pos_y
$A5B920 41 abjsrerase_sprite
$A5BCa4 b4ldyzp_loop_idx
$A5BEb9 c8 03ldaentity_vx,y
$A5C185 aestazp_step_x
$A5C3b9 00 1dldaentity_vy,y
$A5C685 afstazp_step_y
$A5C8b9 13 1dldaentity_sprite_frames,y
$A5CB99 4f 03staentity_headings,y
$A5CE20 9b abb_A5CEjsrcalc_sprite_ptr; x-ref: $A5A7
$A5D1b9 62 03ldaentity_x_coords,y
$A5D485 a3stazp_pos_x
$A5D6b9 75 03ldaentity_y_coords,y
$A5D985 a4stazp_pos_y
$A5DB20 05 abjsrdraw_sprite_with_collision_check
$A5DEa5 2bldazp_player_wall_hits
$A5E0c9 05cmp#$05
$A5E2b0 3fbcsj_A623
$A5E4a4 b4ldyzp_loop_idx
$A5E6a5 a3ldazp_pos_x
$A5E899 62 03staentity_x_coords,y
$A5EB99 88 03staentity_old_x,y
$A5EEa5 a4ldazp_pos_y
$A5F099 75 03staentity_y_coords,y
$A5F399 95 03staentity_old_y,y
$A5F6a5 18ldazp_collision_type
$A5F8f0 29beqj_A623
$A5FA78sei
$A5FBa9 21lda#$21
$A5FD85 47stazp_snd_soprano_seq_idx
$A5FF85 4bstazp_snd_soprano_step
$A601a9 03lda#$03
$A60385 43stazp_snd_soprano_dur
$A60558cli
$A606a5 aeldazp_step_x
$A60899 c8 03staentity_vx,y
$A60Ba5 afldazp_step_y
$A60D99 00 1dstaentity_vy,y
$A610a5 18ldazp_collision_type
$A61230 05bmib_A619
$A61420 69 acjsrdraw_border_segment
$A617a5 18ldazp_collision_type
$A61920 77 acb_A619jsrerase_border_segment; x-ref: $A612
$A61Ca5 18ldazp_collision_type
$A61E10 03bplj_A623
$A62020 69 acjsrdraw_border_segment
$A623c6 b4j_A623deczp_loop_idx; x-ref: $A589, $A595, $A59B, $A5E2, $A5F8, $A61E
$A62530 03bmib_A62A
$A6274c 7e a5jmpj_A57E
$A62Aad a2 03b_A62Aldaentity_velocity_indices; x-ref: $A625
$A62D30 2abmib_A659
$A62Fad c8 03ldaentity_vx
$A632d0 07bneb_A63B
$A634ad 00 1dldaentity_vy
$A637d0 02bneb_A63B
$A639f0 04beqb_A63F
$A63Ba5 1bb_A63Bldazp_collision_check_flag; x-ref: $A632, $A637
$A63Df0 1abeqb_A659
$A63Fad 62 03b_A63Fldaentity_x_coords; load player X ; x-ref: $A639
$A64285 a3stazp_pos_x
$A644ad 75 03ldaentity_y_coords; load player Y
$A64785 a4stazp_pos_y
$A64920 5d a6jsrcheck_entity_collision; check player collision against enemies
$A64C8atxa
$A64D30 0abmib_A659
$A64Ff0 08beqb_A659
$A65120 b6 b0jsrhandle_entity_hit; handle player hit by enemy
$A654a2 00ldx#$00
$A65620 b6 b0jsrhandle_entity_hit
$A65920 ce abb_A659jsrdraw_markers; x-ref: $A62D, $A63D, $A64D, $A64F
$A65C60rts
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
; Checks whether a given X,Y position collides with any active entity.
; Scans all 19 entity slots ($12 down to $00) using 8x8 pixel bounding-box
; (AABB) collision detection.
;
; Inputs: $A3 = X coordinate to test, $A4 = Y coordinate to test
; Outputs: X = index of colliding entity (0-$12), or $FF if no collision
; Side Effects: None
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
check_entity_collision
$A65Da2 12ldx#$12; start from last entity slot ; x-ref: $A320, $A553, $A649
$A65Fbd a2 03b_A65Fldaentity_velocity_indices,x; check entity state ; x-ref: $A699
$A66230 34bmib_A698; skip if inactive (bit 7 set)
$A664bd 62 03ldaentity_x_coords,x; entity X position
$A667c5 a3cmpzp_pos_x; compare with test X
$A669b0 09bcsb_A674; entity.X >= test.X? check right edge
$A66B18clc
$A66C69 08adc#$08; entity.X + 8 (hitbox width)
$A66Ec5 a3cmpzp_pos_x; compare with test.X
$A670b0 0cbcsb_A67E; overlap on X axis? check Y
$A67290 24bccb_A698; no X overlap, skip
$A674a5 a3b_A674ldazp_pos_x; test.X ; x-ref: $A669
$A67618clc
$A67769 08adc#$08; test.X + 8 (hitbox width)
$A679dd 62 03cmpentity_x_coords,x; test.X + 8 >= entity.X? overlap
$A67C90 1abccb_A698; no X overlap, skip
$A67Ebd 75 03b_A67Eldaentity_y_coords,x; entity Y position ; x-ref: $A670
$A681c5 a4cmpzp_pos_y; compare with test Y
$A683b0 09bcsb_A68E; entity.Y >= test.Y? check bottom edge
$A68518clc
$A68669 08adc#$08; entity.Y + 8 (hitbox height)
$A688c5 a4cmpzp_pos_y; compare with test.Y
$A68Ab0 0fbcsr_A69B; overlap on both axes = collision!
$A68C90 0abccb_A698; no Y overlap, skip
$A68Ea5 a4b_A68Eldazp_pos_y; test.Y ; x-ref: $A683
$A69018clc
$A69169 08adc#$08; test.Y + 8 (hitbox height)
$A693dd 75 03cmpentity_y_coords,x; test.Y + 8 >= entity.Y? overlap
$A696b0 03bcsr_A69B; collision! return with X = entity index
$A698cab_A698dex; next entity ; x-ref: $A662, $A672, $A67C, $A68C
$A69910 c4bplb_A65F; loop until X wraps to $FF
$A69B60r_A69Brts; return: X = entity index or $FF ; x-ref: $A68A, $A696
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
; Updates all enemy states, animations, movement, and spawning.
; Handles spawning of enemy types 1 and 2 based on difficulty timers,
; updates sprite frames for animation, calculates pursuit AI velocities
; towards the player based on distance brackets, and handles enemy firing.
;
; Inputs: a37 (frame counter), a3E (timer), a40 (enemy count)
; player position (f0362, f0375)
; Outputs: Enemy states (zero page and $03xx/$1Dxx arrays) updated
; Side Effects: Spawns new enemies, updates sprite pointers and positions
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
$A69Ca5 2fupdate_enemiesldazp_enemy1_slot_idx; check if enemy 1 is active ; x-ref: $A047
$A69Ed0 4fbneb_A6EF
$A6A0a5 3eldazp_game_tick; load frame tick timer
$A6A2c5 4fcmpzp_enemy1_spawn_timer
$A6A4d0 20bneb_A6C6
$A6A6a0 03ldy#$03; search for active entity of type 3
$A6A820 87 a8jsrfind_active_entity_by_type
$A6AB8atxa
$A6ACf0 18beqb_A6C6
$A6AEa0 01ldy#$01
$A6B020 4f a8jsrspawn_entity_init; spawn enemy type 1
$A6B3a6 55ldxzp_difficulty_cap
$A6B5bd 3f a8ldaspawn_delay_enemy1_tbl,x
$A6B818clc
$A6B965 3eadczp_game_tick
$A6BB85 4fstazp_enemy1_spawn_timer
$A6BD78sei; disable IRQs for spawning
$A6BEa9 00lda#$00
$A6C085 46stazp_snd_alto_seq_idx
$A6C258cli
$A6C34c ef a6jmpb_A6EF
$A6C6a5 31b_A6C6ldazp_enemy2_slot_idx; check if enemy 2 is active ; x-ref: $A6A4, $A6AC
$A6C8d0 25bneb_A6EF
$A6CAa5 3eldazp_game_tick
$A6CCc5 50cmpzp_enemy2_spawn_timer
$A6CEd0 1fbneb_A6EF
$A6D0a0 04ldy#$04
$A6D220 87 a8jsrfind_active_entity_by_type
$A6D58atxa
$A6D6d0 08bneb_A6E0
$A6D8a0 02ldy#$02
$A6DA20 87 a8jsrfind_active_entity_by_type
$A6DD8atxa
$A6DEf0 0fbeqb_A6EF
$A6E0a0 03b_A6E0ldy#$03; x-ref: $A6D6
$A6E220 4f a8jsrspawn_entity_init
$A6E5a6 55ldxzp_difficulty_cap
$A6E7bd 3b a8ldaspawn_delay_enemy2_tbl,x
$A6EA18clc
$A6EB65 3eadczp_game_tick
$A6ED85 50stazp_enemy2_spawn_timer
$A6EFa5 30b_A6EFldazp_enemy3_slot_idx; check if enemy 3 is active ; x-ref: $A69E, $A6C3, $A6C8, $A6CE, $A6DE
$A6F1d0 0dbneb_A700
$A6F3a0 04ldy#$04
$A6F520 87 a8jsrfind_active_entity_by_type
$A6F88atxa
$A6F9f0 05beqb_A700
$A6FBa0 02ldy#$02
$A6FD20 4f a8jsrspawn_entity_init
$A700a4 40b_A700ldyzp_entity_count; Y = active enemy count ; x-ref: $A6F1, $A6F9
$A702b9 a2 03b_A702ldaentity_velocity_indices,y; get enemy state from array ; x-ref: $A724
$A70530 1cbmib_A723
$A707b9 3c 03ldaentity_types,y
$A70Aaatax
$A70Ba5 37ldazp_frame_counter
$A70D3d 35 a8andanim_speed_mask_tbl,x
$A710d0 11bneb_A723
$A712b9 4f 03ldaentity_headings,y
$A71518clc
$A71669 01adc#$01
$A718dd 30 a8cmpsprite_frame_limit_tbl,x
$A71B90 03bccb_A720
$A71Dbd 2b a8ldasprite_frame_start_tbl,x
$A72099 13 1db_A720staentity_sprite_frames,y; store calculated sprite frame ; x-ref: $A71B
$A72388b_A723dey; x-ref: $A705, $A710
$A724d0 dcbneb_A702
$A726a6 40ldxzp_entity_count
$A728bd a2 03b_A728ldaentity_velocity_indices,x; x-ref: $A774
$A72B30 46bmib_A773
$A72Dbd 3c 03ldaentity_types,x
$A730a8tay
$A731c9 01cmp#$01
$A733f0 3ebeqb_A773
$A735b9 80 1dldaenemy_speed_masks,y
$A738c9 ffcmp#$ff
$A73Af0 37beqb_A773
$A73C25 37andzp_frame_counter
$A73Ed0 33bneb_A773
$A740bd a2 03ldaentity_velocity_indices,x
$A743a8tay
$A744de b5 03decentity_anim_timers,x
$A747d0 1ebneb_A767
$A749c8iny
$A74A98tya
$A74B29 03and#$03
$A74D9d a2 03staentity_velocity_indices,x
$A750a8tay
$A75118clc
$A752b9 5c 00lda@w zp_wave_vel_y,y
$A755d0 03bneb_A75A
$A757a9 28lda#$28
$A759.byte$2c; bit opcode
$A75Aa9 00b_A75Alda#$00; x-ref: $A755
$A75C69 28adc#$28
$A75E7d 26 1dadcentity_y_center_deltas,x
$A7617d 26 1dadcentity_y_center_deltas,x
$A7649d b5 03staentity_anim_timers,x
$A767b9 57 00b_A767lda@w zp_wave_vel_x,y; x-ref: $A747
$A76A9d c8 03staentity_vx,x
$A76Db9 5c 00lda@w zp_wave_vel_y,y
$A7709d 00 1dstaentity_vy,x
$A773cab_A773dex; x-ref: $A72B, $A733, $A73A, $A73E
$A774d0 b2bneb_A728
$A776a5 37ldazp_frame_counter; load frame counter
$A77825 36andzp_enemy_ai_speed_mask
$A77Ad0 41bneb_A7BD
$A77Ca4 40ldyzp_entity_count
$A77E38b_A77Esec; calculate X distance (enemy - player) ; x-ref: $A7BB
$A77Fb9 62 03ldaentity_x_coords,y
$A782ed 62 03sbcentity_x_coords
$A78590 09bccb_A790
$A78720 9b a8jsrfind_distance_bracket; find distance bracket
$A78Abd 47 a8ldapursuit_neg_velocity_tbl,x
$A78D4c 99 a7jmpj_A799
$A79020 23 aab_A790jsrnegate_a; x-ref: $A785
$A79320 9b a8jsrfind_distance_bracket
$A796bd 4b a8ldapursuit_pos_velocity_tbl,x
$A79999 33 1dj_A799staai_pursuit_vx,y; x-ref: $A78D
$A79C38sec; calculate Y distance (enemy - player)
$A79Db9 75 03ldaentity_y_coords,y
$A7A0ed 75 03sbcentity_y_coords
$A7A390 09bccb_A7AE
$A7A520 9b a8jsrfind_distance_bracket; find distance bracket
$A7A8bd 47 a8ldapursuit_neg_velocity_tbl,x
$A7AB4c b7 a7jmpj_A7B7
$A7AE20 23 aab_A7AEjsrnegate_a; x-ref: $A7A3
$A7B120 9b a8jsrfind_distance_bracket
$A7B4bd 4b a8ldapursuit_pos_velocity_tbl,x
$A7B799 40 1dj_A7B7staai_pursuit_vy,y; x-ref: $A7AB
$A7BA88dey
$A7BBd0 c1bneb_A77E
$A7BDa6 2fb_A7BDldxzp_enemy1_slot_idx; check enemy 1 for firing/sound ; x-ref: $A77A
$A7BFf0 0fbeqb_A7D0
$A7C1a5 38ldazp_enemy1_fire_timer
$A7C3c9 ffcmp#$ff
$A7C5f0 09beqb_A7D0
$A7C725 3eandzp_game_tick
$A7C9d0 05bneb_A7D0
$A7CB86 3bstxzp_firing_entity_slot
$A7CD20 46 afjsrenemy_fire_bullet
$A7D0a6 30b_A7D0ldxzp_enemy3_slot_idx; x-ref: $A7BF, $A7C5, $A7C9
$A7D2f0 0fbeqb_A7E3
$A7D4a5 39ldazp_enemy3_fire_timer
$A7D6c9 ffcmp#$ff
$A7D8f0 09beqb_A7E3
$A7DA25 3eandzp_game_tick
$A7DCd0 05bneb_A7E3
$A7DE86 3bstxzp_firing_entity_slot
$A7E020 46 afjsrenemy_fire_bullet
$A7E3a6 31b_A7E3ldxzp_enemy2_slot_idx; x-ref: $A7D2, $A7D8, $A7DC
$A7E5f0 0fbeqb_A7F6
$A7E7a5 3aldazp_enemy2_fire_timer
$A7E9c9 ffcmp#$ff
$A7EBf0 09beqb_A7F6
$A7ED25 3eandzp_game_tick
$A7EFd0 05bneb_A7F6
$A7F186 3bstxzp_firing_entity_slot
$A7F320 46 afjsrenemy_fire_bullet
$A7F6a6 2fb_A7F6ldxzp_enemy1_slot_idx; x-ref: $A7E5, $A7EB, $A7EF
$A7F8f0 17beqb_A811
$A7FAa5 52ldazp_enemy1_mine_timer
$A7FCc5 3ecmpzp_game_tick
$A7FEd0 11bneb_A811
$A80086 3bstxzp_firing_entity_slot
$A80220 9d afjsrspawn_enemy_mine
$A80518clc
$A806ad 24 91lda$9124
$A80929 7fand#$7f
$A80B09 40ora#$40
$A80D65 3eadczp_game_tick
$A80F85 52stazp_enemy1_mine_timer
$A811a6 30b_A811ldxzp_enemy3_slot_idx; x-ref: $A7F8, $A7FE
$A813f0 15beqr_A82A
$A815a5 53ldazp_enemy3_mine_timer
$A817c5 3ecmpzp_game_tick
$A819d0 0fbner_A82A
$A81B86 3bstxzp_firing_entity_slot
$A81D20 9d afjsrspawn_enemy_mine
$A82018clc
$A821ad 24 91lda$9124
$A82409 c0ora#$c0
$A82665 3eadczp_game_tick
$A82885 53stazp_enemy3_mine_timer
$A82A60r_A82Arts; x-ref: $A813, $A819
; Initial sprite frame per entity type (5 entries, indexed by f033C)
sprite_frame_start_tbl
$A82B.byte$00, $20, $23, $24, $25; x-ref: $A2AF, $A71D, $A85C
; Max sprite frame per entity type; wraps to sprite_frame_start_tbl
sprite_frame_limit_tbl
$A830.byte$1f, $23, $25, $26, $27; x-ref: $A718
; ANDed with frame counter to control animation speed per type
$A835anim_speed_mask_tbl.byte$00, $00, $01, $01, $03, $00; x-ref: $A70D
; Spawn timer delay for enemy 2, indexed by difficulty (250,240,200,150)
spawn_delay_enemy2_tbl
$A83B.byte$fa, $f0, $c8, $96; x-ref: $A6E7
; Spawn timer delay for enemy 1, indexed by difficulty (255,245,205,155)
spawn_delay_enemy1_tbl
$A83F.byte$ff, $f5, $cd, $9b; x-ref: $A6B5
; Distance brackets for enemy AI pursuit (0,40,80,120)
distance_threshold_tbl
$A843.byte$00, $28, $50, $78; x-ref: $A89D
; Pursuit velocity when enemy is ahead of player (0,-2,-3,-3)
pursuit_neg_velocity_tbl
$A847.byte$00, $fe, $fd, $fd; x-ref: $A78A, $A7A8
; Pursuit velocity when enemy is behind player (0,+2,+3,+3)
pursuit_pos_velocity_tbl
$A84B.byte$00, $02, $03, $03; x-ref: $A796, $A7B4
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
; Initializes entity type, starting sprite frame, and tracking indices.
; For type 1 entities, also initializes directional velocity.
;
; Inputs: Y = Entity type, X = Entity slot index
; Outputs: None
; Side Effects: Modifies entity arrays f033C, f1D13, f03C8, f1D00, and f002E
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
$A84F84 51spawn_entity_initstyzp_temp_entity_type; Save requested type ; x-ref: $A6B0, $A6E2, $A6FD
$A851bd 3c 03ldaentity_types,x; Load current type
$A854a8tay
$A855a9 00lda#$00
$A85799 2e 00sta@w zp_entity_type_to_slot,y; Clear tracking for old type
$A85Aa4 51ldyzp_temp_entity_type; Restore requested type
$A85Cb9 2b a8ldasprite_frame_start_tbl,y; Get start frame for type
$A85F9d 13 1dstaentity_sprite_frames,x; Set initial sprite frame
$A86298tya
$A8639d 3c 03staentity_types,x; Set new entity type
$A8668atxa
$A86799 2e 00sta@w zp_entity_type_to_slot,y; Store slot index for this type
$A86Ac0 01cpy#$01; Check if type 1
$A86Cd0 10bner_A87E; Skip velocity init if not type 1
$A86Ebd a2 03ldaentity_velocity_indices,x; Load direction (0-3) from state
$A871a8tay
$A872b9 7f a8ldaspawn_x_velocity_tbl,y; Load X velocity for direction
$A8759d c8 03staentity_vx,x; Set X velocity
$A878b9 83 a8ldaspawn_y_velocity_tbl,y; Load Y velocity for direction
$A87B9d 00 1dstaentity_vy,x; Set Y velocity
$A87E60r_A87Erts; x-ref: $A86C
; Initial X velocity by spawn direction: ↘,↗,↖,↙
$A87Fspawn_x_velocity_tbl.byte$03, $03, $fd, $fd; x-ref: $A872
; Initial Y velocity by spawn direction: ↘,↗,↖,↙
$A883spawn_y_velocity_tbl.byte$03, $fd, $fd, $03; x-ref: $A878
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
; Searches the entity array for an active entity of a given type.
; Scans from index a40 (entity count) down to 1.
;
; Inputs: Y = entity type to search for (1-4)
; Outputs: X = index of matching entity (1-$12), or 0 if not found
; Side Effects: $51 is overwritten with search type
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
find_active_entity_by_type
$A88784 51styzp_temp_entity_type; save entity type to search for ; x-ref: $A6A8, $A6D2, $A6DA, $A6F5
$A889a6 40ldxzp_entity_count; start from total entity count
$A88Bbd a2 03b_A88Bldaentity_velocity_indices,x; check entity state ; x-ref: $A898
$A88E30 07bmib_A897; skip if inactive (bit 7 set)
$A890bd 3c 03ldaentity_types,x; load entity type
$A893c5 51cmpzp_temp_entity_type; matches requested type?
$A895f0 03beqr_A89A; yes, return with X = entity index
$A897cab_A897dex; next entity ; x-ref: $A88E
$A898d0 f1bneb_A88B; loop until X = 0 (not found)
$A89A60r_A89Arts; return: X = entity index or 0 ; x-ref: $A895
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
; Determines a distance bracket index (0-3) by comparing the distance value
; in A against a threshold table. Used by enemy AI to select speed.
;
; Inputs: A = Absolute distance (X or Y)
; Outputs: X = Bracket index (0-3)
; Side Effects: None
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
find_distance_bracket
$A89Ba2 03ldx#$03; Start with highest bracket index (3) ; x-ref: $A787, $A793, $A7A5, $A7B1
$A89Ddd 43 a8b_A89Dcmpdistance_threshold_tbl,x; Compare distance with threshold ; x-ref: $A8A3
$A8A0b0 03bcsr_A8A5; If distance >= threshold, found bracket
$A8A2cadex; Else try next lower bracket
$A8A3d0 f8bneb_A89D; Loop until bracket 0
$A8A560r_A8A5rts; x-ref: $A8A0
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
; Reads and processes joystick input from VIA hardware registers.
;
; Inputs: None
; Outputs: aB0 (Fire pressed = $80)
; aB1 (Right/Up state + player angle)
; aB2 (Left pressed = $80)
; Side Effects: Disables IRQs to safely read VIA2 Port B (Right direction),
; then reads VIA1 Port A (Up/Down/Left/Fire) with a debounce loop.
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
$A8A678read_joysticksei; x-ref: $B3D5, $B407, $B40C
$A8A7a2 7fldx#$7f
$A8A98e 22 91stx$9122; configure VIA2 DDRB
$A8ACad 20 91lda$9120
$A8AFa2 00ldx#$00
$A8B129 80and#$80; read Joy Right (bit 7)
$A8B3d0 02bneb_A8B7
$A8B5a2 ffldx#$ff
$A8B786 b1b_A8B7stxzp_player_angle; x-ref: $A8B3
$A8B9a2 ffldx#$ff
$A8BB8e 22 91stx$9122
$A8BEa2 f7ldx#$f7
$A8C08e 20 91stx$9120
$A8C358cli
$A8C4ad 11 91b_A8C4lda$9111; read VIA1 Port A (Up/Down/Left/Fire) ; x-ref: $A8CA
$A8C7cd 11 91cmp$9111
$A8CAd0 f8bneb_A8C4; debounce loop
$A8CC29 3eand#$3e
$A8CEc9 1fcmp#$1f; check if Fire (bit 5) is pressed
$A8D0b0 04bcsb_A8D6
$A8D2a2 80ldx#$80
$A8D4d0 0abneb_A8E0
$A8D624 b0b_A8D6bitzp_joy_fire; x-ref: $A8D0
$A8D810 04bplb_A8DE
$A8DAa2 80ldx#$80
$A8DC86 35stxzp_fire_cooldown
$A8DEa2 00b_A8DEldx#$00; x-ref: $A8D8
$A8E086 b0b_A8E0stxzp_joy_fire; store Fire button state ; x-ref: $A8D4
$A8E229 1fand#$1f
$A8E4c9 0fcmp#$0f; check if Up (bit 4) is pressed
$A8E6b0 04bcsb_A8EC
$A8E8a2 01ldx#$01
$A8EA86 b1stxzp_player_angle
$A8ECa2 00b_A8ECldx#$00; x-ref: $A8E6
$A8EE29 04and#$04; check if Left (bit 2) is pressed
$A8F0d0 02bneb_A8F4
$A8F2a2 80ldx#$80
$A8F486 b2b_A8F4stxzp_joy_left; x-ref: $A8F0
$A8F618clc
$A8F7a5 b1ldazp_player_angle
$A8F96d 4f 03adcentity_headings; apply turning offset to player angle
$A8FC29 0fand#$0f
$A8FE85 b1stazp_player_angle
$A90060rts
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
; Reads analog paddle and fire button to update player angle and fire state.
; Maps the 0-255 paddle value to a 0-15 angle index using thresholds.
; Checks bit 4 of VIA1 Port A for the fire button.
;
; Inputs: $9008 (Paddle value), $9111 (VIA1 Port A)
; Outputs: aB1 = Player angle (0-15), aB0 = Fire flag ($80 if pressed)
; Side Effects: Updates state variables aB2, a29, a35
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
$A901a2 10read_paddle_inputldx#$10; Start with highest angle index (16) ; x-ref: $B3DC, $B3F7, $B3FC
$A903ad 08 90lda$9008; Read analog paddle value
$A906dd 59 a9b_A906cmppaddle_angle_thresholds,x; Compare with threshold ; x-ref: $A90C
$A909b0 05bcsb_A910; If paddle >= threshold, found angle
$A90Bcadex; Else try next lower angle
$A90C10 f8bplb_A906
$A90E30 05bmib_A915
$A9108ab_A910txa; Use index as angle ; x-ref: $A909
$A91129 0fand#$0f; Mask to 4 bits (0-15)
$A91385 b1stazp_player_angle; Store player angle
$A915ad 11 91b_A915lda$9111; Read fire button (VIA1 Port A) ; x-ref: $A90E
$A91829 10and#$10; Check bit 4
$A91Af0 1bbeqb_A937; Branch if button pressed (active low)
$A91Ca9 00lda#$00
$A91E85 b2stazp_joy_left
$A920a5 b0ldazp_joy_fire
$A922f0 0abeqb_A92E
$A924a5 29ldazp_prev_heading
$A926c5 37cmpzp_frame_counter
$A928f0 04beqb_A92E
$A92Aa9 80lda#$80
$A92C85 35stazp_fire_cooldown
$A92Ea5 37b_A92Eldazp_frame_counter; x-ref: $A922, $A928
$A93085 29stazp_prev_heading
$A932a9 00lda#$00
$A93485 b0stazp_joy_fire
$A93660rts
$A937a5 b2b_A937ldazp_joy_left; x-ref: $A91A
$A93930 14bmir_A94F
$A93Ba5 b0ldazp_joy_fire
$A93Df0 11beqb_A950
$A93Fa5 29ldazp_prev_heading
$A941c5 37cmpzp_frame_counter
$A943d0 0abner_A94F
$A945a9 00lda#$00
$A94785 b0stazp_joy_fire
$A949a9 80lda#$80
$A94B85 29stazp_prev_heading
$A94D85 b2stazp_joy_left
$A94F60r_A94Frts; x-ref: $A939, $A943
$A950a9 80b_A950lda#$80; Set fire flag ($80) ; x-ref: $A93D
$A95285 b0stazp_joy_fire
$A954a5 37ldazp_frame_counter
$A95685 29stazp_prev_heading
$A95860rts
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
; Analog Paddle to Player Angle Threshold Table
; Because the original arcade game used a rotary controller, the VIC-20 port
; supports the Commodore Paddle. This 17-byte table divides the 0-255 analog
; paddle reading ($9008) into 16 evenly spaced intervals (0-15). The paddle
; routine compares the analog reading against this table from top to bottom
; to determine which of the 16 rotational angles the player's ship should face.
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
paddle_angle_thresholds
$A959.byte$00, $0f, $1e, $2d, $3c, $4b, $5a, $69; x-ref: $A906
$A961.byte$78, $87, $96, $a5, $b4, $c3, $d2, $e1
$A969.byte$f0
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
; Applies boundary collisions (outer screen walls and inner central box).
;
; Inputs: aA3, aA4 (X, Y position)
; aAE, aAF (X, Y velocity)
; Outputs: a18 (Collision flag: 0=none, >0 indicates which wall was hit)
; Side Effects: Clamps the X/Y position to keep the entity in bounds. If a wall
; or the central box is hit, the corresponding X or Y velocity
; vector is negated (Two's Complement) to produce a bounce effect.
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
check_boundary_collisions
$A96Aa9 80lda#$80; initialize wall hit flag ; x-ref: $AB7C, $AF7E
$A96C.byte$2c; bit opcode
check_boundary_collisions_narrow
$A96Da9 00lda#$00; Set narrow boundary flag ($00) ; x-ref: $AB09, $AB47
$A96F85 61stazp_wide_boundary_flag; Store in flag
$A971a9 00lda#$00; clear collision flag
$A97385 18stazp_collision_type
$A975a5 a3ldazp_pos_x
$A977c9 f8cmp#$f8
$A979b0 2abcsb_A9A5; check left outer screen boundary
$A97B24 61bitzp_wide_boundary_flag; N=1 ($80) -> use wide boundary zones (ship pixel); N=0 ($00) -> narrow (sprites)
$A97D10 06bplb_A985
$A97Fc9 9dcmp#$9d
$A981b0 34bcsb_A9B7; check right outer screen boundary
$A98390 04bccb_A989
$A985c9 97b_A985cmp#$97; x-ref: $A97D
$A987b0 2ebcsb_A9B7
$A989c9 79b_A989cmp#$79; check right side of inner box ; x-ref: $A983
$A98Bb0 43bcsb_A9D0
$A98Dc9 75cmp#$75
$A98Fb0 38bcsb_A9C9
$A99124 61bitzp_wide_boundary_flag
$A99310 04bplb_A999
$A995c9 28cmp#$28
$A99790 37bccb_A9D0
$A999c9 20b_A999cmp#$20; check left side of inner box ; x-ref: $A993
$A99Bb0 2fbcsb_A9CC
$A99Dc9 01cmp#$01
$A99Fb0 2fbcsb_A9D0
$A9A1c9 01cmp#$01
$A9A3b0 2bbcsb_A9D0
$A9A5a5 a4b_A9A5ldazp_pos_y; x-ref: $A979
$A9A7a0 07ldy#$07
$A9A9c9 50cmp#$50
$A9ABb0 01bcsb_A9AE
$A9ADc8iny
$A9AE84 18b_A9AEstyzp_collision_type; x-ref: $A9AB
$A9B0a9 02lda#$02; clamp X to left edge
$A9B285 a3stazp_pos_x
$A9B44c 77 aajmpj_AA77; bounce (negate X velocity)
$A9B7a5 a4b_A9B7ldazp_pos_y; x-ref: $A981, $A987
$A9B9a0 03ldy#$03
$A9BBc9 50cmp#$50
$A9BD90 01bccb_A9C0
$A9BFc8iny
$A9C084 18b_A9C0styzp_collision_type; x-ref: $A9BD
$A9C2a9 95lda#$95; clamp X to right edge
$A9C485 a3stazp_pos_x
$A9C64c 77 aajmpj_AA77; bounce (negate X velocity)
$A9C9a9 feb_A9C9lda#$fe; x-ref: $A98F
$A9CB.byte$2c; bit opcode
$A9CCa9 fcb_A9CClda#$fc; x-ref: $A99B
$A9CE85 18stazp_collision_type
$A9D0a5 a4b_A9D0ldazp_pos_y; x-ref: $A98B, $A997, $A99F, $A9A3
$A9D2c9 f8cmp#$f8
$A9D4b0 22bcsb_A9F8; check top outer screen boundary
$A9D624 61bitzp_wide_boundary_flag
$A9D810 06bplb_A9E0
$A9DAc9 9dcmp#$9d
$A9DCb0 33bcsb_AA11
$A9DE90 04bccb_A9E4
$A9E0c9 97b_A9E0cmp#$97; x-ref: $A9D8
$A9E2b0 2dbcsb_AA11
$A9E4c9 65b_A9E4cmp#$65; x-ref: $A9DE
$A9E6b0 22bcsb_AA0A
$A9E824 61bitzp_wide_boundary_flag
$A9EA10 04bplb_A9F0
$A9ECc9 3ccmp#$3c
$A9EE90 1abccb_AA0A
$A9F0c9 34b_A9F0cmp#$34; x-ref: $A9EA
$A9F2b0 35bcsb_AA29
$A9F4c9 01cmp#$01
$A9F6b0 12bcsb_AA0A
$A9F8a5 a3b_A9F8ldazp_pos_x; x-ref: $A9D4
$A9FAa0 01ldy#$01
$A9FCc9 50cmp#$50
$A9FE90 01bccb_AA01
$AA00c8iny
$AA0184 18b_AA01styzp_collision_type; x-ref: $A9FE
$AA03a9 02lda#$02; clamp Y to top edge
$AA0585 a4stazp_pos_y
$AA074c 6d aajmpj_AA6D; bounce (negate Y velocity)
$AA0Aa9 00b_AA0Alda#$00; x-ref: $A9E6, $A9EE, $A9F6, $AA2B
$AA0C85 18stazp_collision_type
$AA0E4c ac aajmpcalc_bitmap_pointers
$AA11a5 a3b_AA11ldazp_pos_x; x-ref: $A9DC, $A9E2
$AA13a0 05ldy#$05
$AA15c9 50cmp#$50
$AA17b0 01bcsb_AA1A
$AA19c8iny
$AA1A84 18b_AA1Astyzp_collision_type; hit bottom wall flag ; x-ref: $AA17
$AA1Ca9 94lda#$94; clamp Y to bottom edge
$AA1E85 a4stazp_pos_y
$AA204c 6d aajmpj_AA6D; bounce (negate Y velocity)
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
; Negates the accumulator using two's complement (A = -A).
; Used for velocity bouncing and distance sign flipping.
;
; Inputs: A = signed 8-bit value
; Outputs: A = negated value
; Side Effects: Carry flag modified
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
$AA2349 ffnegate_aeor#$ff; one's complement ; x-ref: $A790, $A7AE, $AA6F, $AA79
$AA2518clc
$AA2669 01adc#$01; +1 = two's complement
$AA2860rts
$AA29a5 18b_AA29ldazp_collision_type; handle inner box collisions ; x-ref: $A9F2
$AA2B10 ddbplb_AA0A
$AA2Dc9 fccmp#$fc
$AA2Fd0 12bneb_AA43
$AA31a5 a3ldazp_pos_x
$AA33c9 25cmp#$25
$AA35b0 18bcsb_AA4F
$AA3724 61bitzp_wide_boundary_flag
$AA3910 04bplb_AA3F
$AA3Ba9 25lda#$25
$AA3Dd0 0cbneb_AA4B
$AA3Fa9 20b_AA3Flda#$20; x-ref: $AA39
$AA41d0 08bneb_AA4B
$AA43a5 a3b_AA43ldazp_pos_x; x-ref: $AA2F
$AA45c9 76cmp#$76
$AA4790 06bccb_AA4F
$AA49a9 79lda#$79
$AA4B85 a3b_AA4Bstazp_pos_x; x-ref: $AA3D, $AA41
$AA4Dd0 28bnej_AA77
$AA4Fa5 a4b_AA4Fldazp_pos_y; x-ref: $AA35, $AA47
$AA51c9 50cmp#$50
$AA53b0 10bcsb_AA65
$AA55a9 fflda#$ff
$AA5785 18stazp_collision_type
$AA5924 61bitzp_wide_boundary_flag
$AA5B10 04bplb_AA61
$AA5Da9 3clda#$3c
$AA5Fd0 0abneb_AA6B
$AA61a9 34b_AA61lda#$34; x-ref: $AA5B
$AA63d0 06bneb_AA6B
$AA65a9 fdb_AA65lda#$fd; x-ref: $AA53
$AA6785 18stazp_collision_type
$AA69a9 65lda#$65
$AA6B85 a4b_AA6Bstazp_pos_y; x-ref: $AA5F, $AA63
$AA6Da5 afj_AA6Dldazp_step_y; negate Y velocity ; x-ref: $AA07, $AA20
$AA6F20 23 aajsrnegate_a
$AA7285 afstazp_step_y
$AA744c 7e aajmpj_AA7E
$AA77a5 aej_AA77ldazp_step_x; negate X velocity ; x-ref: $A9B4, $A9C6, $AA4D
$AA7920 23 aajsrnegate_a
$AA7C85 aestazp_step_x
$AA7Ea5 2bj_AA7Eldazp_player_wall_hits; x-ref: $AA74
$AA80d0 2abnecalc_bitmap_pointers
$AA82a5 aeldazp_step_x
$AA84f0 11beqb_AA97
$AA8630 09bmib_AA91
$AA88c9 01cmp#$01
$AA8Af0 0bbeqb_AA97
$AA8Cc6 aedeczp_step_x
$AA8E4c 97 aajmpb_AA97
$AA91c9 ffb_AA91cmp#$ff; x-ref: $AA86
$AA93f0 02beqb_AA97
$AA95e6 aeinczp_step_x
$AA97a5 afb_AA97ldazp_step_y; x-ref: $AA84, $AA8A, $AA8E, $AA93
$AA99f0 11beqcalc_bitmap_pointers
$AA9B30 09bmib_AAA6
$AA9Dc9 01cmp#$01
$AA9Ff0 0bbeqcalc_bitmap_pointers
$AAA1c6 afdeczp_step_y
$AAA34c ac aajmpcalc_bitmap_pointers
$AAA6c9 ffb_AAA6cmp#$ff; x-ref: $AA9B
$AAA8f0 02beqcalc_bitmap_pointers
$AAAAe6 afinczp_step_y
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
; Calculates memory pointers for drawing to the custom VIC-20 bitmap.
;
; Inputs: aA3 (X coordinate), aA4 (Y coordinate)
; Outputs: aAD (Bit shift offset: X % 8)
; aA5/aA6 (Pointer to the byte containing the target pixel)
; aA7/aA8 (Pointer to the adjacent column, 160 bytes ahead)
; Side Effects: None. Omega Race implements a custom bitmap by arranging the
; VIC-I character map into columns. This routine uses a lookup
; table to find the base address of the column (X / 8), adds the
; Y coordinate, and calculates pointers for rendering.
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
$AAAC18calc_bitmap_pointersclc; x-ref: $AA0E, $AA80, $AA99, $AA9F, $AAA3, $AAA8, $AAFF, $AB41, ...
$AAADa5 a3ldazp_pos_x; load X coordinate
$AAAF29 07and#$07; extract bit offset (X % 8)
$AAB185 adstazp_spr_bit_offset; save bit offset
$AAB3a5 a3ldazp_pos_x
$AAB54alsra
$AAB64alsra
$AAB729 feand#$fe; calculate table index (X / 8) * 2
$AAB9aatax
$AABA18clc
$AABBbd d7 aaldabitmap_column_addresses_lo,x; load column base address low byte
$AABE65 a4adczp_pos_y; add Y coordinate to base address
$AAC085 a5stazp_ptr_bmp_col_lo; store pointer low
$AAC2bd d8 aaldabitmap_colum_addresses_hi,x; load column base address high byte
$AAC569 00adc#$00; add carry
$AAC785 a6stazp_ptr_bmp_col_hi; store pointer high
$AAC918clc
$AACAa5 a5ldazp_ptr_bmp_col_lo
$AACC69 a0adc#$a0; add 160 (bytes per column) to low byte
$AACE85 a7stazp_ptr_bmp_spill_lo; store adjacent column pointer low
$AAD0a5 a6ldazp_ptr_bmp_col_hi
$AAD269 00adc#$00
$AAD485 a8stazp_ptr_bmp_spill_hi; store adjacent column pointer high
$AAD660rts
bitmap_colum_addresses_hi =*+$01 ; x-ref: $AAC2
bitmap_column_addresses_lo
$AAD7.wordBITMAP_COL0, BITMAP_COL1, BITMAP_COL2, BITMAP_COL3, BITMAP_COL4; x-ref: $AABB
$AAE1.wordBITMAP_COL5, BITMAP_COL6, BITMAP_COL7, BITMAP_COL8, BITMAP_COL9
$AAEB.wordBITMAP_COL10, BITMAP_COL11, BITMAP_COL12, BITMAP_COL13, BITMAP_COL14
$AAF5.wordBITMAP_COL15, BITMAP_COL16, BITMAP_COL17, BITMAP_COL18, BITMAP_COL19
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
; Stamps an 8x8 sprite/glyph shape onto the custom bitmap using OR, and
; accumulates pixel-overlap collision data into collision_check_flag.
; The glyph shape (8 bytes) is read from (pA9),Y for rows Y=7..0. Each row
; byte is right-shifted by aAD bits, producing a high-column mask (in A) and
; a spill-column mask (in aAC). Both are OR-ed into the bitmap columns at
; (aA5),Y and (aA7),Y. Before OR-ing, the old bitmap byte is AND-ed with the
; new mask: any non-zero result means pixels were already set -> collision,
; accumulated into collision_check_flag.
; Does NOT clear collision_check_flag or run boundary checks on entry.
; See draw_sprite_with_collision_check ($AB05) for the full-entry variant.
;
; Inputs: pA9/aAA = pointer to 8-byte glyph shape
; aA5/aA6 = pointer to high bitmap column
; aA7/aA8 = pointer to adjacent (spill) bitmap column
; aAD = right-shift count (0..7, X sub-byte pixel offset)
; collision_check_flag = running accumulator (caller-managed)
; Outputs: Bitmap updated (sprite pixels OR-ed in)
; collision_check_flag |= (old_bitmap AND sprite_mask)
; Side Effects: Overwrites aAB, aAC (temporary shift registers)
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
draw_sprite_or_collision
$AAFF20 ac aajsrcalc_bitmap_pointers; x-ref: $AD42, $AD8B, $ADA3, $B2FC, $B358, $B388, $B3A2
$AB024c 0c abjmpj_AB0C
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
; Full-entry variant of draw_sprite_or_collision. Before stamping the sprite:
; 1. Clears collision_check_flag to $00 (fresh collision test).
; 2. Calls sA96D to check X-axis boundary collisions vs the playfield walls;
; sA96D may clamp aA3 and set collision_type if a wall is hit.
; Then falls through into the shared draw loop at jAB0C.
; Use this entry when rendering a moving entity that needs both pixel-collision
; detection (vs other sprites) and wall-boundary clamping.
;
; Inputs: aA3 = X coordinate, aA4 = Y coordinate
; pA9/aAA = pointer to 8-byte glyph shape
; aAD = right-shift count (0..7)
; Outputs: Bitmap updated; collision_check_flag set if any overlap detected
; collision_type set if a wall boundary was hit (via sA96D)
; Side Effects: Clears then rebuilds collision_check_flag; may modify aA3
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
draw_sprite_with_collision_check
$AB05a9 00lda#$00; x-ref: $A5DB, $B00E, $B045
$AB0785 1bstazp_collision_check_flag
$AB0920 6d a9jsrcheck_boundary_collisions_narrow
$AB0Ca0 07j_AB0Cldy#$07; x-ref: $AB02
$AB0Eb1 a9b_AB0Elda(zp_ptr_glyph),y; x-ref: $AB3E
$AB10a2 00ldx#$00
$AB1286 acstxzp_spr_spill_mask
$AB14a6 adldxzp_spr_bit_offset
$AB16f0 07beqb_AB1F
$AB1818b_AB18clc; x-ref: $AB1D
$AB194alsra
$AB1A66 acrorzp_spr_spill_mask
$AB1Ccadex
$AB1Dd0 f9bneb_AB18
$AB1F85 abb_AB1Fstazp_spr_row_mask; x-ref: $AB16
$AB21b1 a5lda(zp_ptr_bmp_col_lo),y
$AB23aatax
$AB2425 abandzp_spr_row_mask
$AB2605 1borazp_collision_check_flag
$AB2885 1bstazp_collision_check_flag
$AB2A8atxa
$AB2B05 aborazp_spr_row_mask
$AB2D91 a5sta(zp_ptr_bmp_col_lo),y
$AB2Fb1 a7lda(zp_ptr_bmp_spill_lo),y
$AB31aatax
$AB3225 acandzp_spr_spill_mask
$AB3405 1borazp_collision_check_flag
$AB3685 1bstazp_collision_check_flag
$AB388atxa
$AB3905 acorazp_spr_spill_mask
$AB3B91 a7sta(zp_ptr_bmp_spill_lo),y
$AB3D88dey
$AB3E10 cebplb_AB0E
$AB4060rts
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
; Erases an 8x8 sprite/glyph from the custom bitmap using AND-NOT masking.
; The glyph shape (8 bytes) is read from (pA9),Y for rows Y=7..0. Each row
; byte is inverted (EOR #$FF) to form a clear-mask (0=erase this pixel,
; 1=leave alone), then right-shifted by aAD bits using SEC/ROR so that 1-bits
; fill in from the left, preserving non-sprite pixels in the shift region.
; The shifted masks are AND-ed into bitmap columns (aA5),Y and (aA7),Y,
; clearing only the pixels that belong to this sprite without disturbing
; any other content already on the bitmap.
; Does NOT modify collision_check_flag.
; See erase_sprite_with_boundary_check ($AB47) for the boundary variant.
;
; Inputs: pA9/aAA = pointer to 8-byte glyph shape
; aA5/aA6 = pointer to high bitmap column
; aA7/aA8 = pointer to adjacent (spill) bitmap column
; aAD = right-shift count (0..7)
; Outputs: Bitmap updated (sprite pixels cleared)
; Side Effects: Overwrites aAC (temporary shift register)
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
$AB4120 ac aaerase_spritejsrcalc_bitmap_pointers; x-ref: $A5B9, $AD5F, $ADB5, $B346
$AB444c 4a abjmpj_AB4A
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
; Boundary-checking variant of erase_sprite. Before erasing, calls sA96D to
; check X-axis boundary collisions vs the playfield walls; sA96D may clamp
; aA3 and set collision_type if a wall is hit. Then falls through into the
; shared erase loop at jAB4A.
; Use this entry when erasing a moving entity whose position may be at or
; beyond a screen boundary at the time of the erase.
;
; Inputs: aA3 = X coordinate, aA4 = Y coordinate
; pA9/aAA = pointer to 8-byte glyph shape
; aAD = right-shift count (0..7)
; Outputs: Bitmap updated (sprite pixels cleared)
; collision_type set if a wall boundary was hit (via sA96D)
; Side Effects: May modify aA3 (clamped by sA96D); overwrites aAC
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
erase_sprite_with_boundary_check
$AB4720 6d a9jsrcheck_boundary_collisions_narrow; x-ref: $B199, $B1C0
$AB4Aa0 07j_AB4Aldy#$07; x-ref: $AB44
$AB4Cb1 a9b_AB4Clda(zp_ptr_glyph),y; x-ref: $AB6A
$AB4E49 ffeor#$ff
$AB50a2 ffldx#$ff
$AB5286 acstxzp_spr_spill_mask
$AB54a6 adldxzp_spr_bit_offset
$AB56f0 07beqb_AB5F
$AB5838b_AB58sec; x-ref: $AB5D
$AB596arora
$AB5A66 acrorzp_spr_spill_mask
$AB5Ccadex
$AB5Dd0 f9bneb_AB58
$AB5F31 a5b_AB5Fand(zp_ptr_bmp_col_lo),y; x-ref: $AB56
$AB6191 a5sta(zp_ptr_bmp_col_lo),y
$AB63a5 acldazp_spr_spill_mask
$AB6531 a7and(zp_ptr_bmp_spill_lo),y
$AB6791 a7sta(zp_ptr_bmp_spill_lo),y
$AB6988dey
$AB6A10 e0bplb_AB4C
$AB6C60rts
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
; Sets a pixel in the custom bitmap at position (aA3, aA4).
;
; Inputs: aA3 = X coordinate, aA4 = Y coordinate
; Outputs: Pixel set in bitmap memory
; Side Effects: Modifies bitmap memory via (aA5) pointer
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
$AB6D20 ac aaplot_pixeljsrcalc_bitmap_pointers; compute bitmap pointer for (aA3,aA4) ; x-ref: $ABB8, $ABDE
$AB70a6 adldxzp_spr_bit_offset; bit offset (X % 8)
$AB72bd 93 abldabit_mask_tbl,x; load bit mask for target pixel
$AB75a2 00ldx#$00
$AB7701 a5ora(zp_ptr_bmp_col_lo,x); OR pixel into bitmap byte
$AB7981 a5sta(zp_ptr_bmp_col_lo,x); write back
$AB7B60rts
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
; Clears a pixel after applying boundary collision checks.
; Bounces velocity if a wall is hit, then clears the pixel.
;
; Inputs: aA3/aA4 = position, aAE/aAF = X/Y velocity
; Outputs: Pixel cleared, position clamped, velocity bounced
; Side Effects: Modifies bitmap memory, may negate velocity
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
clear_pixel_with_bounce
$AB7C20 6a a9jsrcheck_boundary_collisions; clamp position, bounce velocity ; x-ref: $AF05
$AB7F4c 85 abjmpj_AB85
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
; Clears a pixel in the custom bitmap at position (aA3, aA4).
;
; Inputs: aA3 = X coordinate, aA4 = Y coordinate
; Outputs: Pixel cleared in bitmap memory
; Side Effects: Modifies bitmap memory via (aA5) pointer
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
$AB8220 ac aaclear_pixeljsrcalc_bitmap_pointers; x-ref: $AC53
$AB85a6 adj_AB85ldxzp_spr_bit_offset; bit offset (X % 8) ; x-ref: $AB7F
$AB87bd 93 abldabit_mask_tbl,x; load bit mask for target pixel
$AB8Aa2 00ldx#$00
$AB8C49 ffeor#$ff; invert mask
$AB8E21 a5and(zp_ptr_bmp_col_lo,x); AND to clear pixel
$AB9081 a5sta(zp_ptr_bmp_col_lo,x); write back
$AB9260rts
; Bit mask lookup: index 0=$80, 1=$40, 2=$20 ... 7=$01
$AB93bit_mask_tbl.byte$80, $40, $20, $10, $08, $04, $02, $01; x-ref: $A544, $AB72, $AB87, $AE99, $AF87
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
; Converts a sprite/glyph frame index (in A) into a 16-bit pointer to the
; corresponding 8x8 pixel shape in the ROM glyph table at $B496, and stores
; the result in the Zero Page pointer pA9/aAA for use by the draw routine.
;
; Formula: pointer = $B496 + (A * 8)
;
; The index is multiplied by 8 (3 ASL+ROL pairs to propagate carry into the
; high byte), then the base address $B496 is added. Always called immediately
; before sAAFF, which reads (pA9),Y to stamp the 8 bytes into the bitmap.
;
; Inputs: A = sprite/glyph frame index (0-based)
; Outputs: pA9/aAA = 16-bit pointer to the 8-byte shape in ROM
; Side Effects: Overwrites a2A (temp copy of index)
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
$AB9B85 2acalc_sprite_ptrstazp_temp_frame_idx; save frame index; A = sprite/glyph frame index ; x-ref: $A5AC, $A5CE, $AD3F, $AD50, $AD6E, $ADA0, $ADB2, $B00B, ...
$AB9Da9 00lda#$00; clear high byte of 16-bit product
$AB9F85 aastazp_ptr_glyph_hi
$ABA1a5 2aldazp_temp_frame_idx; A *= 2 (shift 1)
$ABA30aasla
$ABA426 aarolzp_ptr_glyph_hi; A *= 4 (shift 2)
$ABA60aasla
$ABA726 aarolzp_ptr_glyph_hi; A *= 8 (shift 3) — final byte offset = index * 8
$ABA90aasla
$ABAA26 aarolzp_ptr_glyph_hi
$ABAC18clc
$ABAD69 96adc#$96; store pointer low into pA9
$ABAF85 a9stazp_ptr_glyph; load high byte of product
$ABB1a5 aaldazp_ptr_glyph_hi; add glyph table base high byte ($B4) + carry
$ABB369 b4adc#$b4; store pointer high into aAA; pA9/aAA now points to glyph shape
$ABB585 aastazp_ptr_glyph_hi
$ABB760rts
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
; Draws a line segment by plotting pixels and stepping by dx, dy.
; Loops until the length counter reaches zero.
;
; Inputs: aA3/aA4 = Start X/Y, aAE/aAF = dx/dy, aBD = length
; Outputs: None
; Side Effects: Modifies the bitmap
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
$ABB820 6d abdraw_line_segmentjsrplot_pixel; x-ref: $ABCB, $AC73
$ABBB18clc
$ABBCa5 a3ldazp_pos_x
$ABBE65 aeadczp_step_x
$ABC085 a3stazp_pos_x
$ABC218clc
$ABC3a5 a4ldazp_pos_y
$ABC565 afadczp_step_y
$ABC785 a4stazp_pos_y
$ABC9c6 bddeczp_seg_len
$ABCBd0 ebbnedraw_line_segment
$ABCD60rts
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
; Plots 8 pixels at the corners and midpoints of the playfield area to act
; as visual markers.
;
; Inputs: None
; Outputs: None
; Side Effects: Modifies character bitmap by setting 8 specific pixels.
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
$ABCEa0 07draw_markersldy#$07; Init loop counter for 8 dots ; x-ref: $A36A, $A659, $B22F, $B24F, $B269
$ABD084 1astyzp_marker_idx
$ABD2a4 1ab_ABD2ldyzp_marker_idx; x-ref: $ABE3
$ABD4b9 e6 abldamarker_x_coords,y; Load X coordinate
$ABD785 a3stazp_pos_x
$ABD9b9 ee abldamarker_y_coords,y; Load Y coordinate
$ABDC85 a4stazp_pos_y
$ABDE20 6d abjsrplot_pixel; Plot pixel
$ABE1c6 1adeczp_marker_idx
$ABE310 edbplb_ABD2
$ABE560rts
$ABE6marker_x_coords.byte$00, $50, $9f, $00, $9f, $00, $50, $9f; x-ref: $ABD4
$ABEEmarker_y_coords.byte$00, $00, $00, $50, $50, $9f, $9f, $9f; x-ref: $ABD9
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
; Erases the arena border from the bitmap. Mirror of draw_arena_border — iterates
; through 8 line segments, clearing pixels using erase_border_segment (sAC77).
; Called during level init before the border is redrawn.
;
; Inputs: None
; Outputs: None
; Side Effects: Clears border pixels from character bitmap ($1000-$1CFF)
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
$ABF6a9 08erase_arena_borderlda#$08; init segment counter = 8 ; x-ref: $A367
$ABF885 3cstazp_attract_delay_ctr
$ABFAa5 3cb_ABFAldazp_attract_delay_ctr; loop — erase one border segment per pass ; x-ref: $AC01
$ABFC20 77 acjsrerase_border_segment; erase segment at current counter index
$ABFFc6 3cdeczp_attract_delay_ctr; decrement segment counter
$AC01d0 f7bneb_ABFA
$AC0360rts
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
; Draws the playfield arena border onto the custom VIC-20 bitmap. Iterates
; through 13 line segments, rendering each using parameters from the
; border_segment_table (fACA0).
;
; Inputs: None
; Outputs: None
; Side Effects: Writes pixels to character bitmap ($1000-$1CFF)
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
$AC04a9 08draw_arena_borderlda#$08; init segment counter = 8 (counts down to $FB) ; x-ref: $A358
$AC0685 3cstazp_attract_delay_ctr
$AC08a5 3cj_AC08ldazp_attract_delay_ctr; loop — draw one border segment per pass ; x-ref: $AC13
$AC0Ac9 fbcmp#$fb; stop when counter reaches $FB
$AC0Cf0 08beqr_AC16
$AC0E20 69 acjsrdraw_border_segment; draw segment at current counter index
$AC11c6 3cdeczp_attract_delay_ctr; decrement segment counter
$AC134c 08 acjmpj_AC08
$AC1660r_AC16rts; x-ref: $AC0C
; Flat array of 5-byte segment records for arena border drawing.
; Each record defines one line segment (start pos, length, step direction):
; +0: X start +1: Y start +2: pixel count +3: X step +4: Y step
; Indexed via offsets from border_segment_tbl.
border_segment_params
$AC17.byte$00; x-ref: $AC86
border_segment_y_start
$AC18.byte$00; x-ref: $AC8B
$AC19border_segment_len.byte$4f; x-ref: $AC90
$AC1Aborder_segment_dx.byte$01; x-ref: $AC95
$AC1Bborder_segment_dy.byte$00, $50, $00, $4f, $01, $00, $00, $9f; x-ref: $AC9A
$AC23.byte$4f, $01, $00, $50, $9f, $4f, $01, $00
$AC2B.byte$28, $3c, $50, $01, $00, $28, $64, $50
$AC33.byte$01, $00, $00, $00, $4f, $00, $01, $00
$AC3B.byte$50, $4f, $00, $01, $9f, $00, $4f, $00
$AC43.byte$01, $9f, $50, $4f, $00, $01, $28, $3c
$AC4B.byte$28, $00, $01, $78, $3c, $28, $00, $01
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
; Erases a line segment by clearing pixels and stepping by dx, dy.
; Loops until the length counter reaches zero.
;
; Inputs: aA3/aA4 = Start X/Y, aAE/aAF = dx/dy, aBD = length
; Outputs: None
; Side Effects: Modifies the bitmap
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
$AC5320 82 aberase_line_segmentjsrclear_pixel; x-ref: $AC66, $AC81
$AC5618clc
$AC57a5 a3ldazp_pos_x
$AC5965 aeadczp_step_x
$AC5B85 a3stazp_pos_x
$AC5D18clc
$AC5Ea5 a4ldazp_pos_y
$AC6065 afadczp_step_y
$AC6285 a4stazp_pos_y
$AC64c6 bddeczp_seg_len
$AC66d0 ebbneerase_line_segment
$AC6860rts
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
; Draws a specific playfield border segment based on an index passed in A.
; Uses border_segment_tbl to look up parameters and calls draw_line_segment.
;
; Inputs: A = Segment index
; Outputs: None
; Side Effects: Modifies the bitmap to draw the segment
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
$AC6918draw_border_segmentclc; Clear carry for addition ; x-ref: $A614, $A620, $AC0E, $AE88, $AEBA
$AC6A69 04adc#$04; Add 4 to index (bias for table)
$AC6Ca8tay; Use as Y index
$AC6Db9 a0 acldaborder_segment_tbl,y; Get offset from table
$AC7020 85 acjsrload_segment_params; Load segment parameters (X, Y, len, dx, dy)
$AC7320 b8 abjsrdraw_line_segment; Draw the line segment
$AC7660rts
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
; Erases a specific playfield border segment based on an index passed in A.
; Uses border_segment_tbl to look up parameters and calls erase_line_segment.
;
; Inputs: A = Segment index
; Outputs: None
; Side Effects: Modifies the bitmap to clear the segment
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
$AC7718erase_border_segmentclc; Clear carry for addition ; x-ref: $A619, $ABFC, $AE8D
$AC7869 04adc#$04; Add 4 to index (bias for table)
$AC7Aa8tay; Use as Y index
$AC7Bb9 a0 acldaborder_segment_tbl,y; Get offset from table
$AC7E20 85 acjsrload_segment_params; Load segment parameters (X, Y, len, dx, dy)
$AC8120 53 acjsrerase_line_segment; Erase the line segment
$AC8460rts
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
; Loads segment parameters (X, Y, length, dx, dy) from tables into Zero Page.
; Indexed by Y register.
;
; Inputs: Y = Offset into parameter tables
; Outputs: aA3 = X, aA4 = Y, aBD = length, aAE = dx, aAF = dy
; Side Effects: None
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
$AC85a8load_segment_paramstay; Use offset in Y ; x-ref: $AC70, $AC7E
$AC86b9 17 acldaborder_segment_params,y; Load X start
$AC8985 a3stazp_pos_x
$AC8Bb9 18 acldaborder_segment_y_start,y; Load Y start
$AC8E85 a4stazp_pos_y
$AC90b9 19 acldaborder_segment_len,y; Load length
$AC9385 bdstazp_seg_len
$AC95b9 1a acldaborder_segment_dx,y; Load dx (X step)
$AC9885 aestazp_step_x
$AC9Ab9 1b acldaborder_segment_dy,y; Load dy (Y step)
$AC9D85 afstazp_step_y
$AC9F60rts
; Offset index table into border_segment_params. Each byte is a byte-offset (Y index)
; into the flat border_segment_params array, selecting a 5-byte segment record.
; Indexed as: Y = segment_counter + 4; offset = border_segment_tbl[Y]
;
; Record layout at border_segment_params[offset] (5 bytes):
; +0: X start (aA3)
; +1: Y start (aA4)
; +2: pixel count / length (aBD)
; +3: X step per pixel (aAE)
; +4: Y step per pixel (aAF)
;
; Entries (13 total for draw, 8 for erase):
; $32 (50) -> top edge, left half X=0, Y=0, len=79, dx=1, dy=0
; $19 (25) -> top edge, right half
; $37 (55) -> bottom edge, left half
; $14 (20) -> bottom edge, right half
; $00 (0) -> left edge, top half
; $00 (0) -> left edge, top half (repeat)
; $05 (5) -> left edge, bottom half
; $28 (40) -> right edge, top half
; $2D (45) -> right edge, bottom half
; $0F (15) -> inner box top
; $0A (10) -> inner box bottom
; $23 (35) -> inner box left
; $1E (30) -> inner box right
$ACA0border_segment_tbl.byte$32, $19, $37, $14, $00, $00, $05, $28; x-ref: $AC6D, $AC7B
$ACA8.byte$2d, $0f, $0a, $23, $1e
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
; Draws the current player score (aF7/aF8/aF9) onto the bitmap at X=$52, Y=$48.
; Copies the 3-byte BCD score to a scratch buffer and calls render_bcd_digits
; to draw each digit, advancing 4 pixels per digit.
;
; Inputs: aF7/aF8/aF9 (3-byte packed BCD current score)
; Outputs: None
; Side Effects: Writes digit graphics to bitmap
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
$ACADa9 52draw_player_scorelda#$52; X position = $52 ; x-ref: $A35B, $B0FC
$ACAF85 17stazp_score_cursor_x
$ACB1a9 48lda#$48; Y position = $48
$ACB385 a4stazp_pos_y
$ACB5a2 02ldx#$02
$ACB7b5 f7b_ACB7ldazp_score_lo,x; copy 3-byte BCD score to scratch buffer ; x-ref: $ACBC
$ACB995 1cstazp_temp_bcd_score,x
$ACBBcadex
$ACBC10 f9bplb_ACB7
$ACBE20 d7 acjsrrender_bcd_digits; render digits
$ACC160rts
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
; Draws the current high score (stored in a23-a25) onto the bitmap.
; Copies the 3-byte BCD score to a scratch buffer and calls render_bcd_digits.
;
; Inputs: a23/a24/a25 (3-byte packed BCD high score)
; Outputs: None
; Side Effects: Writes digit graphics to bitmap
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
$ACC2a9 52draw_high_scorelda#$52; X position = $52 ; x-ref: $A35E
$ACC485 17stazp_score_cursor_x; Store X cursor
$ACC6a9 5clda#$5c; Y position = $5C
$ACC885 a4stazp_pos_y; Store Y pos
$ACCAa2 02ldx#$02; Init loop counter for 3 bytes
$ACCCb5 23b_ACCCldazp_hiscore_lo,x; Copy BCD score byte to scratch ; x-ref: $ACD1
$ACCE95 1cstazp_temp_bcd_score,x; Store in scratch
$ACD0cadex
$ACD110 f9bplb_ACCC
$ACD320 d7 acjsrrender_bcd_digits; Render digits
$ACD660rts
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
; Renders the 3-byte packed BCD score in temp_bcd_score as digits.
; Handles leading zero suppression. Once a non-zero digit is found, all
; subsequent digits are rendered.
;
; Inputs: temp_bcd_score (3 bytes, packed BCD)
; Outputs: None
; Side Effects: Modifies the bitmap, advances score_cursor_x
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
$ACD720 a7 adrender_bcd_digitsjsradvance_score_cursor; Initial spacing ; x-ref: $ACBE, $ACD3
$ACDAa2 02ldx#$02; Index 2 = most significant byte
$ACDC86 b4stxzp_loop_idx
$ACDEa6 b4b_ACDEldxzp_loop_idx; Load BCD byte ; x-ref: $ACEC
$ACE0b5 1cldazp_temp_bcd_score,x
$ACE2d0 0cbneb_ACF0; If not zero, start rendering
$ACE420 a7 adjsradvance_score_cursor; Skip spacing for blank digits
$ACE720 a7 adjsradvance_score_cursor
$ACEAc6 b4deczp_loop_idx
$ACEC10 f0bplb_ACDE
$ACEE30 22bmib_AD12
$ACF029 f0b_ACF0and#$f0; Extract high nibble ; x-ref: $ACE2
$ACF2f0 0bbeqb_ACFF; If high nibble zero, skip it
$ACF4a6 b4b_ACF4ldxzp_loop_idx; x-ref: $AD10
$ACF6b5 1cldazp_temp_bcd_score,x
$ACF84alsra; Shift right to get digit value
$ACF94alsra
$ACFA4alsra
$ACFB4alsra
$ACFC20 9d adjsrdraw_bcd_digit; Draw high nibble digit
$ACFF20 a7 adb_ACFFjsradvance_score_cursor; Advance cursor for next digit ; x-ref: $ACF2
$AD02a6 b4ldxzp_loop_idx
$AD04b5 1cldazp_temp_bcd_score,x
$AD0629 0fand#$0f; Extract low nibble
$AD0820 9d adjsrdraw_bcd_digit; Draw low nibble digit
$AD0B20 a7 adjsradvance_score_cursor
$AD0Ec6 b4deczp_loop_idx
$AD1010 e2bplb_ACF4
$AD12a9 00b_AD12lda#$00; If all were zero, draw a single '0' ; x-ref: $ACEE
$AD1420 9d adjsrdraw_bcd_digit
$AD1760rts
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
; Draws the current wave/level indicator as two columns of icons on the bitmap.
; First column: up to 5 icons at X=$5A, Y=$40 (tens digit of wave).
; Second column: up to 10 icons at X=$46, Y=$54 (units digit of wave).
; Icon graphics are indexed from wave_icon_table (fB71E).
;
; Inputs: None (uses hardcoded positions and wave_icon_table)
; Outputs: None
; Side Effects: Writes icon graphics to bitmap
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
$AD18a9 04draw_wave_indicatorlda#$04; first column: 5 icons max ; x-ref: $A361
$AD1A85 1cstazp_temp_bcd_score
$AD1Ca9 5alda#$5a; X = $5A
$AD1E85 17stazp_score_cursor_x
$AD20a9 40lda#$40; Y = $40
$AD2285 a4stazp_pos_y
$AD2420 37 adjsrdraw_wave_icons
$AD27a9 09lda#$09; second column: 10 icons max
$AD2985 1cstazp_temp_bcd_score
$AD2Ba9 46lda#$46; X = $46
$AD2D85 17stazp_score_cursor_x
$AD2Fa9 54lda#$54; Y = $54
$AD3185 a4stazp_pos_y
$AD3320 37 adjsrdraw_wave_icons
$AD3660rts
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
; Draws a sequence of wave indicator icons from wave_icon_tbl.
; Loops based on the value in temp_bcd_score (counts down to 0).
;
; Inputs: temp_bcd_score = Number of icons to draw - 1
; Outputs: None
; Side Effects: Modifies the bitmap, advances score_cursor_x
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
$AD3720 a7 addraw_wave_iconsjsradvance_score_cursor; Advance cursor for spacing ; x-ref: $AD24, $AD33, $AD47
$AD3Aa4 1cldyzp_temp_bcd_score; Use remaining count as index
$AD3Cb9 1e b7ldawave_icon_tbl,y; Load icon index from table
$AD3F20 9b abjsrcalc_sprite_ptr; Compute sprite pointer
$AD4220 ff aajsrdraw_sprite_or_collision; Draw the icon
$AD45c6 1cdeczp_temp_bcd_score; Decrement remaining count
$AD4710 eebpldraw_wave_icons; Loop if not negative
$AD4960rts
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
; Draws the player lives display onto the bitmap. Erases all 3 ship icon slots,
; then redraws a filled ship icon for each remaining life (a1F). Uses a54 to
; select a bonus ship position for the last icon drawn.
;
; Inputs: a1F (lives remaining), a54 (bonus ship flag)
; Outputs: None
; Side Effects: Writes ship icon graphics to bitmap at lives_icon_x/y_table positions
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
$AD4Aa2 02draw_lives_displayldx#$02; loop over 3 ship slots (X=2 down to 0) ; x-ref: $A364, $B163
$AD4C86 b4stxzp_loop_idx
$AD4Ea9 29lda#$29; bitmap column = $29
$AD5020 9b abjsrcalc_sprite_ptr
$AD53a6 b4b_AD53ldxzp_loop_idx; x-ref: $AD64
$AD55bd 93 adldalives_icon_x_tbl,x; get X position for this slot
$AD5885 a3stazp_pos_x
$AD5Abd 98 adldalives_icon_y_tbl,x; get Y position for this slot
$AD5D85 a4stazp_pos_y
$AD5F20 41 abjsrerase_sprite; erase ship icon
$AD62c6 b4deczp_loop_idx
$AD6410 edbplb_AD53
$AD66a6 1fldxzp_player_lives; lives remaining = 0 -> game over
$AD68f0 28beqr_AD92
$AD6A86 b4stxzp_loop_idx
$AD6Ca9 00lda#$00
$AD6E20 9b abjsrcalc_sprite_ptr
$AD71a5 54ldazp_extra_life_awarded; a54 = bonus ship flag
$AD73f0 0abeqb_AD7F
$AD75a9 3dlda#$3d; bonus ship at fixed position ($3D/$4C)
$AD7785 a3stazp_pos_x
$AD79a9 4clda#$4c
$AD7B85 a4stazp_pos_y
$AD7Dd0 0cbneb_AD8B
$AD7Fa6 b4b_AD7Fldxzp_loop_idx; x-ref: $AD73, $AD90
$AD81bd 93 adldalives_icon_x_tbl,x
$AD8485 a3stazp_pos_x
$AD86bd 98 adldalives_icon_y_tbl,x
$AD8985 a4stazp_pos_y
$AD8B20 ff aab_AD8Bjsrdraw_sprite_or_collision; draw filled ship icon ; x-ref: $AD7D
$AD8Ec6 b4deczp_loop_idx
$AD90d0 edbneb_AD7F
$AD9260r_AD92rts; x-ref: $AD68
$AD93lives_icon_x_tbl.byte$3d, $2b, $2b, $34, $34; x-ref: $AD55, $AD81
$AD98lives_icon_y_tbl.byte$4c, $44, $54, $44, $54; x-ref: $AD5A, $AD86
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
; Renders a single BCD digit (0-9) onto the bitmap.
; Adds $47 to the digit value to get the sprite index.
;
; Inputs: A = Digit value (0-9)
; Outputs: None
; Side Effects: Modifies the bitmap
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
$AD9D18draw_bcd_digitclc; Clear carry for addition ; x-ref: $ACFC, $AD08, $AD14
$AD9E69 47adc#$47; Add $47 to get sprite index ('0' is at $47)
$ADA020 9b abjsrcalc_sprite_ptr; Compute sprite pointer
$ADA320 ff aajsrdraw_sprite_or_collision; Draw the digit
$ADA660rts
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
; Advances the score cursor X position by 4 pixels.
;
; Inputs: score_cursor_x
; Outputs: score_cursor_x (incremented by 4)
; Side Effects: None
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
$ADA7a5 17advance_score_cursorldazp_score_cursor_x; Load current X cursor ; x-ref: $ACD7, $ACE4, $ACE7, $ACFF, $AD0B, $AD37
$ADA918clc; Clear carry for addition
$ADAA69 04adc#$04; Advance by 4 pixels
$ADAC85 17stazp_score_cursor_x; Store updated X cursor
$ADAE85 a3stazp_pos_x
$ADB0a9 5blda#$5b
$ADB220 9b abjsrcalc_sprite_ptr
$ADB520 41 abjsrerase_sprite
$ADB860rts
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
; Initializes a new bullet slot when the player fires.
; Scans for a free slot (0-3), looks up velocity and position offsets
; based on the player's angle (aB1), and sets bullet lifetime.
;
; Inputs: aB1 = Player angle (0-15), player position
; Outputs: None
; Side Effects: Modifies bullet slot arrays, decrements bullet_slots_free
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
$ADB9a9 00fire_bulletlda#$00; x-ref: $A476
$ADBB85 35stazp_fire_cooldown
$ADBDa5 19ldazp_bullet_slots_free
$ADBFf0 45beqr_AE06
$ADC1a2 03ldx#$03
$ADC3bd 5d 1db_ADC3ldabullet_lifetimes,x; x-ref: $AE04
$ADC6d0 3bbneb_AE03
$ADC878sei
$ADC9a9 01lda#$01
$ADCB85 47stazp_snd_soprano_seq_idx
$ADCD85 4bstazp_snd_soprano_step
$ADCF85 43stazp_snd_soprano_dur
$ADD158cli
$ADD2a4 b1ldyzp_player_angle
$ADD418clc
fADD7 =*+$02
$ADD5b9 07 aeldabullet_dx_tbl,y; load X velocity from angle table
$ADD89d 4d 1dstabullet_vx,x
$ADDB18clc
$ADDCad 62 03ldaentity_x_coords
$ADDF79 27 aeadcbullet_spawn_dx_tbl,y; add X spawn offset; places bullet at ship nose
$ADE29d 65 1dstabullet_x_coords,x
$ADE518clc
$ADE6b9 17 aeldabullet_dy_tbl,y; load Y velocity from angle table
$ADE99d 55 1dstabullet_vy,x
$ADEC18clc
$ADEDad 75 03ldaentity_y_coords
$ADF079 37 aeadcbullet_spawn_dy_tbl,y; add Y spawn offset; places bullet at ship nose
$ADF39d 6d 1dstabullet_y_coords,x
$ADF6a9 32lda#$32
$ADF89d 5d 1dstabullet_lifetimes,x
$ADFBa9 00lda#$00
$ADFD9d 75 1dstabullet_owners,x
$AE00c6 19deczp_bullet_slots_free
$AE0260rts
$AE03cab_AE03dex; x-ref: $ADC6
$AE0410 bdbplb_ADC3
$AE0660r_AE06rts; x-ref: $ADBF
; Signed X velocity delta per tick for a fired bullet, indexed by player angle (aB1, 0-15).
; Values are 8-bit signed: $FD=-3, $FE=-2, $FF=-1, $00=0, $01=1, $02=2, $03=3.
; Forms a cosine-like curve across 16 angles (0=right, 4=up, 8=left, 12=down).
; Paired with bullet_dy_tbl (Y axis), bullet_spawn_dx_tbl/bullet_spawn_dy_tbl (spawn offset).
$AE07bullet_dx_tbl.byte$03, $02, $02, $01, $00, $ff, $fe, $fe; x-ref: $ADD5
$AE0F.byte$fd, $fd, $fe, $ff, $00, $01, $02, $02
; Signed Y velocity delta per tick for a fired bullet, indexed by player angle (aB1, 0-15).
; Values are 8-bit signed: $FD=-3..$03=+3. Sine-like curve, 90 degrees offset from bullet_dx_tbl.
$AE17bullet_dy_tbl.byte$00, $ff, $fe, $fe, $fd, $fe, $ff, $ff; x-ref: $ADE6
$AE1F.byte$00, $01, $02, $02, $03, $02, $02, $01
; X spawn position offset (added to player X) for a new bullet, indexed by angle (aB1, 0-15).
; Biases bullet starting position to appear at the ship's nose tip rather than its center.
$AE27bullet_spawn_dx_tbl.byte$09, $09, $09, $05, $04, $03, $ff, $ff; x-ref: $ADDF
$AE2F.byte$ff, $ff, $ff, $03, $04, $05, $09, $09
; Y spawn position offset (added to player Y) for a new bullet, indexed by angle (aB1, 0-15).
; Biases bullet starting position to appear at the ship's nose tip rather than its center.
$AE37bullet_spawn_dy_tbl.byte$04, $03, $ff, $ff, $ff, $ff, $ff, $03; x-ref: $ADF0
$AE3F.byte$04, $05, $09, $09, $09, $09, $09, $05
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
; Per-frame bullet update loop. Iterates over all 8 bullet slots (index 7..0)
; and for each active bullet:
; 1. Loads slot state into working registers via load_bullet_slot.
; 2. Erases the old 3-pixel trail via erase_bullet_trail (steps back 3 pixels).
; 3. Advances position: new_x = x + dx, new_y = y + dy; saves back to slot.
; 4. Draws the new 3-pixel trail via draw_bullet_trail (steps forward 3 pixels).
; 5. On wall hit (collision_type != 0): redraws/erases the impacted border segment.
; 6. On pixel overlap (collision_check_flag != 0): ORs bullet's bit into a26
; (bullet-hit bitmask, consumed by update_display_and_collisions).
; 7. Decrements f1D5D lifetime counter; when it reaches 0 the slot is freed.
;
; Inputs: f1D5D,x = bullet lifetime; f1D4D,x/f1D55,x = dx/dy velocity
; f1D65,x/f1D6D,x = current x/y position; f1D75,x = slot owner flag
; Outputs: a26 = bitmask of bullets that hit something this frame
; f1D65,x/f1D6D,x updated to new positions
; Side Effects: Bitmap modified (erase old trail, draw new trail); border segments
; redrawn on wall collision; bullet_slots_free incremented on expiry
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
$AE47a9 00update_bulletslda#$00; clear bullet-hit bitmask and collision accumulator ; x-ref: $A535
$AE4985 1bstazp_collision_check_flag
$AE4B85 26stazp_bullet_hit_mask
$AE4Da9 07lda#$07
$AE4F85 b4stazp_loop_idx
$AE51a6 b4j_AE51ldxzp_loop_idx; x-ref: $AEC7
$AE53bd 5d 1dldabullet_lifetimes,x; slot counter: iterate 7..0
$AE56f0 6bbeqb_AEC3; skip if slot is empty (lifetime = 0)
$AE5820 31 afjsrload_bullet_slot
$AE5B20 01 afjsrerase_bullet_trail; erase old 3-pixel trail at previous position
$AE5Ea6 b4ldxzp_loop_idx
$AE60de 5d 1ddecbullet_lifetimes,x; decrement lifetime; 0 means bullet expires this tick
$AE63f0 43beqb_AEA8
$AE6518clc
$AE66bd 4d 1dldabullet_vx,x; advance x: new_x = x + dx
$AE6985 aestazp_step_x
$AE6B7d 65 1dadcbullet_x_coords,x
$AE6E85 a3stazp_pos_x
$AE709d 65 1dstabullet_x_coords,x
$AE7318clc
$AE74bd 55 1dldabullet_vy,x
$AE7785 afstazp_step_y
$AE797d 6d 1dadcbullet_y_coords,x; advance y: new_y = y + dy
$AE7C85 a4stazp_pos_y
$AE7E9d 6d 1dstabullet_y_coords,x
$AE8120 cb aejsrdraw_bullet_trail; draw new 3-pixel trail; sets collision_type / collision_check_flag
$AE84a5 18ldazp_collision_type
$AE86f0 0bbeqb_AE93; wall hit? redraw impacted border segment
$AE8820 69 acjsrdraw_border_segment
$AE8Ba5 18ldazp_collision_type
$AE8D20 77 acjsrerase_border_segment
$AE904c a0 aejmpj_AEA0
$AE93a5 1bb_AE93ldazp_collision_check_flag; x-ref: $AE86
$AE95f0 2cbeqb_AEC3; pixel overlap hit — OR this bullet's bit into hit-bitmask
$AE97a4 b4ldyzp_loop_idx
$AE99b9 93 abldabit_mask_tbl,y
$AE9C05 26orazp_bullet_hit_mask
$AE9E85 26stazp_bullet_hit_mask
$AEA0a6 b4j_AEA0ldxzp_loop_idx; x-ref: $AE90
$AEA220 31 afjsrload_bullet_slot
$AEA520 01 afjsrerase_bullet_trail
$AEA8a6 b4b_AEA8ldxzp_loop_idx; x-ref: $AE63
$AEAAbd 75 1dldabullet_owners,x; slot owner flag: 0 = player bullet, free slot back to pool
$AEADd0 02bneb_AEB1
$AEAFe6 19inczp_bullet_slots_free
$AEB1a9 00b_AEB1lda#$00; x-ref: $AEAD
$AEB39d 5d 1dstabullet_lifetimes,x
$AEB6a5 18ldazp_collision_type
$AEB810 03bplb_AEBD
$AEBA20 69 acjsrdraw_border_segment
$AEBDa9 00b_AEBDlda#$00; x-ref: $AEB8
$AEBF85 1bstazp_collision_check_flag
$AEC185 18stazp_collision_type
$AEC3c6 b4b_AEC3deczp_loop_idx; x-ref: $AE56, $AE95
$AEC530 03bmir_AECA
$AEC74c 51 aejmpj_AE51
$AECA60r_AECArts; x-ref: $AEC5
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
; Draws a 3-pixel bullet trail forward from (aA3, aA4) in direction (aAE, aAF).
; Plots 3 pixels, stepping +1 or -1 in x/y per pixel based on velocity sign.
; Sets collision_check_flag if any pixel overlaps existing bitmap content.
; Sets collision_type if a wall boundary is hit (via sAF7E).
;
; Inputs: aA3/aA4 = bullet X/Y position; aAE/aAF = X/Y velocity (sign used only)
; Outputs: collision_check_flag, collision_type
; Side Effects: Bitmap modified (3 pixels drawn)
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
$AECBa9 03draw_bullet_traillda#$03; x-ref: $AE81
$AECD85 bdstazp_seg_len
$AECFa9 00lda#$00
$AED185 1bstazp_collision_check_flag
$AED320 7e afb_AED3jsrplot_bullet_pixel; x-ref: $AEFE
$AED6a5 18ldazp_collision_type
$AED805 1borazp_collision_check_flag
$AEDAd0 24bner_AF00
$AEDCa5 aeldazp_step_x
$AEDEf0 0cbeqb_AEEC
$AEE030 03bmib_AEE5
$AEE2a9 01lda#$01
$AEE4.byte$2c; bit opcode
$AEE5a9 ffb_AEE5lda#$ff; x-ref: $AEE0
$AEE718clc
$AEE865 a3adczp_pos_x
$AEEA85 a3stazp_pos_x
$AEECa5 afb_AEECldazp_step_y; x-ref: $AEDE
$AEEEf0 0cbeqb_AEFC
$AEF030 03bmib_AEF5
$AEF2a9 01lda#$01
$AEF4.byte$2c; bit opcode
$AEF5a9 ffb_AEF5lda#$ff; x-ref: $AEF0
$AEF718clc
$AEF865 a4adczp_pos_y
$AEFA85 a4stazp_pos_y
$AEFCc6 bdb_AEFCdeczp_seg_len; x-ref: $AEEE
$AEFEd0 d3bneb_AED3
$AF0060r_AF00rts; x-ref: $AEDA
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
; Erases a 3-pixel bullet trail backward from (aA3, aA4) in direction (aAE, aAF).
; Steps -1 or +1 in x/y (opposite of velocity sign) and clears each pixel.
; Uses clear_pixel_with_bounce; stops early on wall hit.
;
; Inputs: aA3/aA4 = bullet X/Y position; aAE/aAF = X/Y velocity (sign used only)
; Outputs: None
; Side Effects: Bitmap modified (3 pixels cleared); may set collision_type
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
$AF01a9 03erase_bullet_traillda#$03; x-ref: $AE5B, $AEA5
$AF0385 bdstazp_seg_len
$AF0520 7c abb_AF05jsrclear_pixel_with_bounce; x-ref: $AF2E
$AF08a5 18ldazp_collision_type
$AF0Ad0 24bner_AF30
$AF0Ca5 aeldazp_step_x
$AF0Ef0 0cbeqb_AF1C
$AF1030 03bmib_AF15
$AF12a9 01lda#$01
$AF14.byte$2c; bit opcode
$AF15a9 ffb_AF15lda#$ff; x-ref: $AF10
$AF1718clc
$AF1865 a3adczp_pos_x
$AF1A85 a3stazp_pos_x
$AF1Ca5 afb_AF1Cldazp_step_y; x-ref: $AF0E
$AF1Ef0 0cbeqb_AF2C
$AF2030 03bmib_AF25
$AF22a9 01lda#$01
$AF24.byte$2c; bit opcode
$AF25a9 ffb_AF25lda#$ff; x-ref: $AF20
$AF2718clc
$AF2865 a4adczp_pos_y
$AF2A85 a4stazp_pos_y
$AF2Cc6 bdb_AF2Cdeczp_seg_len; x-ref: $AF1E
$AF2Ed0 d5bneb_AF05
$AF3060r_AF30rts; x-ref: $AF0A
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
; Loads bullet slot X (index in X reg) into working registers.
; Copies position and velocity from parallel bullet arrays to shared ZP vars.
;
; Inputs: X = bullet slot index (0-7)
; Outputs: aA3=x, aA4=y, aAE=dx, aAF=dy
; Side Effects: None
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
$AF31bd 65 1dload_bullet_slotldabullet_x_coords,x; x-ref: $AE58, $AEA2
$AF3485 a3stazp_pos_x
$AF36bd 6d 1dldabullet_y_coords,x
$AF3985 a4stazp_pos_y
$AF3Bbd 4d 1dldabullet_vx,x
$AF3E85 aestazp_step_x
$AF40bd 55 1dldabullet_vy,x
$AF4385 afstazp_step_y
$AF4560rts
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
; Initializes a new bullet slot for an enemy.
; Scans for a free slot among the upper slots (7 down to 4).
; Inherits velocity from the firing enemy and sets position slightly ahead.
;
; Inputs: a3B = Index of the firing enemy
; Outputs: None
; Side Effects: Modifies bullet slot arrays, sets owner flag to 1
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
$AF46a0 07enemy_fire_bulletldy#$07; Start with highest bullet slot (7) ; x-ref: $A7CD, $A7E0, $A7F3
$AF48a6 3bldxzp_firing_entity_slot; Load firing enemy index
$AF4Ab9 5d 1db_AF4Aldabullet_lifetimes,y; Check if slot is free ; x-ref: $AF7B
$AF4Dd0 29bneb_AF78; If active, try next slot
$AF4Fbd 33 1dldaai_pursuit_vx,x; Inherit enemy X velocity
$AF5299 4d 1dstabullet_vx,y
$AF5518clc
$AF567d 62 03adcentity_x_coords,x; Add to enemy X position
$AF5969 04adc#$04; Add offset of 4 pixels
$AF5B99 65 1dstabullet_x_coords,y; Store as bullet X position
$AF5Ebd 40 1dldaai_pursuit_vy,x; Inherit enemy Y velocity
$AF6199 55 1dstabullet_vy,y
$AF6418clc
$AF657d 75 03adcentity_y_coords,x; Add to enemy Y position
$AF6869 04adc#$04; Add offset of 4 pixels
$AF6A99 6d 1dstabullet_y_coords,y; Store as bullet Y position
$AF6Da9 23lda#$23; Set lifetime to 35 frames
$AF6F99 5d 1dstabullet_lifetimes,y
$AF72a9 01lda#$01; Set owner flag to 1 (enemy)
$AF7499 75 1dstabullet_owners,y
$AF7760rts
$AF7888b_AF78dey; Move to next slot ; x-ref: $AF4D
$AF79c0 03cpy#$03; Stop after checking slot 4
$AF7Bd0 cdbneb_AF4A
$AF7D60rts
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
; Plots a single pixel of a bullet trail onto the bitmap.
; Checks for boundary collisions and pixel overlaps (collisions with other entities).
;
; Inputs: aA5 = Pointer to bitmap byte, aAD = bit offset (0-7)
; collision_check_flag = accumulator
; Outputs: collision_check_flag (updated), collision_type (from boundary check)
; Side Effects: Modifies the bitmap
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
$AF7E20 6a a9plot_bullet_pixeljsrcheck_boundary_collisions; Check collisions with walls ; x-ref: $AED3
$AF81a5 18ldazp_collision_type; Check if wall hit
$AF83d0 17bner_AF9C; Return if wall hit
$AF85a6 adldxzp_spr_bit_offset; X = bit offset (0-7)
$AF87bd 93 abldabit_mask_tbl,x; Get bit mask for pixel
$AF8A85 b3stazp_pixel_mask; Store mask
$AF8Ca2 00ldx#$00; Offset 0
$AF8Ea1 a5lda(zp_ptr_bmp_col_lo,x); Read bitmap byte
$AF90a8tay; Save original byte in Y
$AF9125 b3andzp_pixel_mask; Check if pixel already set
$AF9305 1borazp_collision_check_flag; Update collision flag
$AF9585 1bstazp_collision_check_flag
$AF9798tya; Restore original byte
$AF9805 b3orazp_pixel_mask; Set pixel bit
$AF9A81 a5sta(zp_ptr_bmp_col_lo,x); Write back to bitmap
$AF9C60r_AF9Crts; x-ref: $AF83
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
; Spawns a new mine/drone at the position of the current enemy (X).
; Scans for a free slot among the upper slots (18 down to 13).
; Sets type to 5 or 6 based on a random timer check.
;
; Inputs: X = Index of parent enemy
; Outputs: None
; Side Effects: Modifies entity slot arrays (13-18)
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
$AF9Da0 12spawn_enemy_mineldy#$12; Start with highest candidate slot (18) ; x-ref: $A802, $A81D
$AF9Fb9 3c 03b_AF9Fldaentity_types,y; Check if slot is free (negative type) ; x-ref: $AFA7
$AFA230 07bmib_AFAB; Branch if free slot found
$AFA488dey; Else try next lower slot
$AFA5c0 0dcpy#$0d; Stop after checking slot 13
$AFA7b0 f6bcsb_AF9F
$AFA990 20bccr_AFCB
$AFABbd 62 03b_AFABldaentity_x_coords,x; Copy X position from parent enemy ; x-ref: $AFA2
$AFAE99 62 03staentity_x_coords,y
$AFB1bd 75 03ldaentity_y_coords,x; Copy Y position from parent enemy
$AFB499 75 03staentity_y_coords,y
$AFB7a9 00lda#$00; Set state to active (0)
$AFB999 a2 03staentity_velocity_indices,y
$AFBCad 24 91lda$9124; Read random-ish value from timer
$AFBF29 03and#$03; Mask to 2 bits
$AFC1d0 03bneb_AFC6; Branch if not 0
$AFC3a9 05lda#$05; Set type 5 (rare)
$AFC5.byte$2c; bit opcode
$AFC6a9 06b_AFC6lda#$06; Set type 6 (common) ; x-ref: $AFC1
$AFC899 3c 03staentity_types,y; Store entity type
$AFCB60r_AFCBrts; x-ref: $AFA9
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
; Updates the visual display of an enemy entity.
; Runs every 8 frames. Handles normal (3x3 body) and exploding (4 wings) states.
; Animates by toggling bit 0 of the state.
;
; Inputs: Y = Entity slot index
; Outputs: None
; Side Effects: Modifies the bitmap, updates entity state and timer
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
$AFCC84 28draw_enemystyzp_cur_entity_idx; Scratch: current enemy entity slot index, preserved across draw sub-calls ; x-ref: $A598
$AFCEa6 28ldxzp_cur_entity_idx
$AFD0a5 37ldazp_frame_counter; Load frame counter
$AFD229 07and#$07; Check lower 3 bits
$AFD4f0 01beqb_AFD7; Only run every 8 frames
$AFD660rts
$AFD7bd a2 03b_AFD7ldaentity_velocity_indices,x; Load entity state ; x-ref: $AFD4
$AFDAc9 82cmp#$82; Check if state >= $82 (exploding)
$AFDCb0 39bcsb_B017
$AFDE20 a1 b1jsrerase_enemy_body; Erase normal body
$AFE1a0 08ldy#$08
$AFE384 3cstyzp_attract_delay_ctr
$AFE5a6 28b_AFE5ldxzp_cur_entity_idx; x-ref: $B013
$AFE7a4 3cldyzp_attract_delay_ctr
$AFE9b9 8a b0ldaenemy_body_dx_tbl,y; load X offset for body pixel [a3C]
$AFEC18clc
$AFED7d 62 03adcentity_x_coords,x
$AFF085 a3stazp_pos_x
$AFF2b9 93 b0ldaenemy_body_dy_tbl,y; load Y offset for body pixel [a3C]
$AFF518clc
$AFF67d 75 03adcentity_y_coords,x
$AFF985 a4stazp_pos_y
$AFFBbd a2 03ldaentity_velocity_indices,x
$AFFE29 01and#$01
$B000f0 02beqb_B004
$B002a9 09lda#$09
$B00418b_B004clc; x-ref: $B000
$B00565 3cadczp_attract_delay_ctr
$B007a8tay
$B008b9 a4 b0ldaf_B0A4,y
$B00B20 9b abjsrcalc_sprite_ptr
$B00E20 05 abjsrdraw_sprite_with_collision_check; Draw body pixel
$B011c6 3cdeczp_attract_delay_ctr
$B01310 d0bplb_AFE5
$B01530 35bmib_B04C
$B01720 7a b1b_B017jsrerase_enemy_wings; Erase wings ; x-ref: $AFDC
$B01Aa0 03ldy#$03
$B01C84 3cstyzp_attract_delay_ctr
$B01Ea6 28b_B01Eldxzp_cur_entity_idx; x-ref: $B04A
$B020a4 3cldyzp_attract_delay_ctr
$B022b9 82 b0ldaenemy_wing_dx_tbl,y; load X offset for wing pixel [a3C]
$B02518clc
$B0267d 62 03adcentity_x_coords,x
$B02985 a3stazp_pos_x
$B02Bb9 86 b0ldaenemy_wing_dy_tbl,y; load Y offset for wing pixel [a3C]
$B02E18clc
$B02F7d 75 03adcentity_y_coords,x
$B03285 a4stazp_pos_y
$B034bd a2 03ldaentity_velocity_indices,x
$B03729 01and#$01
$B0390aasla
$B03A0aasla
$B03B18clc
$B03C65 3cadczp_attract_delay_ctr
$B03Ea8tay
$B03Fb9 9c b0ldaf_B09C,y
$B04220 9b abjsrcalc_sprite_ptr
$B04520 05 abjsrdraw_sprite_with_collision_check; Draw wing pixel
$B048c6 3cdeczp_attract_delay_ctr
$B04A10 d2bplb_B01E
$B04Ca6 28b_B04Cldxzp_cur_entity_idx; x-ref: $B015
$B04Ede b5 03decentity_anim_timers,x; Decrement animation timer
$B05130 09bmib_B05C; Branch if timer expired
$B053bd a2 03ldaentity_velocity_indices,x
$B05649 01eor#$01; Toggle bit 0 for animation
$B0589d a2 03staentity_velocity_indices,x
$B05B60rts
$B05Ca9 2ab_B05Clda#$2a; x-ref: $B051
$B05E9d 4f 03staentity_headings,x
$B0619d 13 1dstaentity_sprite_frames,x
$B064bd a2 03ldaentity_velocity_indices,x
$B067c9 82cmp#$82
$B069b0 06bcsb_B071
$B06B20 a1 b1jsrerase_enemy_body
$B06E4c 74 b0jmpj_B074
$B07120 7a b1b_B071jsrerase_enemy_wings; x-ref: $B069
$B074a4 28j_B074ldyzp_cur_entity_idx; x-ref: $B06E
$B076b9 3c 03ldaentity_types,y
$B079a9 fflda#$ff
$B07B99 a2 03staentity_velocity_indices,y
$B07E99 3c 03staentity_types,y
$B08160rts
; Signed X pixel offsets (relative to enemy center) for the 4 wing-tip pixels.
; Indexed 0-3. Values: $FC=-4, $04=+4.
; Layout (X,Y pairs with enemy_wing_dy_tbl):
; 0: (-4,-4) top-left
; 1: (+4,-4) top-right
; 2: (-4,+4) bottom-left
; 3: (+4,+4) bottom-right
; Forms a 4-corner diamond shape at ±4 pixels. Used when enemy state >= $82.
$B082enemy_wing_dx_tbl.byte$fc, $04, $fc, $04; x-ref: $B022, $B186
; Signed Y pixel offsets (relative to enemy center) for the 4 wing-tip pixels.
; Indexed 0-3. Values: $FC=-4, $04=+4.
; Paired with enemy_wing_dx_tbl. See that table for full (X,Y) layout.
$B086enemy_wing_dy_tbl.byte$fc, $fc, $04, $04; x-ref: $B02B, $B18F
; Signed X pixel offsets (relative to enemy center) for the 9-pixel enemy body.
; Indexed 0-8. Values: $F8=-8, $00=0, $08=+8.
; Layout (X,Y pairs with enemy_body_dy_tbl) — a 3x3 grid spaced 8 pixels apart:
; 0: (-8,-8) 1: (0,-8) 2: (+8,-8) <- top row
; 3: (-8, 0) 4: (0, 0) 5: (+8, 0) <- middle row
; 6: (-8,+8) 7: (0,+8) 8: (+8,+8) <- bottom row
; Used for the main enemy body (state < $82).
$B08Aenemy_body_dx_tbl.byte$f8, $00, $08, $f8, $00, $08, $f8, $00; x-ref: $AFE9, $B1AD
$B092.byte$08
; Signed Y pixel offsets (relative to enemy center) for the 9-pixel enemy body.
; Indexed 0-8. Values: $F8=-8, $00=0, $08=+8.
; Paired with enemy_body_dx_tbl. See that table for full 3x3 grid layout.
$B093enemy_body_dy_tbl.byte$f8, $f8, $f8, $00, $00, $00, $08, $08; x-ref: $AFF2, $B1B6
$B09B.byte$08
.encode
.enc"screen"
$B09Cf_B09C.text"-./01234"; x-ref: $B03F
$B0A4f_B0A4.text"56789:;<=>?`abcdef"; x-ref: $B008
.endencode
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
; Handles a collision hit on entity slot X. Dispatches on entity type (f033C,x):
;
; Y = 0 -> Player ship was hit:
; - Sets f03A2,x=$80 (inactive/exploding), f03B5,x=$06 (anim frames)
; - Decrements player_lives, sets respawn timer a4D=$3C
; - Triggers death audio/visual effect via SEI-protected register writes
; - Sets bit 0 of a4E (death flag)
;
; Y = 5 -> Large enemy hit:
; - Triggers fanfare sound (a48=1, a4C=1, a44=7)
; - Falls through to score/explosion logic
;
; Y < 5 -> Standard enemy hit:
; - Decrements a3D (remaining enemies on wave)
; - Triggers hit sound (a46=a4A=$0A)
;
; Y > 5 -> Obstacle hit:
; - Triggers alternate sound (a46=a4A=$17)
;
; (Y != 0 common epilogue):
; - Sets f03B5,x=$02 (explosion timer), f03A2,x=$82 (exploding state)
; - Clears f002E,y (per-type counter for this entity kind)
; - Calls add_score(Y) and redraws player score HUD
;
; Inputs: X = entity slot index (0-$12)
; f033C,x = entity type / hit classification (0=player, 1-9=enemy types)
; Outputs: player_lives decremented (if player hit); aF7/aF8/aF9 score updated
; Side Effects: Entity state set to exploding; audio registers written under SEI
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
$B0B6a9 00handle_entity_hitlda#$00; clear entity collision state and pixel-overlap flag ; x-ref: $A565, $A570, $A651, $A656
$B0B89d c8 03staentity_vx,x
$B0BB9d 00 1dstaentity_vy,x
$B0BEbd 3c 03ldaentity_types,x
$B0C1a8tay
$B0C2f0 3cbeqb_B100; Y = entity type: 0=player, else enemy/obstacle
$B0C4c9 05cmp#$05; Y=5 -> large enemy: fanfare sound
$B0C6d0 0cbneb_B0D4
$B0C8a9 01lda#$01
$B0CA85 48stazp_snd_noise_seq_idx
$B0CC85 4cstazp_snd_noise_step
$B0CEa9 07lda#$07
$B0D085 44stazp_snd_noise_dur
$B0D2d0 15bneb_B0E9
$B0D490 04b_B0D4bccb_B0DA; Y < 5: decrement remaining enemy count ; x-ref: $B0C6
$B0D6a9 17lda#$17
$B0D8d0 05bneb_B0DF
$B0DAc6 3db_B0DAdeczp_max_enemy_count; x-ref: $B0D4
$B0DC78sei
$B0DDa9 0alda#$0a
$B0DF78b_B0DFsei; x-ref: $B0D8
$B0E085 46stazp_snd_alto_seq_idx
$B0E285 4astazp_snd_alto_step
$B0E4a9 01lda#$01
$B0E685 42stazp_snd_alto_dur
$B0E858cli
$B0E9a9 02b_B0E9lda#$02; x-ref: $B0D2
$B0EB9d b5 03staentity_anim_timers,x
$B0EEa9 82lda#$82
$B0F09d a2 03staentity_velocity_indices,x; set entity to exploding state (still visible)
$B0F3a9 00lda#$00
$B0F599 2e 00sta@w zp_entity_type_to_slot,y
$B0F898tya
$B0F920 2d b1jsradd_score; award score for this entity type (Y = type index)
$B0FC20 ad acjsrdraw_player_score
$B0FF60rts
$B100a9 80b_B100lda#$80; --- player ship hit branch --- ; x-ref: $B0C2
$B1029d a2 03staentity_velocity_indices,x
$B105a9 06lda#$06
$B1079d b5 03staentity_anim_timers,x
$B10Ac6 1fdeczp_player_lives; decrement lives
$B10Ca9 3clda#$3c
$B10E85 4dstazp_snd_volume_state; invincibility/respawn timer ($3C = 60 frames)
$B110a5 4eldazp_game_phase
$B11209 01ora#$01
$B11485 4estazp_game_phase; Set death-countdown phase (bit 0)
$B11678sei
$B117a9 0clda#$0c
$B11985 48stazp_snd_noise_seq_idx
$B11B85 4cstazp_snd_noise_step
$B11Da9 04lda#$04
$B11F85 44stazp_snd_noise_dur
$B121a9 01lda#$01
$B12385 45stazp_snd_bass_seq_idx
$B12585 49stazp_snd_bass_step
$B127a9 0clda#$0c
$B12985 41stazp_snd_bass_dur
$B12B58cli
$B12C60rts
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
; Adds a BCD score value to the player's 3-byte score (aF7/aF8/aF9).
; The A register is an index into the score table at fB16A; each entry is a
; 2-byte packed BCD value. After adding, checks if the score has crossed the
; extra-life threshold ($4000). If so, and if the bonus life flag (a54) is
; clear, grants an extra life, triggers the fanfare, and updates the HUD.
;
; Inputs: A = score table index (0-7)
; Outputs: aF7/aF8/aF9 = updated 3-byte packed BCD score
; Side Effects: May increment player_lives and call draw_lives_display;
; sets a54=1 to prevent awarding more than one extra life
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
$B12D78add_scoresei; disable IRQs before score update ; x-ref: $B0F9, $B3B7
$B12E0aasla; A*2 = byte offset into 2-byte BCD table entries
$B12Fa8tay; index into table
$B130f8sed; enable BCD (Decimal) mode for BCD addition
$B131b9 6a b1ldascore_table_lo,y; load score low byte from table
$B13465 f7adczp_score_lo; add to score byte 0 (ones/tens)
$B13685 f7stazp_score_lo; store score byte 0
$B138b9 6b b1ldascore_table_hi,y; load score high byte from table
$B13B65 f8adczp_score_mid; add to score byte 1 (hundreds/thousands)
$B13D85 f8stazp_score_mid; store score byte 1
$B13Fa5 f9ldazp_score_hi; propagate carry into score byte 2 (ten-thousands)
$B14169 00adc#$00
$B14385 f9stazp_score_hi; store score byte 2
$B145d8cld; exit BCD mode
$B14658cli; re-enable IRQs
$B147a5 54ldazp_extra_life_awarded; check if extra life already awarded
$B149d0 1ebner_B169; yes — skip extra-life check
$B14Ba5 f8ldazp_score_mid; check score high byte >= $40 (i.e. score >= 4000)
$B14Dc9 40cmp#$40
$B14F90 18bccr_B169; score < 4000 — no extra life yet
$B15178sei; disable IRQs to safely update sprite/sound registers
$B152a9 11lda#$11
$B15485 47stazp_snd_soprano_seq_idx
$B15685 4bstazp_snd_soprano_step
$B158a9 03lda#$03
$B15A85 43stazp_snd_soprano_dur
$B15C58cli
$B15Da9 01lda#$01
$B15F85 54stazp_extra_life_awarded; Set flag: extra life already granted
$B161e6 1finczp_player_lives; grant extra life
$B16320 4a adjsrdraw_lives_display; update lives HUD display
$B1668d 6d a4stapatch_input_dispatch_hi
$B16960r_B169rts; x-ref: $B149, $B14F
score_table_hi =*+$01 ; x-ref: $B138
; 2-byte packed BCD score values indexed by enemy type / kill event
; [0] $0000 = 0 pts (no score)
; [1] $0250 = 250 pts
; [2] $0150 = 150 pts
; [3] $0150 = 150 pts
; [4] $0100 = 100 pts
; [5] $0050 = 50 pts
; [6] $0035 = 35 pts
; [7] $0500 = 500 pts (bonus)
$B16Ascore_table_lo.word$0000, $0250, $0150, $0150, $0100; x-ref: $B131
$B174.word$0050, $0035, $0500
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
; Erases the 4-pixel enemy wing-tip pattern from the bitmap. Iterates indices 3..0,
; computing each pixel position as:
; X = f0362[a28] + enemy_wing_dx_tbl[i]
; Y = f0375[a28] + enemy_wing_dy_tbl[i]
; and calling erase_sprite_with_boundary_check for each.
; Used when entity state (f03A2) >= $82 (exploding / wing-tip visible state).
; For the normal body state, erase_enemy_body is used instead.
;
; Inputs: a28 = entity slot index
; Outputs: None
; Side Effects: Clears 4 pixels from the bitmap at the enemy's wing-tip positions
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
$B17Aa0 03erase_enemy_wingsldy#$03; x-ref: $B017, $B071
$B17C84 1astyzp_marker_idx
$B17Ea6 28b_B17Eldxzp_cur_entity_idx; x-ref: $B19E
$B180a4 1aldyzp_marker_idx
$B182bd 62 03ldaentity_x_coords,x
$B18518clc
$B18679 82 b0adcenemy_wing_dx_tbl,y
$B18985 a3stazp_pos_x
$B18Bbd 75 03ldaentity_y_coords,x
$B18E18clc
$B18F79 86 b0adcenemy_wing_dy_tbl,y
$B19285 a4stazp_pos_y
$B194a9 29lda#$29
$B19620 9b abjsrcalc_sprite_ptr
$B19920 47 abjsrerase_sprite_with_boundary_check
$B19Cc6 1adeczp_marker_idx
$B19E10 debplb_B17E
$B1A060rts
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
; Erases the 9-pixel enemy body from the bitmap. Iterates indices 8..0,
; computing each pixel position as:
; X = f0362[a28] + enemy_body_dx_tbl[i]
; Y = f0375[a28] + enemy_body_dy_tbl[i]
; and calling erase_sprite_with_boundary_check for each.
; This is the erase counterpart to the draw loop in sAFCC.
; Only called when entity state (f03A2) < $82 (body-visible, not exploding).
; For the exploding (wing-tip) state, sB17A is used instead.
;
; Inputs: a28 = entity slot index
; Outputs: None
; Side Effects: Clears 9 pixels from the bitmap at the enemy's 3x3 body positions
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
$B1A1a0 08erase_enemy_bodyldy#$08; loop 8..0 over 9 body pixels ; x-ref: $AFDE, $B06B
$B1A384 1astyzp_marker_idx
$B1A5a6 28b_B1A5ldxzp_cur_entity_idx; x-ref: $B1C5
$B1A7a4 1aldyzp_marker_idx
$B1A9bd 62 03ldaentity_x_coords,x
$B1AC18clc
$B1AD79 8a b0adcenemy_body_dx_tbl,y
$B1B085 a3stazp_pos_x
$B1B2bd 75 03ldaentity_y_coords,x
$B1B518clc
$B1B679 93 b0adcenemy_body_dy_tbl,y; pixel Y = entity_y + body_dy[i]
$B1B985 a4stazp_pos_y
$B1BBa9 29lda#$29; glyph $29 = single-pixel dot shape
$B1BD20 9b abjsrcalc_sprite_ptr
$B1C020 47 abjsrerase_sprite_with_boundary_check
$B1C3c6 1adeczp_marker_idx
$B1C510 debplb_B1A5
$B1C760rts
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
; Title screen / Attract mode sequence.
;
; Inputs: None
; Outputs: Returns when the player presses Start (aB0 flag goes negative)
; Side Effects: Clears screen, displays cycling title screens and graphics,
; sets colors, waits for user input.
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
$B1C820 29 a4attract_modejsrclear_char_ram; clear screen / display RAM ; x-ref: $A029, $B287
$B1CBa0 28ldy#$28; setup title screen colors
$B1CDa9 02b_B1CDlda#VicColors.RED; x-ref: $B1D8
$B1CF99 3c 96staCOLOR_RAM_R2C16,y
$B1D2a9 07lda#VicColors.YELLOW
$B1D499 64 96staCOLOR_RAM_R4C12,y
$B1D788dey
$B1D810 f3bplb_B1CD
$B1DAa2 86ldx#<gfx_attract_slide_1; gfx_attract_slide_1 ($BB86): OMEGA RACE title logo + copyright text
$B1DCa0 bbldy#>gfx_attract_slide_1
$B1DEa9 01lda#$01
$B1E085 aestazp_step_x
$B1E285 afstazp_step_y
$B1E420 cc b2jsrdraw_graphic_string; draw title logo with red/yellow gradient
$B1E720 b4 b2jsrattract_mode_delay; wait for delay
$B1EA24 b0bitzp_joy_fire; check if start button pressed
$B1EC10 01bplb_B1EF
$B1EE60rts
$B1EFa5 62b_B1EFldazp_show_score_table; x-ref: $B1EC
$B1F1f0 18beqb_B20B
$B1F320 52 a4jsrfill_color_ram
$B1F620 29 a4jsrclear_char_ram; clear screen for next graphic
$B1F9a2 28ldx#<gfx_attract_slide_2; gfx_attract_slide_2 ($B728): scoring table (enemy types + point values)
$B1FBa0 b7ldy#>gfx_attract_slide_2
$B1FDa9 02lda#$02
$B1FF85 aestazp_step_x
$B201a9 fflda#$ff
$B20385 afstazp_step_y
$B20520 cc b2jsrdraw_graphic_string; draw scoring table (conditional: only when a62 != 0)
$B20820 b4 b2jsrattract_mode_delay
$B20B20 52 a4b_B20Bjsrfill_color_ram; x-ref: $B1F1
$B20E20 29 a4jsrclear_char_ram
$B211a2 10ldx#<gfx_attract_slide_3; gfx_attract_slide_3 ($BC10): copyright/logo screen
$B213a0 bcldy#>gfx_attract_slide_3
$B215a9 01lda#$01
$B21785 aestazp_step_x
$B21985 afstazp_step_y
$B21B20 cc b2jsrdraw_graphic_string; draw copyright/logo screen
$B21E24 b0bitzp_joy_fire
$B22030 64bmir_B286
$B22220 8a b2jsrattract_color_cycle
$B22524 b0bitzp_joy_fire
$B22730 5dbmir_B286
$B22920 29 a4jsrclear_char_ram
$B22C20 52 a4jsrfill_color_ram
$B22F20 ce abjsrdraw_markers
$B232a2 67ldx#<gfx_story_slide_1; gfx_story_slide_1 ($BC67): 'In the year 2003, the Omegan System...'
$B234a0 bcldy#>gfx_story_slide_1
$B236a9 01lda#$01
$B23885 aestazp_step_x
$B23Aa9 fflda#$ff
$B23C85 afstazp_step_y
$B23E20 cc b2jsrdraw_graphic_string; draw story slide 1: 'In the year 2003...' (instant display, no typing delay)
$B24124 b0bitzp_joy_fire
$B24330 41bmir_B286
$B24520 b4 b2jsrattract_mode_delay
$B24824 b0bitzp_joy_fire
$B24A30 3abmir_B286
$B24C20 29 a4jsrclear_char_ram
$B24F20 ce abjsrdraw_markers
$B252a2 a8ldx#<attract_story_slide_2; next story slide ($BDA8)
$B254a0 bdldy#>attract_story_slide_2
$B256a9 01lda#$01
$B25885 aestazp_step_x
$B25A85 afstazp_step_y
$B25C20 cc b2jsrdraw_graphic_string; draw story slide 2
$B25F20 23 b3jsrattract_ship_animation
$B26224 b0bitzp_joy_fire
$B26430 20bmir_B286
$B26620 29 a4jsrclear_char_ram
$B26920 ce abjsrdraw_markers
$B26Ca2 0aldx#<attract_story_slide_3
$B26Ea0 beldy#>attract_story_slide_3
$B270a9 01lda#$01
$B27285 aestazp_step_x
$B274a9 fflda#$ff
$B27685 afstazp_step_y
$B27820 cc b2jsrdraw_graphic_string
$B27B24 b0bitzp_joy_fire
$B27D30 07bmir_B286
$B27F20 b4 b2jsrattract_mode_delay
$B28224 b0bitzp_joy_fire
$B28410 01bplb_B287
$B28660r_B286rts; x-ref: $B220, $B227, $B243, $B24A, $B264, $B27D
$B2874c c8 b1b_B287jmpattract_mode; x-ref: $B284
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
; Attract mode color cycling animation. Loops $19 (25) times, each iteration
; incrementing aAE and writing (aAE & $07) to 4 fixed color RAM positions
; ($9603, $962B, $963F, $9667), cycling through VIC-20's 8 colors (0-7).
; After each color update, calls the attract_mode_delay inner loop (sB2B8)
; to pace the animation. Aborts early if the start button is pressed (aB0 < 0).
; Called once from attract_mode after displaying the copyright/logo screen.
;
; Inputs: None (aAE used as internal counter, initialized to 0)
; Outputs: None
; Side Effects: Writes to color RAM at $9603, $962B, $963F, $9667;
; returns immediately if aB0 bit 7 set (start pressed)
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
$B28Aa9 19attract_color_cyclelda#$19; loop counter: 25 iterations ; x-ref: $B222
$B28C85 b3stazp_pixel_mask
$B28Ea9 00lda#$00
$B29085 aestazp_step_x
$B292e6 aeb_B292inczp_step_x; advance color index each frame ; x-ref: $B2B1
$B294a5 aeldazp_step_x
$B29629 07and#$07; mask to 3 bits: cycles colors 0-7
$B2988d 03 96staCOLOR_RAM_R0C3; write color to 4 logo positions in color RAM
$B29B8d 2b 96staCOLOR_RAM_R1C21
$B29E8d 3f 96staCOLOR_RAM_R2C19
$B2A18d 67 96staCOLOR_RAM_R4C15
$B2A4a9 06lda#$06
$B2A685 1astazp_marker_idx
$B2A820 b8 b2jsrattract_mode_delay_inner; pace animation with delay; also polls for start button
$B2AB24 b0bitzp_joy_fire; abort if start pressed (bit 7 of aB0)
$B2AD30 04bmir_B2B3
$B2AFc6 b3deczp_pixel_mask
$B2B1d0 dfbneb_B292
$B2B360r_B2B3rts; x-ref: $B2AD
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
; Delay loop used during the attract mode sequence.
;
; Inputs: None
; Outputs: None
; Side Effects: Delays execution for a few seconds by looping 40 x 256 times.
; Continually polls for user input (via scan_input_for_start) and
; aborts the delay instantly if the start button is pressed.
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
$B2B4a9 28attract_mode_delaylda#$28; setup outer loop counter (40) ; x-ref: $B1E7, $B208, $B245, $B27F
$B2B685 1astazp_marker_idx
attract_mode_delay_inner
$B2B8a9 fflda#$ff; Setup inner loop counter (255) ; x-ref: $B2A8, $B2C9
$B2BA85 3cstazp_attract_delay_ctr
$B2BC20 d2 b3b_B2BCjsrscan_input_for_start; Poll joysticks and keyboard ; x-ref: $B2C5
$B2BF24 b0bitzp_joy_fire; Check if start button pressed
$B2C130 08bmir_B2CB; Abort delay if pressed
$B2C3c6 3cdeczp_attract_delay_ctr; Decrement inner counter
$B2C5d0 f5bneb_B2BC
$B2C7c6 1adeczp_marker_idx; Decrement outer counter
$B2C9d0 edbneattract_mode_delay_inner
$B2CB60r_B2CBrts; x-ref: $B2C1
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
; Draws a sequence of characters/graphics to the screen with a typing effect.
;
; Inputs: X (pointer low), Y (pointer high) to graphic data structure
; aAE (delay outer loop), aAF (delay inner loop)
; Outputs: None
; Side Effects: Draws to screen RAM. Can be aborted instantly if the user
; presses the start button (aB0 flag).
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
$B2CC86 2cdraw_graphic_stringstxzp_ptr_gfx_str; store pointer low ; x-ref: $A0C5, $B1E4, $B205, $B21B, $B23E, $B25C, $B278, $B3AF
$B2CE84 2dstyzp_ptr_gfx_str_hi; store pointer high
$B2D0a0 00b_B2D0ldy#$00; x-ref: $B2EC, $B2F0
$B2D2b1 2clda(zp_ptr_gfx_str),y; read base X coordinate
$B2D485 a3stazp_pos_x
$B2D6c8iny
$B2D7b1 2clda(zp_ptr_gfx_str),y; read base Y coordinate
$B2D985 a4stazp_pos_y
$B2DBc8iny
$B2DCb1 2clda(zp_ptr_gfx_str),y; read X-coordinate step
$B2DE85 b3stazp_pixel_mask
$B2E0c8j_B2E0iny; x-ref: $B31F
$B2E1b1 2clda(zp_ptr_gfx_str),y; read next character
$B2E3d0 0ebneb_B2F3; if 00, end of segment
$B2E5c8iny
$B2E698tya
$B2E718clc
$B2E865 2cadczp_ptr_gfx_str
$B2EA85 2cstazp_ptr_gfx_str
$B2EC90 e2bccb_B2D0
$B2EEe6 2dinczp_ptr_gfx_str_hi
$B2F04c d0 b2jmpb_B2D0
$B2F3c9 ffb_B2F3cmp#$ff; if FF, end of all data ; x-ref: $B2E3
$B2F5f0 2bbeqr_B322
$B2F784 b4styzp_loop_idx
$B2F920 9b abjsrcalc_sprite_ptr
$B2FC20 ff aajsrdraw_sprite_or_collision; draw character to screen
$B2FFa5 aeldazp_step_x
$B30185 1astazp_marker_idx
$B303a5 afb_B303ldazp_step_y; x-ref: $B314
$B30585 3cstazp_attract_delay_ctr
$B30720 d2 b3b_B307jsrscan_input_for_start; x-ref: $B310
$B30A24 b0bitzp_joy_fire; abort if start pressed
$B30C30 14bmir_B322
$B30Ec6 3cdeczp_attract_delay_ctr
$B310d0 f5bneb_B307
$B312c6 1adeczp_marker_idx
$B314d0 edbneb_B303
$B316a4 b4ldyzp_loop_idx
$B318a5 a3ldazp_pos_x
$B31A18clc
$B31B65 b3adczp_pixel_mask; advance X by step
$B31D85 a3stazp_pos_x
$B31F4c e0 b2jmpj_B2E0
$B32260r_B322rts; x-ref: $B2F5, $B30C
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
; Attract mode ship animation. Cycles through sprite frames $20, $21, $22
; at a fixed position (X=$10, Y=$90) for 100 frames, with a small inter-frame
; delay (~$FF * $20 iterations). Each frame:
; 1. Erases previous sprite frame at (aA3, aA4).
; 2. Advances sprite index aB3 ($20->$21->$22->$20 wrap at $23).
; 3. Calls calc_sprite_ptr and draw_sprite_or_collision.
; 4. Polls scan_input_for_start; exits immediately if start is pressed.
; Called from attract_mode after story slide 2, before the next slide.
;
; Inputs: None
; Outputs: None
; Side Effects: Bitmap updated (animated sprite drawn); aborts if aB0 bit 7 set
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
attract_ship_animation
$B323a9 20lda#$20; start sprite index: frame 0 of 3-frame animation ; x-ref: $B25F
$B32585 b3stazp_pixel_mask
$B32720 9b abjsrcalc_sprite_ptr
$B32Aa9 10lda#$10; animation position: X=$10, Y=$90
$B32C85 a3stazp_pos_x
$B32Ea9 90lda#$90
$B33085 a4stazp_pos_y
$B332a9 64lda#$64
$B33485 b4stazp_loop_idx; outer loop: 100 animation frames
$B336a9 ffb_B336lda#$ff; inter-frame delay: ~$FF * $20 iterations ; x-ref: $B364
$B33885 1astazp_marker_idx
$B33Aa9 20b_B33Alda#$20; x-ref: $B344
$B33C85 3cstazp_attract_delay_ctr
$B33Ec6 3cb_B33Edeczp_attract_delay_ctr; x-ref: $B340
$B340d0 fcbneb_B33E
$B342c6 1adeczp_marker_idx
$B344d0 f4bneb_B33A
$B34620 41 abjsrerase_sprite; erase previous frame
$B349e6 b3inczp_pixel_mask
$B34Ba5 b3ldazp_pixel_mask
$B34Dc9 23cmp#$23; wrap sprite index: $20, $21, $22 -> back to $20
$B34Fd0 04bneb_B355
$B351a9 20lda#$20
$B35385 b3stazp_pixel_mask
$B35520 9b abb_B355jsrcalc_sprite_ptr; x-ref: $B34F
$B35820 ff aajsrdraw_sprite_or_collision
$B35B20 d2 b3jsrscan_input_for_start; draw next animation frame
$B35E24 b0bitzp_joy_fire; abort animation if start pressed
$B36030 04bmir_B366
$B362c6 b4deczp_loop_idx
$B364d0 d0bneb_B336
$B36660r_B366rts; x-ref: $B360
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
; Phase advancement bonus screen. Called every 4th level before incrementing
; the difficulty phase (a21). Clears the screen, plays a sound fanfare, draws
; the current phase graphic indexed by a21, displays a congratulatory string,
; waits ~1 second, then awards 7 bonus points to the player score.
;
; Inputs: a21 (current difficulty phase, selects which graphic to draw)
; Outputs: None
; Side Effects: Clears screen; triggers sound; draws phase graphic and text;
; delays ~1 second; adds 7 points to player score (sB12D).
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
show_phase_bonus_screen
$B36720 29 a4jsrclear_char_ram; clear screen ; x-ref: $A1C7
$B36A78sei
$B36Ba9 11lda#$11; trigger sound fanfare (channel indices/durations)
$B36D85 47stazp_snd_soprano_seq_idx
$B36F85 4bstazp_snd_soprano_step
$B371a9 03lda#$03
$B37385 43stazp_snd_soprano_dur
$B37558cli
$B376a5 21ldazp_current_phase; get low nibble of phase as sprite index
$B37829 0fand#$0f
$B37A18clc
$B37B69 d4adc#$d4; offset into graphic table ($D4 base)
$B37D20 9b abjsrcalc_sprite_ptr; compute bitmap address for phase graphic
$B380a9 80lda#$80; X position = $80, Y = $1C for primary graphic
$B38285 a3stazp_pos_x
$B384a9 1clda#$1c
$B38685 a4stazp_pos_y
$B38820 ff aajsrdraw_sprite_or_collision; draw primary phase graphic
$B38Ba5 21ldazp_current_phase
$B38D29 f0and#$f0; check high nibble — draw second graphic if nonzero
$B38Ff0 14beqb_B3A5
$B3914alsra
$B3924alsra
$B3934alsra
$B3944alsra
$B39569 d4adc#$d4
$B39720 9b abjsrcalc_sprite_ptr
$B39Aa9 78lda#$78; X position = $78 for secondary graphic
$B39C85 a3stazp_pos_x
$B39Ea9 1clda#$1c
$B3A085 a4stazp_pos_y
$B3A220 ff aajsrdraw_sprite_or_collision; draw secondary phase graphic
$B3A5a2 a1b_B3A5ldx#<phase_bonus_congrats_text; x-ref: $B38F
$B3A7a0 beldy#>phase_bonus_congrats_text
$B3A9a9 01lda#$01
$B3AB85 aestazp_step_x
$B3AD85 afstazp_step_y
$B3AF20 cc b2jsrdraw_graphic_string; draw congratulatory text string
$B3B220 bb b3jsrdelay_1_second; wait ~1 second
$B3B5a9 07lda#$07; award 7 bonus points
$B3B720 2d b1jsradd_score
$B3BA60rts
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
; Delay loop for approximately 1 second.
;
; Inputs: None
; Outputs: None
; Side Effects: Wastes exactly 1 million CPU cycles (~1 second at 1MHz) using
; nested loops and dummy writes to ROM addresses.
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
$B3BBa9 ffdelay_1_secondlda#$ff; setup outer loop counter (256) ; x-ref: $A0C8, $B3B2
$B3BD85 1astazp_marker_idx
$B3BFa9 ffb_B3BFlda#$ff; setup inner loop counter (256) ; x-ref: $B3CF
$B3C185 3cstazp_attract_delay_ctr
$B3C3c6 3cb_B3C3deczp_attract_delay_ctr; 5 cycles ; x-ref: $B3CB
$B3C58d ad a1stainit_new_game; 4 cycles (dummy ROM write)
$B3C88d bd a1stainit_new_game_rts; 4 cycles (dummy ROM write)
$B3CBd0 f6bneb_B3C3; 3 cycles (branch taken) = 16 cycles loop
$B3CDc6 1adeczp_marker_idx
$B3CFd0 eebneb_B3BF
$B3D160rts
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
; Scans joysticks and keyboard for a "Game Start" input during attract mode.
;
; Inputs: None
; Outputs: Sets aB0 to $80 if start is triggered.
; Side Effects: Calls KERNAL keyboard and custom joystick scan routines.
; Depending on the input (F-keys or joystick buttons), it configures
; the selected game mode and player sprite pointers. Also contains a
; hidden cheat/easter-egg check for modifier keys.
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
$B3D220 9f ffscan_input_for_startjsrKERNAL_CSCNKEY; scan keyboard via KERNAL ; x-ref: $B2BC, $B307, $B35B
$B3D520 a6 a8jsrread_joystick; scan joystick 1
$B3D8a5 b0ldazp_joy_fire; check if joystick 1 triggered start
$B3DAd0 2bbneoption_joystick
$B3DC20 01 a9jsrread_paddle_input; scan joystick 2
$B3DFa5 b0ldazp_joy_fire; check if joystick 2 triggered start
$B3E1d0 14bneb_B3F7
$B3E320 e4 ffjsrKERNAL_CGETL; get character from keyboard buffer
$B3E6aatax
$B3E7c9 85cmp#PetsciiShifted.KEY_F1; check for F1
$B3E9f0 1cbeqoption_joystick
$B3EBc9 89cmp#PetsciiShifted.KEY_F2; check for F2
$B3EDf0 18beqoption_joystick
$B3EFc9 86cmp#PetsciiShifted.KEY_F3; check for F3
$B3F1f0 04beqb_B3F7
$B3F3c9 8acmp#PetsciiShifted.KEY_F4; check for F4
$B3F5d0 2abneb_B421
$B3F7a9 01b_B3F7lda#<read_paddle_input; configure game mode A ; x-ref: $B3E1, $B3F1
$B3F98d 7e 1dstainput_dispatch_lo
$B3FCa9 a9lda#>read_paddle_input
$B3FE8d 7f 1dstainput_dispatch_hi
$B401e0 8acpx#$8a
$B403f0 13beqb_B418
$B405d0 0ebneb_B415
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
; Configures the game for Joystick 1 control and sets the number of lives.
; Called when the player presses F1, F2, or the joystick button during attract mode.
;
; Inputs: X = PETSCII key code (if started via keyboard)
; Outputs: player_lives = 2 or 4 (based on F-key pressed)
; joy_fire = $80 (signals start to abort attract mode)
; input_dispatch vector points to read_joystick
; Side Effects: Patches the input_dispatch vector with the handler routine
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
$B407a9 a6option_joysticklda#<read_joystick; configure game mode B ; x-ref: $B3DA, $B3E9, $B3ED
$B4098d 7e 1dstainput_dispatch_lo; Patch input vector LSB
$B40Ca9 a8lda#>read_joystick
$B40E8d 7f 1dstainput_dispatch_hi; Patch input vector MSB
$B411e0 89cpx#$89; Check if F2 was pressed
$B413f0 03beqb_B418; If F2, jump to give 4 lives
$B415a9 02b_B415lda#$02; Else, give 2 lives ; x-ref: $B405
$B417.byte$2c; BIT trick to skip next instruction
$B418a9 04b_B418lda#$04; Give 4 lives (F2 or F4) ; x-ref: $B403, $B413
$B41A85 1fstazp_player_lives; Store selected number of lives
$B41Ca9 80lda#$80; Set game start flag ($80)
$B41E85 b0stazp_joy_fire; Write to joy_fire to abort attract mode
$B42060rts
$B421ae 8d 02b_B421ldxMODIFIER_KEYS; Read KERNAL modifier key flag (Shift/C=) ; x-ref: $B3F5
$B424e0 07cpx#$07; Check if Shift + C= + Ctrl are held down
$B426f0 04beqb_B42C; If yes, activate secret mode
$B42820 38 b4jsrhandle_display_settings_key; Else, process normal F-keys
$B42B60rts
$B42Ca9 08b_B42Clda#VicColors.ORANGE; Load color value (Black) ; x-ref: $B426
$B42E8d 0f 90sta$900f; Update VIC border/background color
$B431a9 01lda#VicColors.WHITE; Load flag/color value
$B43385 27stazp_playfield_color; Set playfield color
$B43585 62stazp_show_score_table; Enable special feature
$B43760rts
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
; Handles keyboard shortcuts to adjust display settings.
; $1D (CRSR RIGHT): Shift screen right
; $11 (CRSR DOWN) : Shift screen down
; $8C : Toggle interlace mode
; $87 : Cycle background color
; $88 : Cycle border color
;
; Inputs: A = PETSCII key code
; Outputs: None
; Side Effects: Modifies VIC registers $9000, $9001, $900F, and color RAM
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
handle_display_settings_key
$B438aatax; X = key code ; x-ref: $B428
$B439a9 01lda#$01
$B43Be0 1dcpx#$1d; Check for CRSR RIGHT
$B43Dd0 0cbneb_B44B
$B43F18clc
$B4406d 00 90adc$9000; Add 1 to horizontal origin
$B44329 8fand#$8f
$B44509 01ora#$01
$B4478d 00 90sta$9000
$B44A60rts
$B44Be0 11b_B44Bcpx#$11; Check for CRSR DOWN ; x-ref: $B43D
$B44Dd0 0cbneb_B45B
$B44F18clc
$B4506d 01 90adc$9001; Add 1 to vertical origin
$B45329 3fand#$3f
$B45509 01ora#$01
$B4578d 01 90sta$9001
$B45A60rts
$B45Be0 8cb_B45Bcpx#$8c; Check for key $8C ; x-ref: $B44D
$B45Dd0 09bneb_B468
$B45Fad 00 90lda$9000
$B46249 80eor#$80; Toggle interlace bit
$B4648d 00 90sta$9000
$B46760rts
$B468e0 87b_B468cpx#$87; Check for key $87 ; x-ref: $B45D
$B46Ad0 11bneb_B47D
$B46Cad 0f 90lda$900f
$B46F18clc
$B47069 10adc#$10; Cycle background color
$B47229 77and#$77
$B47418clc
$B47569 01adc#$01
$B47709 08ora#$08
$B4798d 0f 90sta$900f
$B47C60rts
$B47De0 88b_B47Dcpx#$88; Check for key $88 ; x-ref: $B46A
$B47Fd0 0bbner_B48C
$B481e6 27inczp_playfield_color; Cycle border color
$B483a5 27ldazp_playfield_color
$B48529 07and#$07
$B48785 27stazp_playfield_color
$B48920 52 a4jsrfill_color_ram; Update color RAM
$B48C60r_B48Crts; x-ref: $B47F
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
; Ignores NMI interrupts (likely triggered by the RESTORE key) by restoring
; registers and returning immediately.
;
; Inputs: None (assumes Y, X, A are pushed on stack by KERNAL)
; Outputs: Restores Y, X, A registers
; Side Effects: Reads $9111 (VIA 1 Port A)
; =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
$B48D2c 11 91ignore_nmibit$9111; dummy read of VIA 1 Port A ; x-ref: $A002
$B49068pla; pull Y
$B491a8tay
$B49268pla; pull X
$B493aatax
$B49468pla; pull A
$B49540rti; return from interrupt
; ROM table of 8x8 pixel glyph shapes (8 bytes each).
; Indexed by frame number via calc_sprite_ptr: addr = $B496 + (index * 8).
; Contains all game sprites (player ship, enemy ships, bullets, icons) and
; the large logo tiles used in attract mode screens.
$B496sprite_glyph_table.byte$c0, $30, $2c, $23, $2c, $30, $c0, $00
$B49E.byte$00, $00, $ff, $22, $24, $18, $10, $20
$B4A6.byte$01, $0e, $32, $c2, $24, $14, $08, $08
$B4AE.byte$04, $0c, $14, $24, $64, $9c, $04, $04
$B4B6.byte$10, $10, $28, $28, $44, $7c, $82, $82
$B4BE.byte$20, $30, $28, $24, $26, $39, $20, $20
$B4C6.byte$80, $60, $5c, $23, $24, $28, $10, $10
$B4CE.byte$00, $00, $ff, $44, $24, $18, $08, $04
$B4D6.byte$03, $0c, $34, $c4, $34, $0c, $03, $00
$B4DE.byte$04, $08, $18, $24, $44, $ff, $00, $00
$B4E6.byte$10, $10, $28, $24, $23, $5c, $60, $80
$B4EE.byte$20, $20, $39, $26, $24, $28, $30, $20
$B4F6.byte$82, $82, $7c, $44, $28, $28, $10, $10
$B4FE.byte$04, $04, $9c, $64, $24, $14, $0c, $04
$B506.byte$08, $08, $14, $24, $c4, $3a, $06, $01
$B50E.byte$20, $10, $18, $24, $22, $ff, $00, $00
$B516.byte$c0, $30, $6c, $e3, $6c, $30, $c0, $00
$B51E.byte$00, $00, $ff, $22, $64, $78, $10, $20
$B526.byte$01, $0e, $32, $c2, $24, $74, $68, $08
$B52E.byte$04, $0c, $14, $24, $64, $bc, $34, $04
$B536.byte$10, $10, $28, $28, $44, $7c, $ba, $92
$B53E.byte$20, $30, $28, $24, $26, $3d, $2c, $20
$B546.byte$80, $60, $5c, $23, $24, $2e, $16, $10
$B54E.byte$00, $00, $ff, $44, $26, $1e, $08, $04
$B556.byte$03, $0c, $36, $c7, $36, $0c, $03, $00
$B55E.byte$04, $08, $1e, $26, $44, $ff, $00, $00
$B566.byte$10, $16, $2e, $24, $23, $5c, $60, $80
$B56E.byte$20, $2c, $3d, $26, $24, $28, $30, $20
$B576.byte$92, $ba, $7c, $44, $28, $28, $10, $10
$B57E.byte$04, $34, $bc, $64, $24, $14, $0c, $04
$B586.byte$08, $68, $74, $24, $c4, $3a, $06, $01
$B58E.byte$20, $10, $78, $64, $22, $ff, $00, $00
$B596.byte$00, $82, $54, $38, $6c, $10, $10, $10
$B59E.byte$00, $04, $98, $78, $7c, $08, $04, $00
$B5A6.byte$10, $10, $10, $28, $7c, $28, $44, $00
$B5AE.byte$18, $66, $42, $99, $bd, $42, $66, $18
$B5B6.byte$24, $3c, $c3, $5a, $7e, $c3, $3c, $24
$B5BE.byte$18, $66, $42, $81, $81, $42, $66, $18
$B5C6.byte$24, $3c, $c3, $42, $42, $c3, $3c, $24
$B5CE.byte$10, $28, $44, $fe, $44, $28, $10, $00
$B5D6.byte$10, $28, $44, $fe, $00, $00, $00, $00
$B5DE.fill8, $ff
$B5E6.fill8, $00
$B5EE.byte$04, $04, $08, $10, $20, $40, $40, $00
$B5F6.byte$7c, $82, $ba, $a2, $a2, $ba, $82, $7c
$B5FE.byte$00, $00, $00, $01, $09, $05, $00, $1c
$B606.byte$00, $00, $00, $00, $20, $40, $00, $70
$B60E.byte$00, $05, $09, $00, $00, $00, $00, $00
$B616.byte$00, $40, $20, $00, $00, $00, $00, $00
$B61E.byte$09, $49, $25, $10, $c0, $20, $00, $e0
$B626.byte$20, $24, $48, $10, $06, $08, $00, $0e
$B62E.byte$00, $20, $c0, $10, $25, $49, $09, $01
$B636.byte$00, $08, $06, $10, $48, $24, $20, $00
$B63E.byte$00, $00, $00, $00, $00, $00, $02, $01
$B646.byte$00, $00, $00, $00, $10, $92, $54, $55
$B64E.byte$00, $00, $00, $00, $00, $00, $80, $00
$B656.byte$00, $06, $00, $0f, $00, $06, $00, $01
$B65E.byte$92, $54, $00, $c7, $00, $54, $92, $55
$B666.byte$00, $c0, $00, $e0, $00, $c0, $00, $00
$B66E.byte$02, $00, $00, $00, $00, $00, $00, $00
$B676.byte$54, $92, $10, $00, $00, $00, $00, $00
$B67E.byte$80, $00, $00, $00, $00, $00, $00, $00
$B686.byte$02, $02, $21, $11, $08, $04, $00, $60
$B68E.byte$10, $10, $11, $11, $82, $00, $00, $00
$B696.byte$80, $80, $08, $10, $20, $40, $00, $0c
$B69E.byte$18, $00, $00, $f0, $00, $00, $18, $60
$B6A6.fill8, $00
$B6AE.byte$30, $00, $00, $1e, $00, $00, $30, $0c
$B6B6.byte$00, $04, $08, $11, $21, $02, $02, $00
$B6BE.byte$00, $00, $82, $11, $11, $10, $10, $10
$B6C6.byte$00, $40, $20, $10, $08, $80, $80, $00
$B6CE.byte$e0, $a0, $a0, $a0, $e0, $00, $00, $00
$B6D6.byte$40, $c0, $40, $40, $e0, $00, $00, $00
$B6DE.byte$e0, $20, $60, $80, $e0, $00, $00, $00
$B6E6.byte$e0, $20, $40, $20, $e0, $00, $00, $00
$B6EE.byte$a0, $a0, $e0, $20, $20, $00, $00, $00
$B6F6.byte$e0, $80, $c0, $20, $c0, $00, $00, $00
$B6FE.byte$60, $80, $e0, $a0, $e0, $00, $00, $00
$B706.byte$e0, $20, $40, $80, $80, $00, $00, $00
$B70E.byte$e0, $a0, $e0, $a0, $e0, $00, $00, $00
$B716.byte$e0, $a0, $e0, $20, $20, $00, $00, $00
$B71Ewave_icon_tbl.byte$65, $72, $6f, $63, $73, $2a, $68, $67; x-ref: $AD3C
$B726.byte$69, $68
; draw_graphic_string data: scoring table screen.
; Drawn conditionally (only when a62 != 0). Ends with $FF.
$B728gfx_attract_slide_2.byte$18, $10, $08, $93, $86, $80, $7d, $93; x-ref: $B1F9, $B1FB
$B730.byte$82, $8f, $90, $86, $8c, $8b, $7d, $7f
$B738.byte$96, $00, $24, $38, $08, $7e, $8b, $81
$B740.byte$96, $7d, $83, $86, $8b, $88, $82, $89
$B748.byte$00, $4b, $4e, $04, $77, $69, $6b, $00
$B750.byte$24, $68, $08, $82, $8f, $86, $80, $7d
$B758.byte$80, $8c, $91, $91, $8c, $8b, $00, $40
$B760.byte$88, $08, $d7, $2b, $dc, $d6, $ff, $00
$B768.byte$00, $00, $00, $00, $00, $00, $f0, $f0
$B770.byte$f0, $f0, $f0, $00, $00, $00, $ff, $9b
$B778.byte$b3, $9b, $bb, $b1, $ff, $00, $ff, $89
$B780.byte$bd, $99, $bd, $b9, $ff, $00, $ff, $91
$B788.byte$b7, $91, $bd, $b1, $ff, $00, $ff, $91
$B790.byte$bd, $9d, $bd, $bd, $ff
$B795.fill9, $00
$B79E.byte$40, $a0, $e0, $a0, $a0, $00, $00, $00
$B7A6.byte$c0, $a0, $c0, $a0, $c0, $00, $00, $00
$B7AE.byte$60, $80, $80, $80, $60, $00, $00, $00
$B7B6.byte$c0, $a0, $a0, $a0, $c0, $00, $00, $00
$B7BE.byte$e0, $80, $c0, $80, $e0, $00, $00, $00
$B7C6.byte$e0, $80, $c0, $80, $80, $00, $00, $00
$B7CE.byte$60, $80, $80, $a0, $60, $00, $00, $00
$B7D6.byte$a0, $a0, $e0, $a0, $a0, $00, $00, $00
$B7DE.byte$e0, $40, $40, $40, $e0, $00, $00, $00
$B7E6.byte$e0, $40, $40, $40, $80, $00, $00, $00
$B7EE.byte$a0, $a0, $c0, $a0, $a0, $00, $00, $00
$B7F6.byte$80, $80, $80, $80, $e0, $00, $00, $00
$B7FE.byte$a0, $e0, $a0, $a0, $a0, $00, $00, $00
$B806.byte$c0, $a0, $a0, $a0, $a0, $00, $00, $00
$B80E.byte$40, $a0, $a0, $a0, $40, $00, $00, $00
$B816.byte$c0, $a0, $c0, $80, $80, $00, $00, $00
$B81E.byte$40, $a0, $a0, $a0, $60, $00
; ROM table of 8x8 pixel shapes for the small text font (8 bytes each).
; Contains glyphs for digits 0-9 and uppercase/lowercase letters used
; in the attract mode text slides (story text, copyright lines, etc.).
$B824small_font_glyphs.byte$00, $00, $c0, $a0, $c0, $a0, $a0, $00
$B82C.byte$00, $00, $e0, $80, $e0, $20, $e0, $00
$B834.byte$00, $00, $e0, $40, $40, $40, $40, $00
$B83C.byte$00, $00, $a0, $a0, $a0, $a0, $e0, $00
$B844.byte$00, $00, $a0, $a0, $a0, $a0, $40, $00
$B84C.byte$00, $00, $a0, $a0, $a0, $e0, $a0, $00
$B854.byte$00, $00, $a0, $a0, $40, $a0, $a0, $00
$B85C.byte$00, $00, $a0, $a0, $40, $40, $40, $00
$B864.byte$00, $00, $e0, $20, $40, $80, $e0, $00
$B86C.byte$00, $00, $00, $00, $00, $40, $40, $80
$B874.byte$00, $00, $00, $00, $00, $00, $40
$B87B.fill11, $00
$B886.byte$30, $48, $84, $fc, $84, $84, $84, $00
$B88E.byte$f8, $84, $84, $f8, $84, $84, $f8, $00
$B896.byte$fc, $80, $80, $80, $80, $80, $fc, $00
$B89E.byte$f8, $84, $84, $84, $84, $84, $f8, $00
$B8A6.byte$fc, $80, $80, $f8, $80, $80, $fc, $00
$B8AE.byte$fc, $80, $80, $f8, $80, $80, $80, $00
$B8B6.byte$fc, $80, $8c, $84, $84, $84, $fc, $00
$B8BE.byte$84, $84, $84, $fc, $84, $84, $84, $00
$B8C6.byte$70, $20, $20, $20, $20, $20, $70, $00
$B8CE.byte$08, $08, $08, $08, $08, $88, $78, $00
$B8D6.byte$88, $90, $e0, $a0, $90, $88, $88, $00
$B8DE.byte$80, $80, $80, $80, $80, $80, $fc, $00
$B8E6.byte$84, $cc, $b4, $84, $84, $84, $84, $00
$B8EE.byte$84, $c4, $a4, $94, $8c, $84, $84, $00
$B8F6.byte$fc, $84, $84, $84, $84, $84, $fc, $00
$B8FE.byte$fc, $84, $84, $fc, $80, $80, $80, $00
$B906.byte$fc, $84, $84, $84, $94, $88, $f4, $00
$B90E.byte$fc, $84, $84, $fc, $a0, $90, $88, $00
$B916.byte$fc, $80, $80, $fc, $04, $04, $fc, $00
$B91E.byte$7c, $10, $10, $10, $10, $10, $10, $00
$B926.byte$84, $84, $84, $84, $84, $84, $fc, $00
$B92E.byte$44, $44, $44, $44, $28, $28, $10, $00
$B936.byte$84, $84, $84, $84, $b4, $cc, $84, $00
$B93E.byte$44, $44, $28, $10, $28, $44, $44, $00
$B946.byte$44, $44, $28, $10, $10, $10, $10, $00
$B94E.byte$fc, $04, $08, $10, $20, $40, $fc, $00
$B956.byte$00, $00, $00, $00, $10, $10, $20, $00
$B95E.byte$00, $00, $00, $00, $00, $10, $10, $00
$B966.byte$00, $00, $00, $01, $03, $07, $0f, $1e
$B96E.byte$07, $1f, $7f, $f8, $e0, $c1, $07, $1f
$B976.byte$ff, $ff, $ff, $00, $00, $fc, $ff, $ff
$B97E.byte$00, $c0, $f0, $fc, $3e, $1f, $07, $c3
$B986.byte$00, $00, $00, $00, $00, $00, $80, $ff
$B98E.byte$00, $00, $00, $00, $00, $00, $00, $ff
$B996.byte$1c, $3c, $38, $71, $71, $e3, $e3, $e7
$B99E.byte$3e, $78, $f1, $e7, $cf, $9e, $9c, $38
$B9A6.byte$03, $00, $fc, $ff, $ff, $03, $01, $00
$B9AE.byte$e1, $f1, $78, $3c, $9c, $ce, $ce, $e7
$B9B6.byte$ff, $ff, $00, $00, $7f, $7f, $7f, $70
$B9BE.byte$ff, $ff, $00, $00, $e1, $f1, $f9, $3c
$B9C6.byte$ff, $ff, $00, $00, $ff, $ff, $ff, $00
$B9CE.byte$ff, $ff, $00, $00, $03, $0f, $1f, $3e
$B9D6.byte$ff, $ff, $00, $00, $e0, $e0, $e0, $00
$B9DE.byte$ff, $ff, $00, $00, $e0, $e0, $e0, $70
$B9E6.byte$ff, $ff, $00, $00, $1f, $1f, $1f, $00
$B9EE.byte$ff, $ff, $00, $00, $f0, $f8, $fc, $1c
$B9F6.byte$ff, $ff, $00, $00, $1c, $1c, $1c, $0e
$B9FE.byte$ff, $ff, $00, $00, $03, $0f, $1f, $3e
$BA06.byte$ff, $ff, $00, $00, $df, $df, $df
$BA0D.fill8, $00
$BA15.byte$f0, $e0, $e0, $00, $00, $80, $00, $00
$BA1D.byte$00, $e7, $e7, $e7, $e7, $e7, $e7, $e3
$BA25.byte$e3, $38, $38, $38, $38, $38, $38, $9c
$BA2D.byte$9e, $00, $00, $00, $00, $00, $00, $01
$BA35.byte$03, $e7, $e7, $e7, $e7, $e7, $e7, $ce
$BA3D.byte$ce, $70, $73, $73, $73, $73, $73, $73
$BA45.byte$73, $1c, $9d, $9d, $9d, $9d, $9d, $9d
$BA4D.byte$9d, $00, $ff, $ff, $ff, $c0, $c0, $ff
$BA55.byte$ff, $38, $79, $71, $79, $38, $3e, $1f
$BA5D.byte$0f, $00, $e1, $e3, $e3, $03, $27, $e7
$BA65.byte$e7, $70, $f0, $b8, $b8, $b8, $1c, $fc
$BA6D.byte$fc, $00, $1f, $1f, $1f, $1c, $1c, $1c
$BA75.byte$1c, $1c, $f8, $f0, $f8, $38, $1c, $1c
$BA7D.byte$1c, $0e, $3e, $77, $77, $77, $e3, $ff
$BA85.byte$ff, $38, $70, $70, $70, $38, $be, $9f
$BA8D.byte$8f, $00, $1f, $1f, $1f, $1c, $1c, $df
$BA95.byte$df, $00, $fc, $f8, $f8, $00, $00, $e0
$BA9D.byte$c0, $71, $71, $38, $3c, $1c, $1e, $0f
$BAA5.byte$07, $cf, $e7, $f1, $78, $3e, $1f, $07
$BAAD.byte$c1, $ff, $ff, $fc, $00, $03, $ff, $ff
$BAB5.byte$fc, $9c, $3c, $78, $f1, $e1, $c3, $07
$BABD.byte$1f, $73, $00, $00, $ff, $ff, $ff, $00
$BAC5.byte$00, $9d, $00, $00, $ff, $ff, $ff, $00
$BACD.byte$00, $ff, $00, $00, $ff, $ff, $ff, $00
$BAD5.byte$00, $03, $00, $00, $ff, $ff, $ff, $00
$BADD.byte$00, $cf, $00, $00, $ff, $ff, $ff, $00
$BAE5.byte$00, $fe, $00, $00, $ff, $ff, $ff, $00
$BAED.byte$00, $1c, $00, $00, $ff, $ff, $ff, $00
$BAF5.byte$00, $1d, $00, $00, $ff, $ff, $ff, $00
$BAFD.byte$00, $c3, $00, $00, $ff, $ff, $ff, $00
$BB05.byte$00, $df, $00, $00, $ff, $fe, $fe, $00
$BB0D.byte$00, $c0, $00, $00, $00, $00, $00, $00
$BB15.byte$00, $03, $01, $00, $00, $00, $00, $00
$BB1D.byte$00, $e0, $f8, $7f, $1f, $07, $00, $00
$BB25.byte$00, $00, $00, $ff, $ff, $ff, $00, $00
$BB2D.byte$00, $3e, $fc, $f0, $c0, $00, $00, $00
$BB35.byte$00, $78, $84, $84, $84, $84, $84, $78
$BB3D.byte$00, $10, $30, $10, $10, $10, $10, $38
$BB45.byte$00, $38, $44, $04, $08, $10, $20, $7c
$BB4D.byte$00, $38, $44, $04, $08, $04, $44, $38
$BB55.byte$00, $44, $44, $44, $7c, $04, $04, $04
$BB5D.byte$00, $7c, $40, $78, $04, $04, $44, $38
$BB65.byte$00, $3c, $40, $78, $44, $44, $44, $7c
$BB6D.byte$00, $7c, $04, $08, $10, $20, $40, $40
$BB75.byte$00, $7c, $44, $44, $7c, $44, $44, $7c
$BB7D.byte$00, $7c, $44, $44, $7c, $04, $04, $04
$BB85.byte$00
; draw_graphic_string data: OMEGA RACE title logo (glyphs $9A-$D3 = large 5-row
; logo tiles spanning Y=62-94) followed by copyright text rows at Y=126/138.
; Drawn with a red/yellow Color RAM gradient pre-set by attract_mode.
; Terminates with $FF at $BC0F.
$BB86gfx_attract_slide_1.byte$09, $3e, $08, $9a, $9b, $9c, $9d, $9e; x-ref: $B1DA, $B1DC
$BB8E.fill11, $9f
$BB99.byte$af, $00, $09, $46, $08, $a0, $a1, $a2
$BBA1.byte$a3, $a4, $a5, $a6, $a7, $a8, $a9, $aa
$BBA9.byte$ab, $ac, $ad, $ae, $a6, $b0, $00, $09
$BBB1.byte$4e, $08, $b1, $b2, $b3, $b4, $b5, $b6
$BBB9.byte$b7, $b8, $b9, $ba, $bb, $bc, $bd, $be
$BBC1.byte$bf, $c0, $00, $09, $56, $08
.encode
.enc"none"
$BBC7.text$c1, $c2, $c3, $c4, $c5, $c6, $c7, $c8, $c9, $ca, $cb, $cc, $c7, $cd, $ce, $cf
.endencode
$BBD7.byte$00, $09, $5e, $08, $d0, $d1, $d2, $d3
$BBDF.byte$00, $20, $7e, $04
$BBE3.byte$2c, $60; (c)
$BBE5.byte$48, $50, $4f, $49, $60; 1982
.encode
.enc"none"
$BBEA.text"commodore`ltd|"
.endencode
$BBF8.byte$00, $20, $8a, $04
$BBFC.byte$2c; (c)
$BBFD.byte$60; space
$BBFE.byte$48, $50, $4f, $48; 1981
$BC02.byte$60; space
.encode
.enc"none"
$BC03.text"bally`midway"
.endencode
$BC0F.byte$ff
; draw_graphic_string data: title/logo copyright screen.
; Contains 5 segments (rows of glyph tiles) and ends with $FF at $BC66.
$BC10gfx_attract_slide_3.byte$18, $08, $08, $5c, $7d, $87, $8c, $96; x-ref: $B211, $B213
$BC18.byte$90, $91, $86, $80, $88, $00, $18, $20
$BC20.byte$08, $5d, $7d, $8d, $7e, $81, $81, $89
$BC28.byte$82, $7d, $00, $18, $38, $08, $5e, $7d
$BC30.byte$90, $80, $8f, $82, $82, $8b, $7d, $80
$BC38.byte$8c, $89, $8c, $8f, $00, $18, $50, $08
$BC40.byte$5f, $7d, $90, $85, $86, $8d, $7d, $80
$BC48.byte$8c, $89, $8c, $8f, $00, $1c, $70, $08
$BC50.byte$7f, $8c, $8b, $92, $90, $7d, $90, $85
$BC58.byte$86, $8d, $7d, $7e, $91, $00, $34, $88
$BC60.byte$08, $d8, $d4, $d4, $d4, $d4, $ff
; draw_graphic_string data: attract story slide 1.
; 'In the year 2003, the Omegan System developed a method of training its...'
; Segment header: X=$0A, Y=$18, step=$04, then small-font glyph indices.
; Character values use the small text font table at small_font_glyphs ($B824).
; Drawn with aAF=$FF (instant display, no typing delay).
$BC67gfx_story_slide_1.byte$0a, $18, $04; x-ref: $B232, $B234
.encode
.enc"none"
$BC6A.text"in`the`year`"
.endencode
$BC76.byte$49, $47, $47, $4a; 2003
.encode
.enc"none"
$BC7A.text"{`the`omegan`system"
.endencode
$BC8D.byte$00, $0c, $20, $04
.encode
.enc"none"
$BC91.text"developed`a`method`of`training`its"
.endencode
$BCB3.byte$00, $14, $28, $04
.encode
.enc"none"
$BCB7.text"warriors`to`protect`their`star"
.endencode
$BCD5.byte$00, $0e, $30, $04
.encode
.enc"none"
$BCD9.text"colonies|`over`the`city`of`komar{"
.endencode
$BCFA.byte$00, $0e, $38, $04
.encode
.enc"none"
$BCFE.text"android`controlled`fighters`raced"
.endencode
$BD1F.byte$00, $1a, $40, $04
.encode
.enc"none"
$BD23.text"to`engage`and`destroy`these"
.endencode
$BD3E.byte$00, $30, $48, $04
.encode
.enc"none"
$BD42.text"omegan`warriors|"
.endencode
$BD52.byte$00, $04, $70, $04
.encode
.enc"none"
$BD56.text"points`were`awarded`for`the`ability`to"
.endencode
$BD7C.byte$00, $02, $78, $04
.encode
.enc"none"
$BD80.text"neutralize`this`droid`force`as`follows|"
.endencode
$BDA7.byte$ff
attract_story_slide_2
$BDA8.byte$10, $10, $08, $28, $00, $10, $30, $08; x-ref: $B252, $B254
$BDB0.byte$27, $00, $10, $50, $08, $25, $00, $10
$BDB8.byte$70, $08, $23, $00, $10, $90, $08, $20
$BDC0.byte$00, $50, $10, $08, $d7, $d9, $d4, $7d
$BDC8.byte$8d, $8c, $86, $8b, $91, $90, $00, $50
$BDD0.byte$30, $08, $d9, $d4, $d4, $7d, $8d, $8c
$BDD8.byte$86, $8b, $91, $90, $00, $48, $50, $08
$BDE0.byte$d5, $d4, $d4, $d4, $7d, $8d, $8c, $86
$BDE8.byte$8b, $91, $90, $00, $48, $70, $08, $d5
$BDF0.byte$d9, $d4, $d4, $7d, $8d, $8c, $86, $8b
$BDF8.byte$91, $90, $00, $48, $90, $08, $d6, $d9
$BE00.byte$d4, $d4, $7d, $8d, $8c, $86, $8b, $91
$BE08.byte$90, $ff
attract_story_slide_3
$BE0A.byte$06, $20, $04; x-ref: $B26C, $B26E
.encode
.enc"none"
$BE0D.text"the`omegan`method`is`so`successful`it"
.endencode
$BE32.byte$00, $0c, $28, $04
.encode
.enc"none"
$BE36.text"commands`fear`and`respect`from`all"
.endencode
$BE58.byte$00, $18, $30, $04
.encode
.enc"none"
$BE5C.text"throughout`the`galaxies|`the"
.endencode
$BE78.byte$00, $22, $38, $04
.encode
.enc"none"
$BE7C.text"method`is`code`named|||"
.endencode
$BE93.byte$ff
wave_transition_graphic
$BE94.byte$2d, $30, $08, $84, $7e, $8a, $82, $7d; x-ref: $A0BB, $A0BD
$BE9C.byte$8c, $93, $82, $8f, $ff
phase_bonus_congrats_text
$BEA1.byte$18, $1c, $08, $81, $8f, $8c, $86, $81; x-ref: $B3A5, $B3A7
$BEA9.byte$7d, $83, $8c, $8f, $80, $82, $00, $28
$BEB1.byte$4c, $08, $82, $89, $86, $8a, $86, $8b
$BEB9.byte$7e, $91, $82, $81, $00, $08, $7c, $08
$BEC1.byte$d9, $99, $d4, $d4, $d4, $7d, $7f, $8c
$BEC9.byte$8b, $92, $90, $7d, $8d, $8c, $86, $8b
$BED1.byte$91, $90
$BED3snd_bass_freq_tbl.byte$ff, $8c; x-ref: $A0D5
$BED5snd_bass_dur_tbl.byte$00, $5a; x-ref: $A0EB
$BED7snd_alto_freq_tbl.byte$00, $af, $08, $b3, $08, $af, $08, $a0; x-ref: $A0F4
$BEDF.byte$08, $00, $fa, $f5, $f0, $eb, $e6, $dc
$BEE7.byte$d7, $c8, $be, $b4, $aa, $96, $00, $b4
$BEEF.byte$be, $c8, $cd, $d2, $d7, $dc, $e1, $e6
$BEF7.byte$eb, $f0, $f5, $fa, $ff, $00, $d9, $d4
$BEFF.byte$d9, $db, $df, $cf, $01, $d9, $d4, $d9
$BF07.byte$db, $df, $cf, $01, $d9, $d4, $d9, $db
$BF0F.byte$df, $cf, $01, $d9, $db, $d9, $db, $d4
$BF17snd_alto_dur_tbl.byte$00; x-ref: $A108, $A128
snd_alto_dur_tbl_offset1
$BF18.byte$12, $06, $12, $06, $12, $06, $12, $06; x-ref: $A218
$BF20.byte$00, $01, $01, $02, $03, $03, $02, $02
$BF28.byte$02, $02, $02, $01, $01, $00, $01, $01
$BF30.byte$01, $01, $01, $01, $02, $02, $02, $02
$BF38.byte$02, $02, $03, $09, $00, $05, $06, $06
$BF40.byte$08, $21, $14, $05, $06, $06, $06, $08
$BF48.byte$21, $14, $05, $06, $06, $06, $08, $21
$BF50.byte$14, $05, $06, $06, $06, $0a, $2d, $00
$BF58.byte$09, $03, $09, $03, $09, $03, $09, $03
$BF60.byte$00, $04, $02, $04, $02, $04, $02, $04
$BF68snd_soprano_freq_tbl.byte$02, $ff, $fa, $f5, $f0, $eb, $e6, $e1; x-ref: $A131
$BF70.byte$dc, $d7, $d2, $c8, $be, $b4, $af, $aa
$BF78.byte$00, $ee, $01, $ee, $01, $ee, $01, $ee
$BF80.byte$01, $ee, $01, $ee, $01, $ee, $01, $ee
$BF88.byte$00, $be, $c1, $be, $01
$BF8Dsnd_soprano_dur_tbl.byte$00; x-ref: $A147
$BF8E.fill15, $01
$BF9D.byte$00
$BF9E.fill15, $03
$BFAD.byte$00, $02, $02, $02
$BFB1snd_noise_freq_tbl.byte$04, $b4, $be, $c3, $c8, $cd, $d2, $d7; x-ref: $A150
$BFB9.byte$dc, $e1, $e6, $00, $cd, $01, $c8, $01
$BFC1.byte$c3, $01, $be, $01, $b4, $01, $8c, $00
$BFC9.byte$c8
$BFCAsnd_noise_dur_tbl.byte$00, $08, $08, $08, $08, $08, $08, $08; x-ref: $A166
$BFD2.byte$07, $07, $07, $00, $0f, $01, $0f, $01
$BFDA.byte$0f, $01, $0f, $01, $0f, $01, $0f, $00
$BFE2.byte$64, $03, $31, $82, $0f, $01, $0f, $01
$BFEA.byte$0f, $00, $64
$BFED.fill19, $aa