incsrc subroutinedefs_xkas.asm

!frame = $00C2
!left_hand_x_pos = $13E6
!left_hand_y_pos = $146C
!left_hand_y_speed = $1461
!left_hand_x_speed = $1473
!left_hand_y_acc_bits = $1475
!left_hand_x_acc_bits = $1879
!right_hand_x_pos = $146E
!right_hand_y_pos = $1869
!right_hand_x_speed = $1477
!right_hand_y_speed = $1479
!right_hand_x_acc_bits = $147B
!right_hand_y_acc_bits = $147D

!rat_x_pos = $140B
!rat_y_pos = $1415
!rat_x_speed = $14BE
!rat_y_speed = $14C1
!rat_y_acc_bits = $14C4
!rat_x_acc_bits = $14C7
!rat_direction = $1696
!rat_frame = $17BB
!rat_state = $1864
!rat_state_timer = $1926
!rat_state_extra = $0F72
!rat_priority = $191F
!rat_bob_off = $191B
!rat_bob_off_max = #$08
!rat_bob_off_min = #$F8

!attack_weight_table = $0F86

!sprite_y_pos_hi = $14D4
!sprite_y_pos_lo = $D8

!sprite_x_pos_hi = $14E0
!sprite_x_pos_lo = $E4

!sprite_x_speed = $B6
!sprite_y_speed = $AA

!sprite_x_acc_bits = $14F8
!sprite_y_acc_bits = $14EC

!left_hand_frame = $18B7
!right_hand_frame = $18BB
!left_hand_state = $18B4
!right_hand_state = $18A6
!left_hand_state_timer = $18C5 ;16bit
!right_hand_state_timer = $18C7 ;16bit
!left_hand_state_extra = $0F5E ;10 bytes
!right_hand_state_extra = $0F68 ;10 bytes

!sprite_spawn_x_lo = $0A
!sprite_spawn_x_hi = $0B
!sprite_spawn_y_lo = $0C
!sprite_spawn_y_hi = $0D
!sprite_spawn_x_speed = $0E
!sprite_spawn_y_speed = $0F
!sprite_spawn_return_slot = $09
!sprite_spawn_sprite_number = $7C

!bomb_position = $1510

!rat_clipping_standard = #$01

!rat_clipping_value = $0AF5

!state = $188E
!state_timer = $145E
!state_extra = $1E02 ;10 bytes. Not using cluster sprites, so cluster sprite tables besides sprite number are freeram
!interaction_callback = $1E0C
!left_hand_interaction_callback = $1E0E
!right_hand_interaction_callback = $1E10
!rat_interaction_callback = $1E12


!left_hand_delay_timer = $0F3A
!right_hand_delay_timer = $0F3B
!hand_delay_timer = $0F3C

!which_hand = $188A ;Which hand is currently being calculated. Left = 0, right = 1, none = FF

!robot_state = $1B7F ; Overall robot state. E.g. init, attacking, norveg jetpack, whatever. The other state variables are for the hands
!robot_state_timer = $1923

!sprite_horz_direction = $157C

!health = $1DEF
!robot_start_health = #$07
!rat_start_health = #$04

!hurt_timer = $0DA1
!rat_hurt_timer = $1F3B

!shake_timer = $1887

!smash_sound_effect = #$09
!smash_sound_bank = $1DFC
!slap_down_sound_effect = #$09
!slap_down_sound_bank = $1DFC

!x_off_pointer = $02
!y_off_pointer = $04
!tiles_pointer = $06
!tile_size_pointer = $08
!tile_props_pointer = $0A
!tile_count_tmp = $0E
!direction_tmp = $0F

!left_hand_start_x = #$0130
!right_hand_start_x = #$01C0
!hand_start_y = #$0140

!rat_start_x = #$01E0
!rat_start_y = #$0140

!hand_relaxed_frame = #$00
!hand_clenched_frame = #$01
!hand_slap_frame = #$02
!hand_slap_down_frame = #$03


!idle_state = #$00
!smash_state = #$01
!return_state = #$02
!slap_state = #$03
!slap_down_state = #$04
!dying_smash_state = #$05

!init_state_time = #$0100

!rat_standing_frame = #$00
!rat_talking_frame = #$01
!rat_press_button_1_frame = #$02
!rat_press_button_2_frame = #$03
!rat_jetpack_0_frame = #$04
!rat_jetpack_1_frame = #$05
!rat_jetpack_2_frame = #$06
!rat_jetpack_3_frame = #$07
!rat_jetpack_4_frame = #$08
!rat_jetpack_5_frame = #$09
!rat_controlling_1_frame = #$0A
!rat_controlling_2frame = #$0B
!rat_controlling_3_frame = #$0C

!rat_posing_state = #$00
!rat_to_robot_state = #$01
!rat_in_robot_state = #$02

!rat_pacing_state = #$04
!rat_spinning_state = #$05
!rat_tracking_state = #$06
!rat_bomb_throwing_state = #$07
!rat_hit_falling_state = #$08
!rat_dying_state = #$09

!bomb_sprite_number = #$AC

!num_rat_attacks = #$03

!num_attacks = $0A

!rat_posing_timer = #$0080


!update_sprite_y_pos_no_gravity = $81801A
!update_sprite_x_pos_no_gravity = $818022
!update_sprite_pos_with_gravity = $81802A
!GetMarioClipping = $83B664
!CheckForContact = $83B72B
!hurt_mario = $80F5B7

!layer_1_x_pos_next_frame = $1462
!layer_1_y_pos_next_frame = $1464
!layer_2_x_pos_next_frame = $1466
!layer_2_y_pos_next_frame = $1468

!get_random_number = $81ACF9

!XMovement = $1534

!num_robot_attacks = #$03

!lava_y_pos_max = #$00C8
!lava_y_pos_min = #$00A0
!lava_x_pos = #$0000
!lava_y_pos = $1B97

!layer_1_y_pos_min = #$0090

print "INIT ",pc
    ; sufficiently shuffle the random number seed so we don't get the same thing every time
    phx
    ldx $13
    -
    phx
    jsl !get_random_number
    plx
    dex
    bpl -
    ldx.b !num_robot_attacks-1
    -
    stz !attack_weight_table,x
    dex
    bpl -
    plx
    stz !robot_state
    stz !hurt_timer
    lda !hand_relaxed_frame
    sta !left_hand_frame
    sta !right_hand_frame
    lda !idle_state
    sta !left_hand_state
    sta !right_hand_state
    lda !robot_start_health
    sta !health
    lda !rat_standing_frame
    sta !rat_frame
    lda !rat_posing_state
    sta !rat_state
    rep #$20
    lda !init_state_time
    sta !robot_state_timer
    lda !left_hand_start_x
    sta !left_hand_x_pos
    lda !hand_start_y
    sta !left_hand_y_pos
    sta !right_hand_y_pos
    lda !right_hand_start_x
    sta !right_hand_x_pos
    lda !rat_posing_timer
    sta !rat_state_timer
    lda !rat_start_x
    sta !rat_x_pos
    lda !rat_start_y
    sta !rat_y_pos
    stz !rat_state_extra
    stz !lava_y_pos
    sep #$20
    rtl


print "MAIN ",pc            
    phb
    phk
    plb
    jsr SPRITE_ROUTINE          ;Jump to the routine to keep organized
    plb
    rtl

SPRITE_ROUTINE:
    rep #$20
    lda !lava_y_pos
    sta !layer_2_y_pos_next_frame
    lda !lava_x_pos
    sta !layer_2_x_pos_next_frame
    sep #$20
    jsr handle_hands
    jsr handle_rat
    lda $9D
    beq +
        jmp .return
    +
    lda !hurt_timer
    beq +
        dec !hurt_timer
    +
    lda !rat_hurt_timer
    beq +
        dec !rat_hurt_timer
    +
    lda !robot_state
    bne +
    jmp .do_rat
    +
    ;cmp #$01
    ;bne +
    ;    jmp .do_rat
    ;+
    ; +++
    ;    rep #$20
    ;    lda !robot_state_timer
    ;    bne +
    ;        sep #$20
    ;        inc !robot_state
    ;        jmp .do_rat
    ;    +
    ;    dec !robot_state_timer
    ;    sep #$20
    ;    jmp .do_rat
    ;+++
    cmp #$01
    bne +
        jmp .attacking
    + 
    cmp #$02
    bne +
        jmp .robot_dying_wait_for_return
    +
    cmp #$03
    bne +
        jmp .robot_dying
    +
    cmp #$04
    bne +
        jmp .lava_rising
    +
    cmp #$05
    bne +
        jmp .camera_rising
    +
    jmp .do_rat
    .attacking
    lda !health
    bne +
        inc !robot_state ;Robot dying waiting for hands to return
        jmp ++
    +
    jsr calc_routines
    ++
    jsr copy_left_hand
    jsr do_routine
    jsr restore_left_hand
    jsr copy_right_hand
    jsr do_routine
    jsr restore_right_hand
    jmp .do_rat
    .robot_dying_wait_for_return
    lda !left_hand_state
    beq +
        jsr copy_left_hand
        jsr do_routine
        jsr restore_left_hand
    +
    lda !right_hand_state
    beq +
        jsr copy_right_hand
        jsr do_routine
        jsr restore_right_hand
    +
    lda !right_hand_state
    ora !left_hand_state
    bne +
        inc !robot_state ; Dying state
    +
    jmp .do_rat
    .robot_dying
        lda !left_hand_state
        cmp !dying_smash_state
        beq +
            lda !dying_smash_state
            sta !left_hand_state
            sta !right_hand_state
            stz !left_hand_state_extra
            stz !right_hand_state_extra
            stz !left_hand_state_extra+1
            stz !right_hand_state_extra+1
        +
        jsr copy_left_hand
        jsr do_routine
        jsr restore_left_hand
        jsr copy_right_hand
        jsr do_routine
        jsr restore_right_hand
        lda !left_hand_state_extra+1
        beq +
        lda !right_hand_state_extra
        beq +
            inc !robot_state
            lda #$C8
            sta !shake_timer
            lda #$2C
            sta $1DF9
        +
        jmp .do_rat
    .lava_rising
        jsr blink_arrow
        rep #$20
        lda !lava_y_pos
        inc
        sta !lava_y_pos
        cmp !lava_y_pos_max
        bcc +
            lda !lava_y_pos_max
            sta !lava_y_pos
            inc !robot_state
            inc !rat_state
            stz !rat_state_extra
            sep #$20
            lda #$2D
            sta $1DF9
        +
        sep #$20
        jmp .do_rat
    .camera_rising
        rep #$20
        dec !lava_y_pos
        lda !layer_1_y_pos_next_frame
        dec
        sta !layer_1_y_pos_next_frame
        cmp !layer_1_y_pos_min
        bcs +
            sep #$20
            inc !robot_state
            phx
            ldx.b !num_rat_attacks-1
            -
            stz !attack_weight_table,x
            dex
            bpl -
            plx
            lda !rat_start_health
            sta !health
        +
        sep #$20
        jmp .do_rat
    .do_rat
    jsr copy_rat
    lda !rat_state
    asl
    phx
    tax
    rep #$20
    lda rat_states,x
    sta $00
    sep #$20
    plx
    pea .rat_return-1
    jmp ($0000)
    .rat_return
    jsr restore_rat
    .return
    rts

rat_states:
    dw rat_posing_state
    dw rat_to_robot
    dw rat_in_robot
    dw rat_leaving_robot
    dw rat_pacing
    dw rat_spinning
    dw rat_tracking
    dw rat_bomb_throw
    dw rat_hit_falling
    dw rat_dying

rat_posing_state:
    stz !rat_clipping_value
    stz !rat_bob_off
    lda !rat_state_extra
    bne +
        jmp .laughing
    +
    cmp #$01
    bne +
        jmp .pressing_button
    +
    cmp #$02
    bne +
        jmp .igniting_jetpack
    +
    lda !rat_to_robot_state
    sta !rat_state
    stz !rat_state_extra
    rts
    .laughing
        lda !rat_state_timer
        lsr #3
        and #$01
        sta !frame,x
        rep #$20
        lda !rat_state_timer
        dec
        bne +
            sep #$20
            inc !rat_state_extra
            rep #$20
            lda #$0040
        +
        sta !rat_state_timer
        sep #$20
        rts
    .pressing_button
        ldy #$02
        lda !rat_state_timer
        cmp #$20
        bcs +
            iny
        +
        tya
        sta !frame,x
        lda !rat_state_timer
        dec
        bne +
            sep #$20
            inc !rat_state_extra
            rep #$20
            lda #$003F
        +
        sta !rat_state_timer
        sep #$20
        rts
    .jetpack_frames
        db !rat_jetpack_3_frame
        db !rat_jetpack_2_frame
        db !rat_jetpack_1_frame
        db !rat_jetpack_0_frame

    .igniting_jetpack
        lda !rat_state_timer
        lsr #4
        phx
        tax
        lda .jetpack_frames,x
        plx
        sta !frame,x
        lda !rat_state_timer
        dec
        bne +
            inc !rat_state_extra
        +
        sta !rat_state_timer
        rts

; Height to start heading left
!rat_to_robot_height_1 = #$00E8
; Max height, when to start going down
!rat_to_robot_height_2 = #$0100
; Height to lower to to enter the robot
!rat_to_robot_height_3 = #$00E8
; X pos to go to before starting to go down
!rat_to_robot_left_1 = #$0180
; X pos to end at
!rat_to_robot_left_2 = #$0180

!jetpack_y_speed = #$C0
!rat_to_robot_x_speed = #$DA

rat_to_robot:
    ldx $15E9
    stz !rat_clipping_value
    jsr animate_jetpack_rat
    jsr bob_rat
    lda !rat_state_extra
    bne +
        jmp .up
    +
    cmp #$01
    bne +
        jmp .up_left
    +
    ;cmp #$02
    ;bne +
    ;    jmp .down_left
    ;+
    inc !rat_state
    inc !robot_state
    rts
    .up
        lda $64
        sta !rat_priority
        lda !jetpack_y_speed
        sta !sprite_y_speed,x
        stz !sprite_x_speed,x
        jsl !update_sprite_pos_with_gravity
        lda !sprite_y_pos_hi,x
        xba
        lda !sprite_y_pos_lo,x
        rep #$20
        cmp !rat_to_robot_height_1
        bcs +
            sep #$20
            inc !rat_state_extra
            lda !rat_to_robot_x_speed
            sta !sprite_x_speed,x
        +
        sep #$20
        rts
    .up_left
        stz !rat_priority
        stz $0F ; Using this address to track which limits we have reached
        jsl !update_sprite_pos_with_gravity
        lda !sprite_x_pos_hi,x
        xba
        lda !sprite_x_pos_lo,x
        rep #$20
        cmp !rat_to_robot_left_2
        bcs +
            lda !rat_to_robot_left_2
            sep #$20
            sta !sprite_x_pos_lo,x
            xba
            sta !sprite_x_pos_hi,x
            stz !sprite_x_speed,x
        +
        sep #$20
        lda !sprite_y_pos_hi,x
        xba
        lda !sprite_y_pos_lo,x
        rep #$20
        cmp !rat_to_robot_height_3
        bcc +
            lda !rat_to_robot_height_3
            sep #$20
            sta !sprite_y_pos_lo,x
            xba
            sta !sprite_y_pos_hi,x
            stz !sprite_y_speed,x
        +
        sep #$20
        lda !sprite_y_pos_hi,x
        xba
        lda !sprite_y_pos_lo,x
        rep #$20
        cmp !rat_to_robot_height_3
        bne +
            inc $0F
            sep #$20
            lda !sprite_x_pos_hi,x
            xba
            lda !sprite_x_pos_lo,x
            rep #$20
            cmp !rat_to_robot_left_2
            bne +
                inc $0F
        +
        sep #$20
        lda $0F
        cmp #$02
        bne +
            inc !rat_state_extra
        +
        rts
    ;.down_left

rat_in_robot:
    stz !rat_priority
    stz !rat_bob_off
    lda #$07
    sec
    sbc !health
    lsr
    phx
    tax
    lda $13
    clc
    ror #7
    -
    rol
    dex
    bpl -
    .done_with_asl
    plx
    and #$03
    cmp #$03
    bne +
        lda #$01
    +
    clc
    adc !rat_controlling_1_frame
    sta !frame,x
    rts

jetpack_frames:
    db !rat_jetpack_4_frame
    db !rat_jetpack_5_frame
    db !rat_jetpack_4_frame
    db !rat_jetpack_3_frame

!rat_leaving_robot_up_y = #$0090
!rat_leaving_robot_down_y = #$00C0
!rat_leaving_robot_up_y_speed = #$E0
!rat_leaving_robot_down_y_speed = #$20
rat_leaving_robot:
    ldx $15E9
    stz !rat_clipping_value
    jsr animate_jetpack_rat
    jsr bob_rat
    lda !rat_state_extra
    bne +
        jmp .up
    +
    cmp #$01
    bne +
        jmp .down
    +
    inc !rat_state
    rts
    .up
        stz !rat_priority
        lda !rat_leaving_robot_up_y_speed
        sta !sprite_y_speed,x
        jsl !update_sprite_y_pos_no_gravity
        lda !sprite_y_pos_hi,x
        xba
        lda !sprite_y_pos_lo,x
        rep #$20
        cmp !rat_leaving_robot_up_y
        bcs +
            inc !rat_state_extra
        +
        sep #$20
        rts
    .down
        lda $64
        sta !rat_priority
        lda !rat_leaving_robot_down_y_speed
        sta !sprite_y_speed,x
        jsl !update_sprite_y_pos_no_gravity
        lda !sprite_y_pos_hi,x
        xba
        lda !sprite_y_pos_lo,x
        rep #$20
        cmp !rat_leaving_robot_down_y
        bcc +
            inc !rat_state_extra
            ;lda !rat_leaving_robot_down_y
            sep #$20
            jsl !get_random_number
            lda $148D
            and #$3F
            clc
            adc #$40
            sta !rat_state_timer
            stz !rat_state_timer+1
        +
        sep #$20
        rts

!rat_pacing_y_pos = #$00C0
rat_pacing:
    ldx $15E9
    lda !rat_clipping_standard
    sta !rat_clipping_value
    rep #$20
    lda #.interaction_callback
    sta !interaction_callback
    sep #$20
    lda $64
    sta !rat_priority
    jsr animate_jetpack_rat
    jsr bob_rat
    lda !sprite_horz_direction,x
    phx
    asl
    sta $0F
    lsr
    tax
    lda .x_speed,x
    plx
    sta !sprite_x_speed,x
    jsl !update_sprite_x_pos_no_gravity

    stz !sprite_y_speed,x
    lda !sprite_y_pos_hi,x
    xba
    lda !sprite_y_pos_lo,x
    rep #$20
    cmp !rat_pacing_y_pos
    bcc +
        sep #$20
        lda #$E0
        sta !sprite_y_speed,x
        bra ++
    +
        dec !rat_state_timer
        bne +
            sep #$20
            jsr calc_rat_jetpack_routines
        +
    ++
    sep #$20
    jsl !update_sprite_y_pos_no_gravity
    phx
    ldx $0F
    rep #$20
    lda .x_off,x
    sta $00
    sep #$20
    plx
    lda !sprite_x_pos_hi,x
    xba
    lda !sprite_x_pos_lo,x
    rep #$20
    cmp $00
    sep #$20
    php
    lda !sprite_horz_direction,x
    bne .pacing_right
        .pacing_left
            plp
            bcs +
                eor #$01
                sta !sprite_horz_direction,x
            +
            jmp .pacing_return
        .pacing_right
            plp
            bcc +
                eor #$01
                sta !sprite_horz_direction,x
            +
            jmp .pacing_return
    .pacing_return
    rts

    .interaction_callback
        ;lda !rat_hurt_timer
        ;beq +
        ;    rts
        ;+
        ;JSL !SubVertPos ; \
        sta $7FA000
        ;LDA $0E         ;  | if mario isn't above sprite, and there's vertical contact...
        ;CMP #$E8        ;  |     ... sprite wins
        ;BPL .SpriteWins     ; /
        lda $0B
        xba
        lda $05
        rep #$20
        sta $00
        lda $96
        sec
        sbc $00
        cmp #$FFEC
        sep #$20
        bpl .SpriteWins


        LDA $7D         ; \ if mario speed is upward, return
        BMI .NoContact      ; /

        JSL $81AA33 ; set mario speed

        JSL $81AB99             ; display contact graphic
        LDA #$02
        STA $1DF9
        lda !rat_hit_falling_state
        sta !rat_state
        lda #$40
        sta !sprite_y_speed,x
        JMP .NoContact 
        .SpriteWins
            ;LDA $154C,x ; \ if disable interaction set...
            ;BNE .NoContact
            jsl !hurt_mario
        .NoContact
        rts

    .x_speed
        db $E0,$20
    .x_off
        dw $0120, $01E0

!rat_spinning_windup_time = #$0040
!rat_spinning_winddown_time = #$0040
!rat_spinning_screen_mid_y = #$0100
!rat_spinning_screen_mid_x = #$0150
!rat_spinning_setup_x_speed = #$20
!rat_spinning_setup_y_speed = #$20
rat_spinning:
    ldx $15E9
    lda !rat_clipping_standard
    sta !rat_clipping_value
    rep #$20
    lda #rat_pacing_interaction_callback
    sta !interaction_callback
    sep #$20
    lda $64
    sta !rat_priority
    jsr animate_jetpack_rat
    jsr bob_rat
    lda !rat_state_extra
    bne +
        jmp .init
    +
    cmp #$01
    bne +
        jmp .goto_start
    +
    cmp #$02
    bne +
        jmp .windup
    +
    cmp #$03
    bne +
        jmp .go
    +
    cmp #$04
    bne +
        jmp .winddown
    +
    lda !rat_pacing_state
    sta !rat_state
    stz !rat_state_extra
    jsl !get_random_number
    lda $148D
    and #$3F
    clc
    adc #$40
    sta !rat_state_timer
    stz !rat_state_timer+1
    rts
    .init
        stz !rat_state_extra+1
        rep #$20
        lda $D3
        cmp !rat_spinning_screen_mid_y
        sep #$20
        rol !rat_state_extra+1
        rep #$20
        lda $D1
        cmp !rat_spinning_screen_mid_x
        sep #$20
        rol !rat_state_extra+1
        inc !rat_state_extra
        stz !sprite_y_speed,x
        stz !sprite_x_speed,x
    .goto_start
        jsl !update_sprite_y_pos_no_gravity
        jsl !update_sprite_x_pos_no_gravity
        lda !rat_state_extra+1
        asl
        phx
        tax
        rep #$20
        lda .start_x,x
        sta $00
        lda .start_y,x
        sta $02
        sep #$20
        plx
        lda !sprite_x_pos_hi,x
        xba
        lda !sprite_x_pos_lo,x
        rep #$20
        sec
        sbc $00
        sep #$20
        bcs .goto_start_x_gt
        .goto_start_x_lt
            cmp #$FC
            bcc +
                stz !sprite_y_speed,x
                jmp .goto_start_y_end
            +
            lda !rat_spinning_setup_x_speed
            sta !sprite_x_speed,x
            lda #$01
            sta !sprite_horz_direction,x
            jmp .goto_start_x_end
        .goto_start_x_gt
            cmp #$04
            bcs +
                stz !sprite_x_speed,x
                jmp .goto_start_x_end
            +
            lda !rat_spinning_setup_x_speed
            eor #$FF
            inc
            sta !sprite_x_speed,x
            stz !sprite_horz_direction,x
        .goto_start_x_end

        lda !sprite_y_pos_hi,x
        xba
        lda !sprite_y_pos_lo,x
        rep #$20
        sec
        sbc $02
        sep #$20
        bcs .goto_start_y_gt
        .goto_start_y_lt
            cmp #$FC
            bcc +
                stz !sprite_y_speed,x
                jmp .goto_start_y_end
            +
            lda !rat_spinning_setup_y_speed
            sta !sprite_y_speed,x
            jmp .goto_start_y_end
        .goto_start_y_gt
            cmp #$04
            bcs +
                stz !sprite_y_speed,x
                jmp .goto_start_y_end
            +
            lda !rat_spinning_setup_y_speed
            eor #$FF
            inc
            sta !sprite_y_speed,x
        .goto_start_y_end
        lda !sprite_y_speed,x
        ora !sprite_x_speed,x
        bne +
            inc !rat_state_extra
            rep #$20
            lda !rat_spinning_windup_time
            sta !rat_state_timer
            sep #$20
        +
        rts
    .windup
        lda $14
        lsr #2
        and #$01
        sta !sprite_horz_direction,x
        rep #$20
        dec !rat_state_timer
        sep #$20
        bne +
            inc !rat_state_extra
        +
        rts
    .go
        lda $14
        lsr #2
        and #$01
        sta !sprite_horz_direction,x
        ; We're going to need to know which direction we are going later
        lda !rat_state_extra+1
        phx
        tax
        lda .attacking_y_speed,x
        sta $02
        lda .attacking_x_speed,x
        sta $03
        lda .attacking_x_accelaration,x
        sta $04
        plx
        lda $02
        sta !sprite_y_speed,x
        lda !sprite_x_speed,x
        cmp #$00
        bne +
            lda $03
            bpl ++
                dec !sprite_x_speed,x
            ++
            lda !sprite_x_speed,x
        +
        cmp $03
        php
        pha
        lda $03
        bpl .go_x_speed_positive
        .go_x_speed_negative
            pla
            plp
            bcs +
                lda $03
                sta !sprite_x_speed,x
                bra ++
            +
                beq ++
                clc
                adc $04
                sta !sprite_x_speed,x
            ++
            jmp .go_x_speed_end
        .go_x_speed_positive
            pla
            plp
            bcc +
                lda $03
                sta !sprite_x_speed,x
                bra ++
            +
                clc
                adc $04
                sta !sprite_x_speed,x
            ++
        .go_x_speed_end
        lda !rat_state_extra+1
        asl
        phx
        tax
        rep #$20
        lda .end_x,x
        sta $00
        lda .end_y,x
        sta $02
        sep #$20
        plx
        lda !sprite_y_pos_hi,x
        xba
        lda !sprite_y_pos_lo,x
        rep #$20
        sta $05
        cmp $02
        php
        sep #$20
        lda !sprite_y_speed,x
        bpl .go_y_pos_down
        .go_y_pos_up
            plp
            beq +
            bcs ++
                +
                lda $02
                sep #$20
                sta !sprite_y_pos_lo,x
                xba
                sta !sprite_y_pos_hi,x
                stz !sprite_y_speed,x
            ++
            jmp .go_y_pos_end
        .go_y_pos_down
            plp
            bcc +
                lda $02
                sep #$20
                sta !sprite_y_pos_lo,x
                xba
                sta !sprite_y_pos_hi,x
                stz !sprite_y_speed,x
            +
        .go_y_pos_end
        sep #$20

        lda !sprite_x_pos_hi,x
        xba
        lda !sprite_x_pos_lo,x
        rep #$20
        sta $05
        cmp $00
        php
        sep #$20
        lda $04
        bpl .go_x_pos_right
        .go_x_pos_left
            plp
            beq +
            bcs ++
                +
                lda $00
                sep #$20
                sta !sprite_x_pos_lo,x
                xba
                sta !sprite_x_pos_hi,x
                stz !sprite_x_speed,x
            ++
            jmp .go_x_pos_end
        .go_x_pos_right
            plp
            bcc +
                lda $00
                sep #$20
                sta !sprite_x_pos_lo,x
                xba
                sta !sprite_x_pos_hi,x
                stz !sprite_x_speed,x
            +
        .go_x_pos_end
        sep #$20

        jsl !update_sprite_y_pos_no_gravity
        jsl !update_sprite_x_pos_no_gravity
        lda !sprite_y_speed,x
        ora !sprite_x_speed,x
        bne +
            inc !rat_state_extra
            rep #$20
            lda !rat_spinning_winddown_time
            sta !rat_state_timer
            sep #$20
        +
        rts
    .winddown
        lda $14
        lsr #2
        and #$01
        sta !sprite_horz_direction,x
        rep #$20
        dec !rat_state_timer
        sep #$20
        bne +
            inc !rat_state_extra
        +
        rts

    .interaction_callback
        ;lda !rat_hurt_timer
        ;beq +
        ;    rts
        ;+
        JSL !SubVertPos ; \
        LDA $0E         ;  | if mario isn't above sprite, and there's vertical contact...
        CMP #$E8        ;  |     ... sprite wins
        BPL .SpriteWins     ; /
        LDA $7D         ; \ if mario speed is upward, return
        BMI .NoContact      ; /

        LDA $15     ; Save controller state
        PHA
        ORA #$C0    ; Set holding X/Y and A/B
        STA $15
        JSL $81AA33 ; set mario speed
        PLA
        STA $15

        JSL $81AB99             ; display contact graphic
        LDA #$02
        STA $1DF9
        lda !rat_hit_falling_state
        sta !rat_state
        stz !rat_state_extra+1
        lda #$40
        sta !sprite_y_speed,x
        JMP .NoContact 
        .SpriteWins
            ;LDA $154C,x ; \ if disable interaction set...
            ;BNE .NoContact
            jsl !hurt_mario
        .NoContact
        rts
    ; 0 Mario top left, 1 Mario top right
    ; 2 Mario bot right, 3 Mario bot right
    ; bit 1 set means bot, cleared means top
    ; bit 0 set means right, cleared means left
    .start_x
        dw $01D0,$0118,$01D0,$0118
    .start_y
        dw $0118,$0118,$00A0,$00A0
    .end_x
        dw $0128,$01B8,$0128,$01D8
    .end_y
        dw $00C0,$00C0,$0110,$0110
    .attacking_y_speed
        db $C0,$C0,$40,$40
    .attacking_x_speed
        db $C0,$40,$C0,$40
    .attacking_x_accelaration
        db $FC,$04,$FC,$04

rat_tracking:
    ldx $15E9
    lda !rat_clipping_standard
    sta !rat_clipping_value
    rep #$20
    lda #rat_pacing_interaction_callback
    sta !interaction_callback
    sep #$20
    lda $64
    sta !rat_priority
    jsr animate_jetpack_rat
    jsr bob_rat
    lda !rat_state_extra
    bne +
        jmp .init
    +
    cmp #$01
    bne +
        jmp .go_offscreen
    +
    cmp #$02
    bne +
        jmp .goto_start
    +
    cmp #$03
    bne +
        jmp .track
    +
    cmp #$04
    bne +
        jmp .rush
    +
    cmp #$05
    bne +
        jmp .return
    +
    lda !rat_pacing_state
    sta !rat_state
    stz !rat_state_extra
    jsl !get_random_number
    lda $148D
    and #$3F
    clc
    adc #$40
    sta !rat_state_timer
    stz !rat_state_timer+1
    rts
    .init
        stz !rat_state_extra+1
        rep #$20
        lda $D1
        cmp !rat_spinning_screen_mid_x
        sep #$20
        rol !rat_state_extra+1
        inc !rat_state_extra
    .go_offscreen
        lda !rat_state_extra+1
        phx
        tax
        lda .go_offscreen_x_speed,x
        sta $00
        txa
        asl
        tax
        rep #$20
        lda .go_offscreen_x_pos,x
        sta $01
        sep #$20
        plx

        .go_offscreen_calc_x
        lda $00
        sta !sprite_x_speed,x
        stz !sprite_y_speed,x
        jsl !update_sprite_x_pos_no_gravity

        lda !sprite_x_pos_hi,x
        xba
        lda !sprite_x_pos_lo,x
        rep #$20
        cmp $01
        php
        sep #$20
        lda $00
        bpl .go_offscreen_x_right
        .go_offscreen_x_left
            plp
            bcs .go_offscreen_x_end
            lda $01
            sep #$20
            sta !sprite_x_pos_lo,x
            xba
            sta !sprite_x_pos_hi,x
            stz !sprite_x_speed,x
            jmp .go_offscreen_x_end
        .go_offscreen_x_right
            plp
            bcc .go_offscreen_x_end
            lda $01
            sep #$20
            sta !sprite_x_pos_lo,x
            xba
            sta !sprite_x_pos_hi,x
            stz !sprite_x_speed,x
            ;jmp .go_offscreen_x_end
        .go_offscreen_x_end
        sep #$20
        lda !sprite_x_speed,x
        beq +
            and #$80
            rol #2
            and #$01
            eor #$01
            sta !sprite_horz_direction,x
        +
        lda !sprite_x_speed,x
        bne +
            inc !rat_state_extra
        +
        rts
    .goto_start
        rep #$20
        lda $96
        sep #$20
        sta !sprite_y_pos_lo,x
        xba
        sta !sprite_y_pos_hi,x

        lda !rat_state_extra+1
        phx
        tax
        lda .goto_start_x_speed,x
        sta $00
        txa
        asl
        tax
        rep #$20
        lda .goto_start_x_pos,x
        sta $01
        sep #$20
        plx

        jsr .go_offscreen_calc_x
        lda !sprite_x_speed,x
        bne +
            jsl !get_random_number
            and #$3F
            clc
            adc #$40
            sta !rat_state_timer
            stz !rat_state_timer+1
        +
        rts
    .track
        rep #$20
        lda $96
        sep #$20
        sta !sprite_y_pos_lo,x
        xba
        sta !sprite_y_pos_hi,x

        dec !rat_state_timer
        bne +
            inc !rat_state_extra
        +
        rts
    .rush
        lda !rat_state_extra+1
        phx
        tax
        lda .rush_x_speed,x
        sta $00
        txa
        asl
        tax
        rep #$20
        lda .rush_end_x,x
        sta $01
        sep #$20
        plx

        jsr .go_offscreen_calc_x
        rts
    .return
        rep #$20
        lda !rat_pacing_y_pos
        sep #$20
        sta !sprite_y_pos_lo,x
        xba
        sta !sprite_y_pos_hi,x
        lda !rat_state_extra+1
        phx
        tax
        lda .return_x_speed,x
        sta $00
        txa
        asl
        tax
        rep #$20
        lda .return_end_x,x
        sta $01
        sep #$20
        plx

        jsr .go_offscreen_calc_x
        rts

    .interaction_callback
        ;lda !rat_hurt_timer
        ;beq +
        ;    rts
        ;+
        JSL !SubVertPos ; \
        LDA $0E         ;  | if mario isn't above sprite, and there's vertical contact...
        CMP #$E8        ;  |     ... sprite wins
        BPL .SpriteWins     ; /
        LDA $7D         ; \ if mario speed is upward, return
        BMI .NoContact      ; /

        LDA $15     ; Save controller state
        PHA
        ORA #$C0    ; Set holding X/Y and A/B
        STA $15
        JSL $81AA33 ; set mario speed
        PLA
        STA $15

        JSL $81AB99             ; display contact graphic
        LDA #$02
        STA $1DF9
        lda !rat_hit_falling_state
        sta !rat_state
        stz !rat_state_extra+1
        lda #$40
        sta !sprite_y_speed,x
        JMP .NoContact 
        .SpriteWins
            ;LDA $154C,x ; \ if disable interaction set...
            ;BNE .NoContact
            jsl !hurt_mario
        .NoContact
        rts
    .go_offscreen_x_speed
        db $30,$D0
    .go_offscreen_x_pos
        dw $0200,$00E0
    .goto_start_x_speed
        db $E0,$20
    .goto_start_x_pos
        dw $01E0,$0100
    .rush_x_speed
        db $A0, $60
    .rush_end_x
        dw $00C0,$0220
    .return_x_speed
        db $20,$E0
    .return_end_x
        dw $01E0,$0120

!rat_bomb_throw_throw_timer = #$0010
!rat_bomb_throw_wait_timer = #$0030
rat_bomb_throw:
    jsr rat_pacing
    lda !rat_clipping_standard
    sta !rat_clipping_value
    rep #$20
    lda #rat_pacing_interaction_callback
    sta !interaction_callback
    sep #$20
    lda !rat_state_extra
    bne +
        jmp .init
    +
    cmp #$01
    bne +
        jmp .wait_to_throw
    +
    cmp #$02
    bne +
        jmp .throw
    +
    lda !rat_pacing_state
    sta !rat_state
    stz !rat_state_extra
    jsl !get_random_number
    lda $148D
    and #$3F
    clc
    adc #$40
    sta !rat_state_timer
    stz !rat_state_timer+1
    rts
    .init
        ;jsl !get_random_number
        ;lda $148D
        ;and #$03
        ;inc
        inc !rat_state_extra
        lda #$04
        sta !rat_state_extra+1
        ; Current slot being used
        stz !rat_state_extra+2
        ; These are used to track which slots are being used
        stz !rat_state_extra+3
        stz !rat_state_extra+4
        stz !rat_state_extra+5
        stz !rat_state_extra+6
        rep #$20
        lda !rat_bomb_throw_wait_timer
        sta !rat_state_timer
        sep #$20
        rts
    .wait_to_throw
        rep #$20
        lda !rat_state_timer
        bne +
            sep #$20
            phx
            inc !rat_state_extra
            -
            jsl !get_random_number
            lda $148D
            and #$03
            tax
            lda !rat_state_extra+3,x
            stx !rat_state_extra+2
            cmp #$00
            bne -
            inc
            sta !rat_state_extra+3,x
            plx
            rep #$20
            lda !rat_bomb_throw_throw_timer
            sta !rat_state_timer
        +
        sep #$20
        rts
    .throw
        lda !rat_state_timer
        ; Later add some throwing animation here
        bne +++
            lda !bomb_sprite_number
            sta !sprite_spawn_sprite_number
            lda !sprite_y_pos_lo,x
            clc
            adc #$10
            sta !sprite_spawn_y_lo
            lda !sprite_y_pos_hi,x
            adc #$00
            sta !sprite_spawn_y_hi
            lda !sprite_x_pos_hi,x
            xba
            lda !sprite_x_pos_lo,x
            phx
            pha
            lda !sprite_horz_direction,x
            asl
            tax
            pla
            rep #$20
            clc
            adc .spawn_x_off,x
            sep #$20
            plx
            sta !sprite_spawn_x_lo
            xba
            sta !sprite_spawn_x_hi
            jsr spawn_custom_sprite
            phx
            lda !rat_state_extra+2
            ldx !sprite_spawn_return_slot
            sta !bomb_position,x
            plx
            dec !rat_state_extra+1
            bne +
                inc !rat_state_extra
                rts
            +
            dec !rat_state_extra
            rep #$20
            lda !rat_bomb_throw_wait_timer
            sta !rat_state_timer
            sep #$20
        +++
        rts
    .interaction_callback
        ;lda !rat_hurt_timer
        ;beq +
        ;    rts
        ;+
        JSL !SubVertPos ; \
        LDA $0E         ;  | if mario isn't above sprite, and there's vertical contact...
        CMP #$E8        ;  |     ... sprite wins
        BPL .SpriteWins     ; /
        LDA $7D         ; \ if mario speed is upward, return
        BMI .NoContact      ; /

        JSL $81AA33 ; set mario speed

        JSL $81AB99             ; display contact graphic
        LDA #$02
        STA $1DF9
        lda !rat_hit_falling_state
        sta !rat_state
        stz !rat_state_extra+1
        lda #$40
        sta !sprite_y_speed,x
        JMP .NoContact 
        .SpriteWins
            ;LDA $154C,x ; \ if disable interaction set...
            ;BNE .NoContact
            jsl !hurt_mario
        .NoContact
        rts
    .spawn_x_off
        dw $FFF0,$0010

!rat_hit_falling_y_accel = #$02
!rat_hit_falling_hurt_y_pos = #$0150
rat_hit_falling:
    ldx $15E9
    rep #$20
    lda #rat_pacing_interaction_callback
    sta !rat_interaction_callback
    sep #$20
    lda #$40
    sta !rat_hurt_timer
    stz !rat_clipping_value
    lda $64
    sta !rat_priority
    jsr animate_jetpack_rat
    lda !sprite_horz_direction,x
    phx
    asl
    sta $0F
    lsr
    tax
    lda .x_speed,x
    plx
    sta !sprite_x_speed,x
    jsl !update_sprite_x_pos_no_gravity
    phx
    ldx $0F
    rep #$20
    lda .x_off,x
    sta $00
    sep #$20
    plx
    lda !sprite_x_pos_hi,x
    xba
    lda !sprite_x_pos_lo,x
    rep #$20
    cmp $00
    sep #$20
    php
    lda !sprite_horz_direction,x
    bne .pacing_right
        .pacing_left
            plp
            bcs +
                eor #$01
                sta !sprite_horz_direction,x
            +
            jmp .pacing_return
        .pacing_right
            plp
            bcc +
                eor #$01
                sta !sprite_horz_direction,x
            +
            jmp .pacing_return
    .pacing_return
    jsl !update_sprite_y_pos_no_gravity
    lda !sprite_y_pos_hi,x
    xba
    lda !sprite_y_pos_lo,x
    rep #$20
    cmp !rat_hit_falling_hurt_y_pos
    sep #$20
    bcc +
        lda !rat_state_extra+1
        bne +
        lda #$28
        sta $1DFC
        dec !health
        inc !rat_state_extra+1
        lda !health
        bne ++
            lda !rat_dying_state
            sta !rat_state
            stz !rat_state_extra
        ++
    +
    lda !sprite_y_speed,x
    sec
    sbc !rat_hit_falling_y_accel
    sta !sprite_y_speed,x
    bpl +
        lda !rat_pacing_state
        sta !rat_state
        stz !rat_state_extra
        jsl !get_random_number
        lda $148D
        and #$3F
        clc
        adc #$40
        sta !rat_state_timer
        stz !rat_state_timer+1
    +
    rts
    .x_speed
        db $E0,$20
    .x_off
        dw $0120, $01E0

!dying_y_max = #$0160
!floating_up_y_min = #$0150
!dying_x_pos = #$0180
rat_dying:
    stz !rat_hurt_timer
    ldx $15E9
    stz !rat_clipping_value
    lda $64
    sta !rat_priority
    lda !rat_talking_frame
    sta !frame,x
    lda !rat_state_extra
    bne +
        jmp .falling
    +
    cmp #$01
    bne +
        jmp .floating_up
    +
    cmp #$02
    bne +
        jmp .bobbing
    +
    cmp #$03
    bne +
        jmp .sinking
    +
    cmp #$05
    beq +
    ; Win game
        lda #$03
        sta $1DFB
        lda #$FF
        sta $1493
        dec $13C6
        inc !rat_state_extra
    +
    rts
    .falling
        lda #$20
        sta !sprite_y_speed,x
        jsl !update_sprite_y_pos_no_gravity
        lda !sprite_y_pos_hi,x
        xba
        lda !sprite_y_pos_lo,x
        rep #$20
        cmp !dying_y_max
        sep #$20
        bcc +
            inc !rat_state_extra
        +
        rts
    .floating_up
        jsr bob_rat_slow
        rep #$20
        lda !dying_x_pos
        sep #$20
        sta !sprite_x_pos_lo,x
        xba
        sta !sprite_x_pos_hi,x
        lda #$F8
        sta !sprite_y_speed,x
        jsl !update_sprite_y_pos_no_gravity
        lda !sprite_y_pos_hi,x
        xba
        lda !sprite_y_pos_lo,x
        rep #$20
        cmp !floating_up_y_min
        sep #$20
        bcs +
            inc !rat_state_extra
            lda #$40
            sta !rat_state_timer
            stz !rat_state_timer+1
        +
        rts
    .bobbing
        jsr bob_rat_slow
        dec !rat_state_timer
        bpl +
            inc !rat_state_extra
        +
        rts
    .sinking
        jsr bob_rat_slow
        lda #$08
        sta !sprite_y_speed,x
        jsl !update_sprite_y_pos_no_gravity
        lda !sprite_y_pos_hi,x
        xba
        lda !sprite_y_pos_lo,x
        rep #$20
        cmp !dying_y_max
        sep #$20
        bcc +
            inc !rat_state_extra
        +
        rts



animate_jetpack_rat:
    lda $14
    lsr #4
    and #$03
    phx
    tax
    lda jetpack_frames,x
    plx
    sta !frame,x
    rts
bob_rat:
    lda $14
    lsr #2
    and #$0F
    cmp #$08
    bcc +
        sec
        sbc #$08
        sta $00
        lda #$08
        sec
        sbc $00
    +
    sec
    sbc #$04
    sta !rat_bob_off
    rts
bob_rat_slow:
    lda $14
    lsr #2
    and #$0F
    cmp #$08
    bcc +
        sec
        sbc #$08
        sta $00
        lda #$08
        sec
        sbc $00
    +
    sec
    sbc #$04
    sta !rat_bob_off
    rts

robot_attacks:
    db !smash_state
    db !slap_state
    db !slap_down_state


; Decide which hand does what at what time. Hands act independantaly.
; The more times you hit it, the faster it attacks, eventually the two hands will begin attacking
; at the same time.
calc_routines:
    lda !num_robot_attacks
    sta !num_attacks
    lda !left_hand_delay_timer
    beq +
        dec !left_hand_delay_timer
    +
    lda !right_hand_delay_timer
    beq +
        dec !right_hand_delay_timer
    +
    lda !health
    cmp #$04
    bcs .one_hand
    jmp .both_hands
    .one_hand
        lda !left_hand_state
        beq +
            jmp .one_hand_return
        +
        lda !right_hand_state
        beq +
            jmp .one_hand_return
        +
        jsl !get_random_number
        lda $148D
        and #$01
        bne .one_hand_right
        .one_hand_left
            lda !left_hand_delay_timer
            bne .one_hand_right
            phx
            jsr get_weighted_attack
            lda robot_attacks,x
            plx
            sta !left_hand_state
            jsr copy_left_hand
            jsr .do_init
            jsr restore_left_hand
            bra .one_hand_return
        .one_hand_right
            lda !right_hand_delay_timer
            beq +
                lda !left_hand_delay_timer
                beq .one_hand_left
                jmp .one_hand_return
            +
            phx
            jsr get_weighted_attack
            lda robot_attacks,x
            plx
            sta !right_hand_state
            jsr copy_right_hand
            jsr .do_init
            jsr restore_right_hand
        .one_hand_return
        rts
    .both_hands
        lda !left_hand_state
        bne .both_hands_right
        lda !right_hand_state
        bne .both_hands_left
        jsl !get_random_number
        lda $148D
        and #$01
        bne .both_hands_right
        .both_hands_left
            lda !left_hand_state
            bne .both_hands_return
            lda !left_hand_delay_timer
            bne .both_hands_return
            phx
            jsr get_weighted_attack
            lda robot_attacks,x
            plx
            sta !left_hand_state
            jsr copy_left_hand
            jsr .do_init
            jsr restore_left_hand
            jmp .both_hands_return
        .both_hands_right
            lda !right_hand_state
            bne .both_hands_return
            lda !right_hand_delay_timer
            bne .both_hands_return
            phx
            jsr get_weighted_attack
            lda robot_attacks,x
            plx
            sta !right_hand_state
            jsr copy_right_hand
            jsr .do_init
            jsr restore_right_hand
            jmp .both_hands_return
        .both_hands_return
        rts


    .init_routines
        dw .smash_routine_init
        dw .slap_routine_init
        dw .slap_down_routine_init
    ; Handle the init for the new state we make
    .do_init
        phx
        lda $02
        asl
        tax
        rep #$20
        lda .init_routines,x
        sta $00
        sep #$20
        plx
        pea .init_return-1
        jmp ($0000)
        .init_return
        rts
    .smash_routine_init
        stz !state_timer
        rep #$20
        stz !state_extra
        stz !state_extra+2
        stz !state_extra+4
        sep #$20
        rts
    .slap_routine_init
        stz !state_timer
        rep #$20
        stz !state_extra
        stz !state_extra+2
        stz !state_extra+4
        sep #$20
        rts
    .slap_down_routine_init
        stz !state_timer
        rep #$20
        stz !state_extra
        stz !state_extra+2
        stz !state_extra+4
        sep #$20
        rts

rat_jetpack_routines:
    db !rat_spinning_state
    db !rat_tracking_state
    db !rat_bomb_throwing_state

calc_rat_jetpack_routines:
    lda !num_rat_attacks
    sta !num_attacks
    lda !rat_state
    cmp !rat_pacing_state
    bne .return
    ;jsl !get_random_number
    ;lda #$00
    ;sta $4205
    ;lda $148D
    ;sta $4204
    ;lda.b !num_rat_attacks
    ;sta $4206
    ;nop #12
    phx
    ;ldx $4216
    jsr get_weighted_attack
    lda rat_jetpack_routines,x
    plx
    ;lda !rat_bomb_throwing_state
    sta !rat_state
    stz !rat_state_extra
    .return
    rts
do_routine:
    phx
    lda !state
    asl
    tax
    rep #$20
    lda routines,x
    ldx #$00
    sta $00
    sep #$20
    jsr ($0000,x)
    plx
    rep #$20
    lda !state_timer
    beq +
        dec !state_timer
    +
    sep #$20
    rts

get_weighted_attack:
    jsl !get_random_number
    lda #$00
    sta $4205
    lda $148D
    sta $4204
    lda.b !num_attacks
    sta $00
    phx
    ldx !num_attacks
    dex
    -
    lda !attack_weight_table,x
    clc
    adc $00
    sta $00
    dex
    bpl -
    sta $4206
    nop #12
    ldx $4216
    stx $02
    lda #$00
    ldx #$00
    -
    cmp $02
    beq +
    bcs .not_found_1
    +
        clc
        adc !attack_weight_table,x
        cmp $02
        bcc .not_found_2
        jmp .attack_found
    .not_found_1
        clc
        adc !attack_weight_table,x
    .not_found_2
        inc
        inx
        jmp -
    .attack_found
    stx $02
    ;lda robot_attacks,x
    ldx #$00
    -
    cpx $02
    bne .inc_weight
    jmp +
    .inc_weight
        inc !attack_weight_table,x
        jmp ++
    +
        stz !attack_weight_table,x
    ++
    inx
    cpx !num_attacks
    bcc -
    plx
    ldx $02
    rts

routines:
    dw idle_routine
    dw smash_routine
    dw return_routine
    dw slap_routine
    dw slap_down_routine
    dw dying_smash_routine

idle_routine:
    ldx $15E9
    rep #$20
    stz !interaction_callback
    sep #$20
    ;rep #$20
    ;lda !state_timer
    ;sep #$20
    ;bne +
    ;    lda !smash_state
    ;    sta !state
    ;    rep #$20
    ;    stz !state_extra
    ;    stz !state_extra+2
    ;    stz !state_extra+4
    ;    sep #$20
    ;+
    rts

x_EOR:
db $00,$80

SUB_LOCKONX:
    jsl !SubHorizPos
    lda $0F
    lsr
    ora x_EOR,y
    sta !sprite_x_speed,x
    rts

!smash_speed = #$70
!ground_y_pos = #$0154
!max_y_speed = #$E0
smash_routine:
    ldx $15E9
    lda !hand_clenched_frame
    sta !frame,x
    lda !state_extra
    bne +
    jmp .init
    +
    cmp.b #$01
    bne +
    jmp .lifting
    +
    cmp.b #$02
    bne +
    jmp .following
    +
    cmp.b #$03
    bne +
    jmp .smashing
    +
    cmp.b #$04
    bne +
    jmp .waiting
    +
    jmp .end
    .init
        inc !state_extra
        rep #$20
        stz !interaction_callback
        sep #$20
        stz !sprite_y_speed,x
        jmp .return
    .lifting
        rep #$20
        lda #.smashing_interaction_callback
        sta !interaction_callback
        sep #$20
        jsr SUB_LOCKONX
        lda !sprite_y_speed,x
        bpl +
        cmp !max_y_speed
        bcc ++
        +
            dec !sprite_y_speed,x
        ++
        lda !sprite_y_pos_hi,x
        xba
        lda !sprite_y_pos_lo,x
        rep #$20
        cmp #$0100
        sep #$20
        bcs +
            stz !sprite_y_speed,x
            inc !state_extra
            rep #$20
            lda #$0040
            sta !state_timer
            sep #$20
        +
        jsl !update_sprite_y_pos_no_gravity
        jsl !update_sprite_x_pos_no_gravity
        jmp .return


    .following
        rep #$20
        lda #.smashing_interaction_callback
        sta !interaction_callback
        sep #$20
        jsr SUB_LOCKONX
        rep #$20
        lda !state_timer
        sep #$20
        bne +
            inc !state_extra
        +
        jsl !update_sprite_y_pos_no_gravity
        jsl !update_sprite_x_pos_no_gravity
        jmp .return
    .smashing
        rep #$20
        lda #.smashing_interaction_callback
        sta !interaction_callback
        sep #$20
        lda !smash_speed
        sta !sprite_y_speed,x
        stz !sprite_x_speed,x
        jsl !update_sprite_y_pos_no_gravity
        jsl !update_sprite_x_pos_no_gravity
        lda !sprite_y_pos_hi,x
        xba
        lda !sprite_y_pos_lo,x
        rep #$20
        cmp !ground_y_pos
        sep #$20
        bcc +
            rep #$20
            lda !ground_y_pos
            sep #$20
            sta !sprite_y_pos_lo,x
            xba
            sta !sprite_y_pos_hi,x
            inc !state_extra
            rep #$20
            lda #$0080
            sta !state_timer
            sep #$20
            lda #$10
            sta !shake_timer
            lda !smash_sound_effect
            sta !smash_sound_bank
        +
        jmp .return

    .waiting
        rep #$20
        lda #.waiting_interaction_callback
        sta !interaction_callback
        sep #$20
        stz !sprite_y_speed,x
        rep #$20
        lda !state_timer
        sep #$20
        bne +
            inc !state_extra
        +
        jmp .return
    .end
    lda !return_state
    sta !state
    lda !hand_relaxed_frame
    sta !frame,x

    .return
    rts

    .smashing_interaction_callback
        jsr ride_sprite
        jsr sprite_hit_below
        jsr sprite_act_solid
        rts
    .waiting_interaction_callback
        jmp .smashing_interaction_callback

!slap_left_x = #$0080
!slap_right_x = #$0220
!slap_pullback_y = #$0100
!slap_y = #$0150
!slap_pullback_speed = #$0005
!slap_speed = #$0007
slap_routine:
    ldx $15E9
    rep #$20
    stz !interaction_callback
    sep #$20
    lda !hand_relaxed_frame
    sta !frame,x
    lda !state_extra
    beq .pullback
    cmp #$01
    bne +
        jmp .init_sleep
    +
    cmp #$02
    bne +
        jmp .sleep
    +
    cmp #$03
    bne +
        jmp .slap
    +
    jmp .end
    .pullback
        lda !hand_relaxed_frame
        sta !frame,x
        lda !which_hand
        bne +
            rep #$20
            lda !slap_left_x
            bra ++
        +
            rep #$20
            lda !slap_right_x
        ++
        sta $00
        sep #$20
        lda !sprite_x_pos_hi,x
        xba
        lda !sprite_x_pos_lo,x
        rep #$20
        sta $02
        cmp $00
        bcs +
            lda $00
            sec
            sbc $02
            cmp !slap_pullback_speed+1
            bcs +++
                inc !state_extra
                lda $00
                bra ++
            +++
            lda $02
            clc
            adc !slap_pullback_speed
            bra ++
        +
            sec
            sbc $00
            cmp !slap_pullback_speed+1
            bcs +++
                inc !state_extra
                lda $00
                bra ++
            +++
            lda $02
            sec
            sbc !slap_pullback_speed
        ++
        sep #$20
        sta !sprite_x_pos_lo,x
        xba
        sta !sprite_x_pos_hi,x

        lda !sprite_y_pos_hi,x
        xba
        lda !sprite_y_pos_lo,x
        rep #$20
        sta $00
        sec
        sbc !slap_pullback_y
        bmi +
        cmp !slap_pullback_speed+1
        bcc +
        bra ++
        +
        lda !slap_pullback_y
        bra +++
        ++
            lda $00
            sec
            sbc !slap_pullback_speed
        +++
        sep #$20
        sta !sprite_y_pos_lo,x
        xba
        sta !sprite_y_pos_hi,x
        jmp .return
    .init_sleep
        lda #$10
        sta !state_timer
        inc !state_extra
        jmp .return
    .sleep
        lda !state_timer
        bne +
            inc !state_extra
        +
        jmp .return
    .slap
        rep #$20
        lda #.interaction_callback
        sta !interaction_callback
        sep #$20
        lda !hand_slap_frame
        sta !frame,x
        lda.b !slap_y
        sta !sprite_y_pos_lo,x
        lda.b !slap_y>>8
        sta !sprite_y_pos_hi,x
        lda !which_hand
        beq +
            rep #$20
            lda !slap_left_x
            bra ++
        +
            rep #$20
            lda !slap_right_x
        ++
        sta $00
        sep #$20
        lda !sprite_x_pos_hi,x
        xba
        lda !sprite_x_pos_lo,x
        rep #$20
        sta $02
        cmp $00
        bcs +
            lda $00
            sec
            sbc $02
            cmp !slap_speed+1
            bcs +++
                inc !state_extra
                lda $00
                bra ++
            +++
            lda $02
            clc
            adc !slap_speed
            bra ++
        +
            sec
            sbc $00
            cmp !slap_speed+1
            bcs +++
                inc !state_extra
                lda $00
                bra ++
            +++
            lda $02
            sec
            sbc !slap_speed
        ++
        sep #$20
        sta !sprite_x_pos_lo,x
        xba
        sta !sprite_x_pos_hi,x
        jmp .return
    .end
        lda !return_state
        sta !state
    .return
        rts

    .interaction_callback
        jsl !hurt_mario
        rts

!slap_down_pullback_y = #$0080
!slap_down_y = #$0158
!slap_down_pullback_speed = #$B0
!slap_down_speed = #$70
!ground_y_pos = #$0160
!max_y_speed = #$E0
slap_down_routine:
    ldx $15E9
    rep #$20
    stz !interaction_callback
    sep #$20
    lda !hand_relaxed_frame
    sta !frame,x
    lda !state_extra
    bne +
        jmp .pullback
    +
    cmp #$01
    bne +
        jmp .sleep_up
    +
    cmp #$02
    bne +
        jmp .slam
    +
    cmp #$03
    bne +
        jmp .sleep
    +
    jmp .end
    .pullback
        lda !hand_slap_down_frame
        sta !frame,x
        lda !sprite_y_pos_hi,x
        xba
        lda !sprite_y_pos_lo,x
        rep #$20
        cmp !slap_down_pullback_y
        sep #$20
        bcs +
            inc !state_extra
            stz !state_timer+1
            ; Random number between 40 and 80
            ;jsl !get_random_number
            ;lda $148D
            ;lsr #2
            ;clc
            ;adc #$40
            lda #$60
            sta !state_timer
            jmp .return
        +
        lda !slap_down_pullback_speed
        sta !sprite_y_speed,x
        jsl !update_sprite_y_pos_no_gravity
        jmp .return
    .sleep_up
        lda !state_timer
        bne +
            inc !state_extra
            rep #$20
            lda $94
            sep #$20
            sta !sprite_x_pos_lo,x
            xba
            sta !sprite_x_pos_hi,x
        +
        jmp .return

    .slam
        lda !hand_slap_down_frame
        sta !frame,x
        rep #$20
        lda #.slam_interation_callback
        sta !interaction_callback
        sep #$20
        lda.b !slap_down_speed
        sta !sprite_y_speed,x
        stz !sprite_x_speed,x
        jsl !update_sprite_y_pos_no_gravity
        lda !sprite_y_pos_hi,x
        xba
        lda !sprite_y_pos_lo,x
        rep #$20
        cmp !ground_y_pos+$10
        sep #$20
        bcc +
            rep #$20
            lda !ground_y_pos+$10
            sep #$20
            sta !sprite_y_pos_lo,x
            xba
            sta !sprite_y_pos_hi,x
            inc !state_extra
            rep #$20
            lda #$0030
            sta !state_timer
            sep #$20
            lda #$10
            sta !shake_timer
            lda !slap_down_sound_effect
            sta !slap_down_sound_bank
        +
        jmp .return

    .sleep
        lda !hand_slap_down_frame
        sta !frame,x
        rep #$20
        lda !state_timer
        sep #$20
        bne +
            inc !state_extra
        +
        jmp .return
    .end
        lda !return_state
        sta !state
        lda !hand_relaxed_frame
        sta !frame,x
    .return
    rts

    .slam_interation_callback
        jsr .sprite_hit_below
        rts

    .sprite_hit_below
        stz $0C
        lda $1497
        bne .int_return
        jsl !SubVertPos          ; \
        lda.b $0E                 ;  | if mario isn't above sprite, and there's vertical contact...
        cmp.b #$E0                ;  |     ... sprite wins
        bcc .int_return
            LDA #$01                ; Disable interactions for a few frames
            STA $154C,x
            sta $0C
            lda $13EF
            bne ++
                lda #$04
                clc
                adc $D8,x
                sta $96
                lda $14D4,x
                adc #$00
                sta $97
                rep #$20
                lda $96
                cmp !ground_y_pos
                bcc +
                    lda !ground_y_pos
                    sta $96
                    sep #$20
                    jsl !hurt_mario
                +
                sep #$20
                jmp .int_return
            ++
            lda $1497
            bne .int_return
                jsl !hurt_mario
        .int_return
        rts

!dying_smash_rising_y = #$00E0
dying_smash_rising_x:
    dw $0118, $01D0
dying_smash_rising_x_speed:
    db $E0,$18
!dying_smash_rising_y_speed = #$C0
!dying_smash_delay_time = #$0020
!ground_y_pos = #$0154
dying_smash_routine:
    ldx $15E9
    rep #$20
    lda #.interaction_callback
    sta !interaction_callback
    sep #$20
    lda !hand_clenched_frame
    sta !frame,x
    lda !state_extra
    bne +
    jmp .rising
    +
    cmp #$01
    bne +
    jmp .delay
    +
    cmp #$02
    bne +
    jmp .smashing
    +
    ; Finish and stuff
    inc !state_extra+1
    rts
    .rising
        lda !dying_smash_rising_y_speed
        sta !sprite_y_speed,x
        lda !which_hand
        phx
        tax
        lda dying_smash_rising_x_speed,x
        pha
        txa
        asl
        tax
        rep #$20
        lda dying_smash_rising_x,x
        sta $0E
        sep #$20
        pla
        plx
        sta !sprite_x_speed,x
        jsl !update_sprite_y_pos_no_gravity
        jsl !update_sprite_x_pos_no_gravity
        stz $00
        lda !which_hand
        bne +++
            lda !sprite_x_pos_hi,x
            xba
            lda !sprite_x_pos_lo,x
            rep #$20
            cmp $0E
            beq +
            bcs ++
            +
                lda $0E
                sep #$20
                sta !sprite_x_pos_lo,x
                xba
                sta !sprite_x_pos_hi,x
                inc $00
            ++
            sep #$20
            jmp .rising_x_done
        +++
            lda !sprite_x_pos_hi,x
            xba
            lda !sprite_x_pos_lo,x
            rep #$20
            cmp $0E
            bcc ++
                lda $0E
                sep #$20
                sta !sprite_x_pos_lo,x
                xba
                sta !sprite_x_pos_hi,x
                inc $00
            ++
            sep #$20
            jmp .rising_x_done
        .rising_x_done
        lda !sprite_y_pos_hi,x
        xba
        lda !sprite_y_pos_lo,x
        rep #$20
        cmp !dying_smash_rising_y
        beq +
        bcs ++
        +
            lda !dying_smash_rising_y
            sep #$20
            sta !sprite_y_pos_lo,x
            xba
            sta !sprite_y_pos_hi,x
            inc $00
        ++
        sep #$20
        lda $00
        cmp #$02
        bne +
            inc !state_extra
            rep #$20
            lda !dying_smash_delay_time
            sta !state_timer
            sep #$20
        +
        rts
    .delay
        lda !state_timer
        bne +
            inc !state_extra
        +
        rts
    .smashing
        lda !smash_speed
        sta !sprite_y_speed,x
        stz !sprite_x_speed,x
        jsl !update_sprite_y_pos_no_gravity  ;changed to jsl from jsr
        lda !sprite_y_pos_hi,x
        xba
        lda !sprite_y_pos_lo,x
        rep #$20
        cmp !ground_y_pos
        bcc +
            inc !state_extra
            lda !ground_y_pos
            sep #$20
            sta !sprite_y_pos_lo,x
            xba
            sta !sprite_y_pos_hi,x
            lda #$10
            sta !shake_timer
            lda !smash_sound_effect
            sta !smash_sound_bank
        +
        sep #$20
        rts
    .interaction_callback
        jsr ride_sprite
        jsr sprite_hit_below
        jsr sprite_act_solid
        rts

delay_times:
    db $00,$00,$20,$40,$00,$20,$40,$80

return_routine:
    ldx $15E9
    lda !hand_relaxed_frame
    sta !frame,x
    rep #$20
    stz !interaction_callback
    sep #$20
    stz $04 ; Counter for which axis have reached the right positions. When it's 2, the state ends
    lda !which_hand
    bne +
        rep #$20
        lda !left_hand_start_x
        bra ++
    +
        rep #$20
        lda !right_hand_start_x
    ++
    sta $02
    sep #$20
    lda !sprite_x_pos_hi,x
    xba
    lda !sprite_x_pos_lo,x
    rep #$20
    sta $05
    sec
    sbc $02
    php
    bpl +
        eor #$FFFF
        inc
    +
    cmp #$0004
    bcs +
        plp
        lda $02
        inc $04
        bra ++
    +
        lda $05
        plp
        bpl +++
            clc
            adc #$0003
            bra ++
        +++
        sec
        sbc #$0003
    ++
    sep #$20
    sta !sprite_x_pos_lo,x
    xba
    sta !sprite_x_pos_hi,x

    lda !sprite_y_pos_hi,x
    xba
    lda !sprite_y_pos_lo,x

    rep #$20
    sta $05
    sec
    sbc !hand_start_y
    php
    bpl +
        eor #$FFFF
        inc
    +
    cmp #$0004
    bcs +
        plp
        lda !hand_start_y
        inc $04
        bra ++
    +
        lda $05
        plp
        bpl +++
            clc
            adc #$0003
            bra ++
        +++
        sec
        sbc #$0003
    ++
    sep #$20
    sta  !sprite_y_pos_lo,x
    xba
    sta !sprite_y_pos_hi,x

    lda $04
    cmp #$02
    bne +
        lda !idle_state
        sta !state
        rep #$20
        lda !init_state_time
        sta !state_timer
        sep #$20
        lda !health
        cmp #$04
        bcs .one_hand
            phx
            tax
            lda delay_times,x
            sta !hand_delay_timer
            plx
            jmp +
        .one_hand
            phx
            tax
            lda delay_times,x
            sta !left_hand_delay_timer
            sta !right_hand_delay_timer
            sta !hand_delay_timer
            plx
    +
    rts

copy_right_hand:
    lda !right_hand_x_pos+1
    sta !sprite_x_pos_hi,x
    lda !right_hand_x_pos
    sta !sprite_x_pos_lo,x
    lda !right_hand_y_pos+1
    sta !sprite_y_pos_hi,x
    lda !right_hand_y_pos
    sta !sprite_y_pos_lo,x
    lda !right_hand_frame
    sta !frame,x
    lda !right_hand_x_speed
    sta !sprite_x_speed,x
    lda !right_hand_y_speed
    sta !sprite_y_speed,x
    lda !right_hand_x_acc_bits
    sta !sprite_x_acc_bits,x
    lda !right_hand_y_acc_bits
    sta !sprite_y_acc_bits,x
    stz !sprite_horz_direction,x

    lda !right_hand_delay_timer
    sta !hand_delay_timer

    lda !right_hand_state
    sta !state
    rep #$20
    lda !right_hand_state_timer
    sta !state_timer
    lda !right_hand_state_extra
    sta !state_extra
    lda !right_hand_state_extra+2
    sta !state_extra+2
    lda !right_hand_state_extra+4
    sta !state_extra+4
    lda !right_hand_state_extra+6
    sta !state_extra+6
    lda !right_hand_state_extra+8
    sta !state_extra+8
    lda !right_hand_interaction_callback
    sta !interaction_callback
    sep #$20

    lda #$01
    sta !which_hand

    rts
copy_left_hand:
    lda !left_hand_x_pos+1
    sta !sprite_x_pos_hi,x
    lda !left_hand_x_pos
    sta !sprite_x_pos_lo,x
    lda !left_hand_y_pos+1
    sta !sprite_y_pos_hi,x
    lda !left_hand_y_pos
    sta !sprite_y_pos_lo,x
    lda !left_hand_frame
    sta !frame,x
    lda !left_hand_x_speed
    sta !sprite_x_speed,x
    lda !left_hand_y_speed
    sta !sprite_y_speed,x
    lda !left_hand_x_acc_bits
    sta !sprite_x_acc_bits,x
    lda !left_hand_y_acc_bits
    sta !sprite_y_acc_bits,x
    lda #$01
    sta !sprite_horz_direction,x
    lda !left_hand_frame
    sta !frame,x

    lda !left_hand_delay_timer
    sta !hand_delay_timer

    lda !left_hand_state
    sta !state
    rep #$20
    lda !left_hand_state_timer
    sta !state_timer
    lda !left_hand_state_extra
    sta !state_extra
    lda !left_hand_state_extra+2
    sta !state_extra+2
    lda !left_hand_state_extra+4
    sta !state_extra+4
    lda !left_hand_state_extra+6
    sta !state_extra+6
    lda !left_hand_state_extra+8
    sta !state_extra+8
    lda !left_hand_interaction_callback
    sta !interaction_callback
    sep #$20

    stz !which_hand

    rts

restore_right_hand:
    lda !sprite_x_pos_hi,x
    sta !right_hand_x_pos+1
    lda !sprite_x_pos_lo,x
    sta !right_hand_x_pos
    lda !sprite_y_pos_hi,x
    sta !right_hand_y_pos+1
    lda !sprite_y_pos_lo,x
    sta !right_hand_y_pos
    lda !sprite_x_speed,x
    sta !right_hand_x_speed
    lda !sprite_y_speed,x
    sta !right_hand_y_speed
    lda !sprite_x_acc_bits,x
    sta !right_hand_x_acc_bits
    lda !sprite_y_acc_bits,x
    sta !right_hand_y_acc_bits
    lda !frame,x
    sta !right_hand_frame

    lda !hand_delay_timer
    sta !right_hand_delay_timer

    lda !state
    sta !right_hand_state
    rep #$20
    lda !state_timer
    sta !right_hand_state_timer
    lda !state_extra
    sta !right_hand_state_extra
    lda !state_extra+2
    sta !right_hand_state_extra+2
    lda !state_extra+4
    sta !right_hand_state_extra+4
    lda !state_extra+6
    sta !right_hand_state_extra+6
    lda !state_extra+8
    sta !right_hand_state_extra+8
    lda !interaction_callback
    sta !right_hand_interaction_callback
    sep #$20

    lda #$FF
    sta !which_hand

    rts

restore_left_hand:
    lda !sprite_x_pos_hi,x
    sta !left_hand_x_pos+1
    lda !sprite_x_pos_lo,x
    sta !left_hand_x_pos
    lda !sprite_y_pos_hi,x
    sta !left_hand_y_pos+1
    lda !sprite_y_pos_lo,x
    sta !left_hand_y_pos
    lda !sprite_x_speed,x
    sta !left_hand_x_speed
    lda !sprite_y_speed,x
    sta !left_hand_y_speed
    lda !sprite_x_acc_bits,x
    sta !left_hand_x_acc_bits
    lda !sprite_y_acc_bits,x
    sta !left_hand_y_acc_bits
    lda !frame,x
    sta !left_hand_frame

    lda !hand_delay_timer
    sta !left_hand_delay_timer

    lda !state
    sta !left_hand_state
    rep #$20
    lda !state_timer
    sta !left_hand_state_timer
    lda !state_extra
    sta !left_hand_state_extra
    lda !state_extra+2
    sta !left_hand_state_extra+2
    lda !state_extra+4
    sta !left_hand_state_extra+4
    lda !state_extra+6
    sta !left_hand_state_extra+6
    lda !state_extra+8
    sta !left_hand_state_extra+8
    lda !interaction_callback
    sta !left_hand_interaction_callback
    sep #$20

    lda #$FF
    sta !which_hand

    rts

copy_rat:
    lda !rat_x_pos+1
    sta !sprite_x_pos_hi,x
    lda !rat_x_pos
    sta !sprite_x_pos_lo,x
    lda !rat_y_pos+1
    sta !sprite_y_pos_hi,x
    lda !rat_y_pos
    sta !sprite_y_pos_lo,x
    lda !rat_frame
    sta !frame,x
    lda !rat_x_speed
    sta !sprite_x_speed,x
    lda !rat_y_speed
    sta !sprite_y_speed,x
    lda !rat_x_acc_bits
    sta !sprite_x_acc_bits,x
    lda !rat_y_acc_bits
    sta !sprite_y_acc_bits,x
    lda !rat_direction
    sta !sprite_horz_direction,x
    rep #$20
    lda !rat_interaction_callback
    sta !interaction_callback
    sep #$20
    rts

restore_rat:
    lda !sprite_x_pos_hi,x
    sta !rat_x_pos+1
    lda !sprite_x_pos_lo,x
    sta !rat_x_pos
    lda !sprite_y_pos_hi,x
    sta !rat_y_pos+1
    lda !sprite_y_pos_lo,x
    sta !rat_y_pos
    lda !frame,x
    sta !rat_frame
    lda !sprite_x_speed,x
    sta !rat_x_speed
    lda !sprite_y_speed,x
    sta !rat_y_speed
    lda !sprite_x_acc_bits,x
    sta !rat_x_acc_bits
    lda !sprite_y_acc_bits,x
    sta !rat_y_acc_bits
    lda !sprite_horz_direction,x
    sta !rat_direction
    rep #$20
    lda !interaction_callback
    sta !rat_interaction_callback
    sep #$20
    rts

handle_hands:
    jsr copy_left_hand
    jsr interact_hand
    jsr draw_hand
    jsr restore_left_hand

    jsr copy_right_hand
    jsr interact_hand
    jsr draw_hand
    jsr restore_right_hand

    rts

handle_rat:
    jsr copy_rat
    jsr interact_rat
    jsr draw_rat
    jsr restore_rat
    rts

interact_hand:
    lda $9D
    bne .not_interact
    jsl !GetMarioClipping
    jsr GetRobotClipping
    jsl !CheckForContact
    bcc .not_interact        ; return if no contact
    rep #$20
    lda.l !interaction_callback
    beq +
    pea.w +
    pla
    dec
    pha
    lda.l !interaction_callback
    dec
    pha
    sep #$20
    rts
    +
    sep #$20
    .not_interact
    rts

interact_rat:
    lda $9D
    bne .not_interact
    jsl !GetMarioClipping
    lda !rat_clipping_value
    beq .not_interact
    dec
    jsr GetRatClipping
    jsl !CheckForContact
    bcc .not_interact        ; return if no contact
    rep #$20
    lda.l !interaction_callback
    beq +
    pea.w +
    pla
    dec
    pha
    lda.l !interaction_callback
    dec
    pha
    sep #$20
    rts
    +
    sep #$20
    .not_interact
    rts


GetRobotClipping:
    phy
    phx
    txy
    lda !frame,x
    tax
    STZ $0F                 ;$03B6A8    |
    LDA.l .SprClippingDispX,X        ;$03B6AA    |
    BPL .CODE_03B6B2             ;$03B6AE    |
    DEC $0F                 ;$03B6B0    |
.CODE_03B6B2
    CLC
    ADC.w $E4,Y             ;$03B6B3    |
    STA $04                 ;$03B6B6    |
    LDA.w $14E0,Y               ;$03B6B8    |
    ADC $0F                 ;$03B6BB    |
    STA $0A                 ;$03B6BD    |
    LDA.l .SprClippingWidth,X        ;$03B6BF    |
    STA $06                 ;$03B6C3    |
    STZ $0F                 ;$03B6C5    |
    LDA.l .SprClippingDispY,X        ;$03B6C7    |
    BPL .CODE_03B6CF             ;$03B6CB    |
    DEC $0F                 ;$03B6CD    |
.CODE_03B6CF
    CLC
    ADC.w $D8,Y             ;$03B6D0    |
    STA $05                 ;$03B6D3    |
    LDA.w $14D4,Y               ;$03B6D5    |
    ADC $0F                 ;$03B6D8    |
    STA $0B                 ;$03B6DA    |
    LDA.l .SprClippingHeight,X       ;$03B6DC    |
    STA $07                 ;$03B6E0    |
    PLX                 ;$03B6E2    |
    PLY                 ;$03B6E3    |
    rts                 ;$03B6E4    |
    ; By frame
    .SprClippingDispX
        db $00,$F2,$F8,$F0
    .SprClippingWidth
        db $00,$2D,$10,$30
        
    .SprClippingDispY
        db $00,$F0,$F0,$F8
    .SprClippingHeight
        db $00,$34,$30,$10

GetRatClipping:
    phy
    phx
    txy
    tax
    STZ $0F                 ;$03B6A8    |
    LDA.l .SprClippingDispX,X        ;$03B6AA    |
    BPL .CODE_03B6B2             ;$03B6AE    |
    DEC $0F                 ;$03B6B0    |
.CODE_03B6B2
    CLC
    ADC.w $E4,Y             ;$03B6B3    |
    STA $04                 ;$03B6B6    |
    LDA.w $14E0,Y               ;$03B6B8    |
    ADC $0F                 ;$03B6BB    |
    STA $0A                 ;$03B6BD    |
    LDA.l .SprClippingWidth,X        ;$03B6BF    |
    STA $06                 ;$03B6C3    |
    STZ $0F                 ;$03B6C5    |
    LDA.l .SprClippingDispY,X        ;$03B6C7    |
    clc
    adc !rat_bob_off
    BPL .CODE_03B6CF             ;$03B6CB    |
    DEC $0F                 ;$03B6CD    |
.CODE_03B6CF
    CLC
    ADC.w $D8,Y             ;$03B6D0    |
    STA $05                 ;$03B6D3    |
    LDA.w $14D4,Y               ;$03B6D5    |
    ADC $0F                 ;$03B6D8    |
    STA $0B                 ;$03B6DA    |
    LDA.l .SprClippingHeight,X       ;$03B6DC    |
    STA $07                 ;$03B6E0    |
    PLX                 ;$03B6E2    |
    PLY                 ;$03B6E3    |
    rts                 ;$03B6E4    |
    ; By frame
    .SprClippingDispX
        db $FA
    .SprClippingWidth
        db $0D
        
    .SprClippingDispY
        db $08
    .SprClippingHeight
        db $24

ride_sprite:
    stz $0D
    jsl !SubVertPos           ; \
    LDA.b $0E                 ;  | if mario isn't above sprite, and there's vertical contact...
    CMP.b #$C1                ;  |     ... sprite wins
    bcs +
        jmp .return
    +
    lda $0E
    cmp.b #$E0
    bcc +
        jmp .return
    +
    sta $0D
    lda $7D
    bpl +
      jmp .return
    +
        LDA.b #$01                ; \ set "on sprite" flag
        STA.w $1471               ; /
        STZ.b $7D                 ; Y speed = 0
        LDA.b #$D1                ; \
        LDY.w $187A               ;  | mario's y position += E1 or D1 depending if on yoshi
        BEQ +                   ;  |
        LDA.b #$C1                ;  |
        +
        CLC                     ;  |
        ADC.b $D8,x               ;  |
        STA.b $96                 ;  |
        LDA.w $14D4,x             ;  |
        ADC.b #$FF                ;  |
        STA.b $97                 ; /
        LDA #$01                ; Disable interactions for a few frames
        STA $154C,x
        ;REP #$20
        ldy #$00
        lda !XMovement,x
        sta $00
        bpl +
        ldy #$FF
        +
        tya
        sta $01
        rep #$20
        LDA.b $94
        CLC
        ADC $00
        STA.b $94
        sep #$20
        
    .return
    rts

sprite_act_solid:
    lda $1471
    ora $0D
    ;ora $0C
    ora $9D
    ora $71
    ora $154C,x
    bne .return
    ;lda $0F
    ;cmp.b #$B2
    ;bcc .return
    lda $14D4,x
    xba
    lda $D8,x
    rep #$20
    clc
    adc #$0008
    ldy $19
    beq +
        clc
        adc #$0008
    +
    cmp $96
    sep #$20
    bcc .return
    jsl !SubHorizPos
    LDA.b $0F
    CMP.b #$DC
    bcc .CheckRight
    ;bcs .return
        LDA.b #$E3                ; \
        CLC                     ;  |
        ADC.b $E4,x               ;  |
        STA.b $94                 ;  |
        LDA.w $14E0,x             ;  |
        ADC.b #$FF                ;  |
        STA.b $95                 ; /
        stz $7B
        bra .return
    .CheckRight
    cmp.b #$30
    bcs .return
    ;cmp.b #$20
    ;bcs .return
        LDA.b #$1E                ; \
        CLC                     ;  |
        ADC.b $E4,x               ;  |
        STA.b $94                 ;  |
        LDA.w $14E0,x             ;  |
        ADC.b #$00                ;  |
        STA.b $95                 ; /
        stz $7B
    .return
    rts

;This code is hilariously bad, because solid objects are freakin' magic to me
sprite_hit_below:
    stz $0C
    ;jsl !SubVertPos          ; \
    ;lda.b $0E                 ;  | if mario isn't above sprite, and there's vertical contact...
    ;ldy $19
    ;beq +
    ;    sec
    ;    sbc #$20
    ;    sta $0E
    ;+
    ;lda $0E
    ;bpl .sprite_wins
    ;cmp.b #$FD                ;  |     ... sprite wins
    lda $14D4,x
    xba
    lda $D8,x
    rep #$20
    clc
    adc #$001B
    ldy $19
    beq +
    ldy $73
    bne +
        sec
        sbc #$0004
    +
    cmp $96
    bcs +
        sep #$20
        jmp .return
    +
    sec
    sbc $96
    ldy $73
    bne +
    ldy $19
    bne ++
    +
        sec
        sbc #$000C
    ++
    bmi .return
    cmp #$000C
    sep #$20
    bcs .return
        .sprite_wins
        ;lda $154C,x
        ;bne .return
        LDA #$01                ; Disable interactions for a few frames
        STA $154C,x
        sta $0C
        lda $13EF
        bne +++
            lda #$12
            phy
            ldy $19
            beq +
            ldy $73
            bne +
                clc
                adc #$06
            +
            ply
            clc
            adc $D8,x
            sta $96
            lda $14D4,x
            adc #$00
            sta $97
            lda $7D
            bpl +
                lda !sprite_y_speed,x
                bra ++
            +
                cmp !sprite_y_speed,x
                bcs ++
                lda !sprite_y_speed,x
            ++
            sta $7D
            rep #$20
            lda $96
            cmp !ground_y_pos
            bcc +
                lda !ground_y_pos
                sta $96
                sep #$20
                jsl !hurt_mario
            +
            sep #$20
            jmp .return
        +++
        lda $1497
        bne .return
        lda !sprite_y_speed,x
        beq .return
        bmi .return
            jsl !hurt_mario
    .return
    rts

hand_tile_count:
    db $05,$08,$05,$05

hand_tile_pointers:
    dw hand_relaxed_tiles
    dw hand_clenched_tiles
    dw hand_slap_tiles
    dw hand_slap_down_tiles

hand_x_off_pointers:
    dw hand_relaxed_x_off
    dw hand_clenched_x_off
    dw hand_slap_x_off
    dw hand_slap_down_x_off

hand_y_off_pointers:
    dw hand_relaxed_y_off
    dw hand_clenched_y_off
    dw hand_slap_y_off
    dw hand_slap_down_y_off

hand_relaxed_tiles:
hand_slap_tiles:
    db $86,$88
    db $A6,$A8
    db $C6,$C8
hand_clenched_tiles:
    db $8A,$8C,$8E
    db $AA,$AC,$AE
    db $CA,$CC,$CE
hand_slap_down_tiles:
    db $80,$82,$84
    db $A0,$A2,$A4

hand_relaxed_x_off:
hand_slap_x_off:
    db $F0,$00
    db $F0,$00
    db $F0,$00

hand_relaxed_y_off:
hand_slap_y_off:
    db $F0,$F0
    db $00,$00
    db $10,$10

hand_clenched_x_off:
    db $F0,$00,$10
    db $F0,$00,$10
    db $F0,$00,$10

hand_clenched_y_off:
    db $F0,$F0,$F0
    db $00,$00,$00
    db $10,$10,$10

hand_slap_down_x_off:
    db $F0,$00,$10
    db $F0,$00,$10

hand_slap_down_y_off:
    db $F0,$F0,$F0
    db $00,$00,$00



draw_hand:
    jsl !GetDrawInfo
    lda !sprite_horz_direction,x
    sta !direction_tmp
    lda !frame,x
    phx
    tax
    lda hand_tile_count,x
    sta !tile_count_tmp
    txa
    asl
    tax
    rep #$20
    lda hand_tile_pointers,x
    sta !tiles_pointer
    lda hand_x_off_pointers,x
    sta !x_off_pointer
    lda hand_y_off_pointers,x
    sta !y_off_pointer
    sep #$20
    plx
    phx
    ldx !tile_count_tmp
    .draw_loop
        lda !direction_tmp
        bne +
            lda $00
            phy
            txy
            clc
            adc (!x_off_pointer),y
            ply
            bra ++
        +
            lda $00
            phy
            txy
            sec
            sbc (!x_off_pointer),y
            ;sec
            ;sbc.b #$10
            ply
        ++
        sta $0300,y

        lda $01
        phy
        txy
        clc
        adc (!y_off_pointer),y
        ply
        sta $0301,y

        phx
        ldx $15E9
        lda $15F6,x
        plx
        ora $64
        phy
        ldy !direction_tmp
        beq +
            ora #$40
        +
        ply
        sta $0303,y

        phy
        txy
        lda (!tiles_pointer),y
        ply
        sta $0302,y

        iny
        iny
        iny
        iny
        dex
        bpl .draw_loop

    .done
    plx
    phy
    lda !tile_count_tmp
    ldy #$02
    jsl $81B7B3                 ;/and then draw em
    ply
    tya
    sta $15EA,x
    rts

rat_tile_count:
    db $05,$05,$05,$05,$05,$06,$06,$06,$06,$06,$03,$03,$03,$05

rat_tile_props_pointers:
    dw rat_standing_props
    dw rat_talking_props
    dw rat_press_button_1_props
    dw rat_press_button_2_props
    dw rat_jetpack_0_props
    dw rat_jetpack_1_props
    dw rat_jetpack_2_props
    dw rat_jetpack_3_props
    dw rat_jetpack_4_props
    dw rat_jetpack_5_props
    dw rat_controlling_1_props
    dw rat_controlling_2_props
    dw rat_controlling_3_props
    
rat_tile_size_pointers:
    dw rat_standing_sizes
    dw rat_talking_sizes
    dw rat_press_button_1_sizes
    dw rat_press_button_2_sizes
    dw rat_jetpack_0_sizes
    dw rat_jetpack_1_sizes
    dw rat_jetpack_2_sizes
    dw rat_jetpack_3_sizes
    dw rat_jetpack_4_sizes
    dw rat_jetpack_5_sizes
    dw rat_controlling_1_sizes
    dw rat_controlling_2_sizes
    dw rat_controlling_3_sizes

rat_tile_pointers:
    dw rat_standing_tiles
    dw rat_talking_tiles
    dw rat_press_button_1_tiles
    dw rat_press_button_2_tiles
    dw rat_jetpack_0_tiles
    dw rat_jetpack_1_tiles
    dw rat_jetpack_2_tiles
    dw rat_jetpack_3_tiles
    dw rat_jetpack_4_tiles
    dw rat_jetpack_5_tiles
    dw rat_controlling_1_tiles
    dw rat_controlling_2_tiles
    dw rat_controlling_3_tiles

rat_x_off_pointers:
    dw rat_standing_x_off
    dw rat_talking_x_off
    dw rat_press_button_1_x_off
    dw rat_press_button_2_x_off
    dw rat_jetpack_0_x_off
    dw rat_jetpack_1_x_off
    dw rat_jetpack_2_x_off
    dw rat_jetpack_3_x_off
    dw rat_jetpack_4_x_off
    dw rat_jetpack_5_x_off
    dw rat_controlling_1_x_off
    dw rat_controlling_2_x_off
    dw rat_controlling_3_x_off

rat_y_off_pointers:
    dw rat_standing_y_off
    dw rat_talking_y_off
    dw rat_press_button_1_y_off
    dw rat_press_button_2_y_off
    dw rat_jetpack_0_y_off
    dw rat_jetpack_1_y_off
    dw rat_jetpack_2_y_off
    dw rat_jetpack_3_y_off
    dw rat_jetpack_4_y_off
    dw rat_jetpack_5_y_off
    dw rat_controlling_1_y_off
    dw rat_controlling_2_y_off
    dw rat_controlling_3_y_off

rat_standing_tiles:
    db $00,$01
    db $20,$21
    db $40,$41
rat_talking_tiles:
    db $03,$23
    db $20,$21
    db $40,$41
rat_press_button_1_tiles:
    db $00,$01
    db $05,$21
    db $40,$41
rat_press_button_2_tiles:
    db $00,$01
    db $07,$21
    db $40,$41
rat_jetpack_0_tiles:
    db $09,$0A
    db $29,$2A
    db $49,$4A
rat_jetpack_1_tiles:
    db $09,$0A
    db $29,$2A
    db $49,$4A
    db $0F
rat_jetpack_2_tiles:
    db $09,$0A
    db $29,$2A
    db $49,$4A
    db $1F
rat_jetpack_3_tiles:
    db $09,$0A
    db $29,$2A
    db $49,$45
    db $2F
rat_jetpack_4_tiles:
    db $09,$0A
    db $29,$2A
    db $49,$47
    db $3F
rat_jetpack_5_tiles:
    db $09,$0A
    db $29,$2A
    db $49,$4A
    db $2F
rat_controlling_1_tiles:
    db $61,$62
    db $64,$66
rat_controlling_2_tiles:
    db $61,$62
    db $68,$6A
rat_controlling_3_tiles:
    db $61,$62
    db $6C,$6E

rat_standing_x_off:
    db $F4,$FC
    db $F4,$FC
    db $F4,$FC
rat_talking_x_off:
    db $F4,$04
    db $F4,$FC
    db $F4,$FC
rat_press_button_1_x_off:
    db $F4,$FC
    db $F4,$FC
    db $F4,$FC
rat_press_button_2_x_off:
    db $F4,$FC
    db $F4,$FC
    db $F4,$FC
rat_jetpack_0_x_off:
    db $F4,$FC
    db $F4,$FC
    db $F4,$FC
rat_jetpack_1_x_off:
    db $F4,$FC
    db $F4,$FC
    db $F4,$FC
    db $04
rat_jetpack_2_x_off:
    db $F4,$FC
    db $F4,$FC
    db $F4,$FC
    db $04
rat_jetpack_3_x_off:
    db $F4,$FC
    db $F4,$FC
    db $F4,$FC
    db $04
rat_jetpack_4_x_off:
    db $F4,$FC
    db $F4,$FC
    db $F4,$FC
    db $04
rat_jetpack_5_x_off:
    db $F4,$FC
    db $F4,$FC
    db $F4,$FC
    db $04
rat_controlling_1_x_off:
    db $F8,$00
    db $F0,$00
rat_controlling_2_x_off:
    db $F8,$00
    db $F0,$00
rat_controlling_3_x_off:
    db $F8,$00
    db $F0,$00

rat_standing_y_off:
    db $00,$00
    db $10,$10
    db $20,$20
rat_talking_y_off:
    db $00,$00
    db $10,$10
    db $20,$20
rat_press_button_1_y_off:
    db $00,$00
    db $10,$10
    db $20,$20
rat_press_button_2_y_off:
    db $00,$00
    db $10,$10
    db $20,$20
rat_jetpack_0_y_off:
    db $00,$00
    db $10,$10
    db $20,$20
rat_jetpack_1_y_off:
    db $00,$00
    db $10,$10
    db $20,$20
    db $18
rat_jetpack_2_y_off:
    db $00,$00
    db $10,$10
    db $20,$20
    db $18
rat_jetpack_3_y_off:
    db $00,$00
    db $10,$10
    db $20,$20
    db $18
rat_jetpack_4_y_off:
    db $00,$00
    db $10,$10
    db $20,$20
    db $18
rat_jetpack_5_y_off:
    db $00,$00
    db $10,$10
    db $20,$20
    db $18
rat_controlling_1_y_off:
    db $00,$00
    db $10,$10
rat_controlling_2_y_off:
    db $00,$00
    db $10,$10
rat_controlling_3_y_off:
    db $00,$00
    db $10,$10

rat_standing_sizes:
    db $02,$02
    db $02,$02
    db $02,$02
rat_talking_sizes:
    db $02,$02
    db $02,$02
    db $02,$02
rat_press_button_1_sizes:
    db $02,$02
    db $02,$02
    db $02,$02
rat_press_button_2_sizes:
    db $02,$02
    db $02,$02
    db $02,$02
rat_jetpack_0_sizes:
    db $02,$02
    db $02,$02
    db $02,$02
rat_jetpack_1_sizes:
    db $02,$02
    db $02,$02
    db $02,$02
    db $00
rat_jetpack_2_sizes:
    db $02,$02
    db $02,$02
    db $02,$02
    db $00
rat_jetpack_3_sizes:
    db $02,$02
    db $02,$02
    db $02,$02
    db $00
rat_jetpack_4_sizes:
    db $02,$02
    db $02,$02
    db $02,$02
    db $00
rat_jetpack_5_sizes:
    db $02,$02
    db $02,$02
    db $02,$02
    db $00
rat_controlling_1_sizes:
    db $02,$02
    db $02,$02
rat_controlling_2_sizes:
    db $02,$02
    db $02,$02
rat_controlling_3_sizes:
    db $02,$02
    db $02,$02

rat_standing_props:
    db $0D,$0D
    db $0D,$0D
    db $0D,$0D
rat_talking_props:
    db $0D,$0D
    db $0D,$0D
    db $0D,$0D
rat_press_button_1_props:
    db $0D,$0D
    db $0D,$0D
    db $0D,$0D
rat_press_button_2_props:
    db $0D,$0D
    db $0D,$0D
    db $0D,$0D
rat_jetpack_0_props:
    db $0D,$0D
    db $0D,$0D
    db $0D,$0D
rat_jetpack_1_props:
    db $0D,$0D
    db $0D,$0D
    db $0D,$0D
    db $0D
rat_jetpack_2_props:
    db $0D,$0D
    db $0D,$0D
    db $0D,$0D
    db $0D
rat_jetpack_3_props:
    db $0D,$0D
    db $0D,$0D
    db $0D,$0D
    db $0D
rat_jetpack_4_props:
    db $0D,$0D
    db $0D,$0D
    db $0D,$0D
    db $0D
rat_jetpack_5_props:
    db $0D,$0D
    db $0D,$0D
    db $0D,$0D
    db $0D
rat_controlling_1_props:
    db $0D,$0D
    db $0D,$0D
rat_controlling_2_props:
    db $0D,$0D
    db $0D,$0D
rat_controlling_3_props:
    db $0D,$0D
    db $0D,$0D



draw_rat:
    jsl !GetDrawInfo
    lda !sprite_horz_direction,x
    sta !direction_tmp
    lda !frame,x
    phx
    tax
    lda rat_tile_count,x
    sta !tile_count_tmp
    sta $0D
    txa
    asl
    tax
    rep #$20
    lda rat_tile_pointers,x
    sta !tiles_pointer
    lda rat_x_off_pointers,x
    sta !x_off_pointer
    lda rat_y_off_pointers,x
    sta !y_off_pointer
    lda rat_tile_size_pointers,x
    sta !tile_size_pointer
    lda rat_tile_props_pointers,x
    sta !tile_props_pointer
    sep #$20
    plx
    lda !rat_hurt_timer
    beq +
        lda $14
        lsr #3
        and #$01
        bne +
        jsr draw_shield
        lda !tile_count_tmp
        dec
        dec
        sta $0D
    +
    phx
    ldx $0D
    .draw_loop
        lda !direction_tmp
        bne +
            lda $00
            phy
            txy
            clc
            adc (!x_off_pointer),y
            ply
            bra ++
        +
            lda $00
            phy
            txy
            sec
            sbc (!x_off_pointer),y
            pha
            lda (!tile_size_pointer),y
            beq +
                pla
                sec
                sbc #$08
                pha
            +
            pla
            ply
        ++
        sta $0300,y

        lda $01
        phy
        txy
        clc
        adc (!y_off_pointer),y
        ply
        clc
        adc !rat_bob_off
        sta $0301,y

        phy
        txy
        lda (!tile_props_pointer),y
        ply
        ora !rat_priority
        phy
        ldy !direction_tmp
        beq +
            ora #$40
        +
        ply
        sta $0303,y

        phy
        txy
        lda (!tiles_pointer),y
        ply
        sta $0302,y

        phy
        tya
        lsr #2
        tay
        phy
        txy
        lda (!tile_size_pointer),y
        ply
        phx
        ldx $15E9
        ora $15A0,x
        plx
        sta $0460,y
        ply

        iny
        iny
        iny
        iny
        dex
        bpl .draw_loop

    .done
    plx
    phy
    lda !tile_count_tmp
    ldy #$FF
    jsl $81B7B3                 ;/and then draw em
    ply
    tya
    sta $15EA,x
    rts

shield_tiles:
    db $25,$27
shield_x_off:
    db $F0,$00
shield_y_off:
    db $FC,$FC

draw_shield:
    phx
    ldx #$01
    .tile_loop
        lda !direction_tmp
        bne +
            lda $00
            clc
            adc shield_x_off,x
            bra ++
        +
            lda $00
            sec
            sbc shield_x_off,x
            sec
            sbc #$08
        ++
        sta $0300,y
        lda $01
        clc
        adc shield_y_off,x
        clc
        adc !rat_bob_off
        sta $0301,y
        lda $64
        ora.b #%00000111
        phy
        ldy !direction_tmp
        beq +
            ora #$40
        +
        ply
        sta $0303,y
        lda shield_tiles,x
        sta $0302,y

        phy
        tya
        lsr #2
        tay
        lda #$02
        phx
        ldx $15E9
        ora $15A0,x
        plx
        sta $0460,y
        ply
        inc !tile_count_tmp
        iny
        iny
        iny
        iny
        dex
        bpl .tile_loop
    .done
    plx
    rts

spawn_custom_sprite:
    lda $186C,x
    bne .return
    jsl $82A9DE
    bmi .return
    lda #$01                ; Sprite state ($14C8,x).
    sta $14C8,y
    phx
    tyx
    stx !sprite_spawn_return_slot
    lda !sprite_spawn_sprite_number
    sta $7FAB9E,x
    plx
    lda !sprite_spawn_x_lo
    sta $00E4,y
    lda !sprite_spawn_x_hi
    sta $14E0,y
    lda !sprite_spawn_y_lo
    sta $00D8,y
    lda !sprite_spawn_y_hi
    sta $14D4,y
    phx
    tyx
    jsl $87F7D2
    jsl $8187A7
    lda #$08
    sta $7FAB10,x
    plx
.return
    rts

!arrow_tile = #$0D
!arrow_props = #$05
!arrow_x = #$80
!arrow_y = #$70
blink_arrow:
    lda $14
    lsr #4
    and #$01
    bne .return
    ldy $15EA,x
    lda !arrow_x
    sta $0300,y
    lda !arrow_y
    sta $0301,y
    lda !arrow_tile
    sta $0302,y
    lda !arrow_props
    ora $64
    sta $0303,y
    lda #$00
    ldy #$02
    jsl $81B7B3
    ldy $15EA,x
    iny #4
    tya
    sta $15EA,x
    .return
    rts