; level_x_move_player - move the player, call subroutines based on button presses
; level_x_move_player_right - go right, or stop and scroll background 
; level_x_move_player_left - go left
; lxmpl_subcopy - copy tile data to player
; level_x_update_floor_table - floor table is used to determine if player falls or not
; level_x_player_falling - is the player falling? check floor table
; level_x_player_up - move the player up, called by jumping
; level_x_handle_jumping - handle jumping

;-------------------------------------------------------------------
;-------------------------------------------------------------------
;-------------------------------------------------------------------
; Player movement
;-------------------------------------------------------------------
;-------------------------------------------------------------------
;-------------------------------------------------------------------
   
;----------------------------
; level_x_move_player
;
level_x_move_player:
   PUSH BC                     ; Save registers
   PUSH DE                     ;
   PUSH HL                     ;
   PUSH AF                     ;

; Stand still is default
   LD de, level_x_stand_frame  ; Stand still frame is default
   CALL lxmpl_subcopy          ;

; Go left or right?
   IN a, (PORT_INPUT1)         ;   
   CALL lxmp_left_or_right     ;
   BIT 5, a                    ;
   CALL Z, lxmp_left_or_right  ;   
      
; Jumping or falling?  
   CALL level_x_handle_jumping ;
   
   POP AF                      ; Restore registers
   POP HL                      ;
   POP DE                      ;
   POP BC                      ;
   RET                         ; End subroutine 

lxmp_left_or_right:
   BIT 2, a                    ; Go left?
   CALL Z, level_x_move_player_left ;
; Go right   
   BIT 3, a                    ; Go right?
   CALL Z, level_x_move_player_right;
   RET                         ; End subroutine    
   
;----------------------------
; level_x_move_player_right
;
level_x_move_player_right:
   PUSH BC                     ; Save registers
   PUSH DE                     ;
   PUSH HL                     ;
   PUSH AF                     ;

; Player run into a block?
   LD a, (RAM_PLAYER_X_COLUMN) ;
   ADD a, 1                    ; index
   LD de, $0000                ;
   LD e, a                     ;   
   LD hl, RAM_FLOOR_TABLE      ; base
   ADD hl,de                   ;
   LD a, (hl)                  ; Y-coordinate of column to left
   LD b, a                     ;
   LD a, (RAM_VPOS + 50)       ; Player Y-coordinate
   CP b                        ; a == b ?
   JP Z, lxmpr_animate         ; Run in place
   
; Change position   
   LD hl, RAM_HPOS + 84        ; Start of player HPOS
   LD b, 12                    ; 12 sprites

; Don't move player, but scroll screen
   LD a, (hl)                  ; 
   CP $A0                      ; Scroll screen if needed
   CALL Z, level_x_scroll_right ;
   LD a, (hl)                  ; 
   CP $A0                      ; Scroll screen if needed   
   JP Z, lxmpr_animate         ;
   
lxmpr_loop_0:   
   INC (hl)                    ; Go right
   INC hl                      ; Move address
   INC hl                      ;
   DEC b                       ;
   JP NZ, lxmpr_loop_0         ;   

; Change player column?
   LD a, (RAM_HPOS + 102)      ; Player X-coordinate (sprite 51)
   RRA                         ; Divide by 8
   RRA                         ;
   RRA                         ;
   AND $1F                     ; Mask unwanted upper bits
   LD (RAM_PLAYER_X_COLUMN), a ;
    
; Animate tiles
lxmpr_animate:
   LD a, (RAM_FRAME_CTR)       ; Change based on frame
   AND $18                     ; Mask unwanted bits
   CP $00                      ;
   JP Z, lxmpr_frame0          ;
   CP $08                      ;
   JP Z, lxmpr_frame1          ;
   CP $10                      ;
   JP Z, lxmpr_frame0          ;   
   CP $18                      ;
   JP Z, lxmpr_frame2          ;
   
lxmpr_frame0:   
   LD de, level_x_run_frame_R0 ;
   JP lxmpr_frame_done         ;
lxmpr_frame1:   
   LD de, level_x_run_frame_R1 ;  
   JP lxmpr_frame_done         ;
lxmpr_frame2:   
   LD de, level_x_run_frame_R2 ;

lxmpr_frame_done: 
   CALL lxmpl_subcopy          ;
   
   POP AF                      ; Restore registers
   POP HL                      ;
   POP DE                      ;
   POP BC                      ;
   RET                         ; End subroutine 

;----------------------------
; level_x_move_player_left
;
level_x_move_player_left:
   PUSH BC                     ; Save registers
   PUSH DE                     ;
   PUSH HL                     ;
   PUSH AF                     ;

; Player run into a block?
   LD a, (RAM_PLAYER_X_COLUMN) ;
   SUB 1                       ; index
   LD de, $0000                ;
   LD e, a                     ;   
   LD hl, RAM_FLOOR_TABLE      ; base
   ADD hl,de                   ;
   LD a, (hl)                  ; Y-coordinate of column to left
   LD b, a                     ;
   LD a, (RAM_VPOS + 50)       ; Player Y-coordinate
   CP b                        ; a == b ?
   JP Z, lxmpl_animate         ; Run in place

; Change position   
   LD hl, RAM_HPOS + 84        ; Start of player HPOS
   LD b, 12                    ; 12 sprites
   
; Don't move player. Don't scroll screen.
   LD a, (hl)                  ; 
   CP $08                      ; Stuck at edge of screen
   JP Z, lxmpl_animate         ;
   
lxmpl_loop_0:   
   DEC (hl)                    ; Go left
   INC hl                      ; Move address
   INC hl                      ;
   DEC b                       ;
   JP NZ, lxmpl_loop_0         ;

; Change player column?
   LD a, (RAM_HPOS + 102)      ; Player X-coordinate (sprite 51)
   RRA                         ; Divide by 8
   RRA                         ;
   RRA                         ;
   AND $1F                     ; Mask unwanted upper bits
   LD (RAM_PLAYER_X_COLUMN), a ;
   
; Animate tiles
lxmpl_animate:
   LD a, (RAM_FRAME_CTR)       ; Change based on frame
   AND $18                     ; Mask unwanted bits
   CP $00                      ;
   JP Z, lxmpl_frame0          ;
   CP $08                      ;
   JP Z, lxmpl_frame1          ;
   CP $10                      ;
   JP Z, lxmpl_frame0          ;   
   CP $18                      ;
   JP Z, lxmpl_frame2          ;
   
lxmpl_frame0:   
   LD de, level_x_run_frame_L0 ;
   JP lxmpl_frame_done         ;
lxmpl_frame1:   
   LD de, level_x_run_frame_L1 ;  
   JP lxmpl_frame_done         ;
lxmpl_frame2:   
   LD de, level_x_run_frame_L2 ;

lxmpl_frame_done: 
   CALL lxmpl_subcopy          ;
   
   POP AF                      ; Restore registers
   POP HL                      ;
   POP DE                      ;
   POP BC                      ;
   RET                         ; End subroutine   

;-------------------------------
; lxmpl_subcopy
;   
; Copy data from DE to player tiles.
;
lxmpl_subcopy:   
   LD hl, RAM_HPOS + 85        ; Start of player HPOS
   LD b, 12                    ; 12 sprites
   
lxmpl_loop_1:    
   LD a, (de)                  ; Copy tile
   LD (hl), a                  ;
   INC hl                      ; Move address
   INC hl                      ;   
   INC de                      ; Next tile 
   DEC b                       ;
   JP NZ, lxmpl_loop_1         ;   
   RET                         ; End subroutine   

;---------------------------------
; level_x_update_floor_table
;
level_x_update_floor_table:
   PUSH BC                      ; Save registers
   PUSH DE                      ;
   PUSH HL                      ;
   PUSH AF                      ;
   
; Shift floor values back 
   LD b, 32                     ;
   LD hl, RAM_FLOOR_TABLE       ; 
   LD de, RAM_FLOOR_TABLE + 1   ;
initft_01:
   LD a, (de)                   ; Initialize floor table
   LD (hl), a                   ;
   INC hl                       ;
   INC de                       ;
   DEC b                        ;
   JP NZ, initft_01             ;    

; Read new floor value  
   CALL level_x_col_list_set_HL ; Select column list
   
lxuft_level_selected:   
   LD de, (RAM_COLUMN_INDEX)    ; Get index within list
   ADD hl, de                   ; 
   LD a, (hl)                   ; Load offset 

; Translate index into floor value
   CP 0                         ;
   JP Z, lxufv_00_01            ;
   CP 1                         ;
   JP Z, lxufv_00_01            ;
   CP 2                         ;
   JP Z, lxufv_02_03            ;
   CP 3                         ;
   JP Z, lxufv_02_03            ;
   CP 4                         ;
   JP Z, lxufv_04_05            ;
   CP 5                         ;
   JP Z, lxufv_04_05            ;
   CP 6                         ;
   JP Z, lxufv_06_07            ;
   CP 7                         ;
   JP Z, lxufv_06_07            ;
   CP 8                         ;
   JP Z, lxufv_08_09            ;
   CP 9                         ;
   JP Z, lxufv_08_09            ;
   CP 10                        ;
   JP Z, lxufv_10_11            ;
   CP 11                        ;
   JP Z, lxufv_10_11            ;
   
lxufv_00_01:
   LD a, 20*8                   ; 
   LD (RAM_FLOOR_TABLE + 31), a ;
   JP lxufv_end                 ;   
lxufv_02_03:
   LD a, 24*8                   ; 
   LD (RAM_FLOOR_TABLE + 31), a ;
   JP lxufv_end                 ;    
lxufv_04_05:
   LD a, 14*8                   ; 
   LD (RAM_FLOOR_TABLE + 31), a ;
   JP lxufv_end                 ;   
lxufv_06_07:
   LD a, 8*8                    ; 
   LD (RAM_FLOOR_TABLE + 31), a ;
   JP lxufv_end                 ;     
lxufv_08_09:
   LD a, 10*8                   ; 
   LD (RAM_FLOOR_TABLE + 31), a ;
   JP lxufv_end                 ;   
lxufv_10_11:
   LD a, 16*8                   ; 
   LD (RAM_FLOOR_TABLE + 31), a ;
   JP lxufv_end                 ;    
   
 lxufv_end:  
   POP AF                       ; Restore registers
   POP HL                       ;
   POP DE                       ;
   POP BC                       ;
   RET                          ; End subroutine  

;-------------------------------
; level_x_player_falling
;
level_x_player_falling:
   PUSH BC                      ; Save registers
   PUSH DE                      ;
   PUSH HL                      ;
   PUSH AF                      ; 
   
; Middle sprite column   
   LD a, (RAM_PLAYER_X_COLUMN)  ; Player X-coordinate (sprite 53) 
   LD de, $0000                 ; Read from table with index
   LD e, a                      ;
   LD hl, RAM_FLOOR_TABLE       ;
   ADD hl, de                   ;
   LD a, (hl)                   ; Result, Y-coordinate of floor
   LD b, a                      ;

;----------------------------------   
   LD a, (RAM_VPOS + 51)        ; Player Y-coordinate  
   ADD a, 8                     ; Match floor Y-coordinate
   CP b                         ; (Player Y-coordinate + 8) == floor Y-coordinate
   JP Z, lxpf_end2              ; *** Center check
;----------------------------------    
   INC hl                       ;
   LD a, (hl)                   ; Result, Y-coordinate of floor
   LD b, a                      ;   
   LD a, (RAM_VPOS + 51)        ; Player Y-coordinate  
   ADD a, 8                     ; Match floor Y-coordinate   
   CP b                         ; (Player Y-coordinate + 8) == floor Y-coordinate
   JP Z, lxpf_end2              ; *** Right check
;---------------------------------- 
   DEC hl                       ;
   DEC hl                       ;
   LD a, (hl)                   ; Result, Y-coordinate of floor
   LD b, a                      ;   
   LD a, (RAM_VPOS + 51)        ; Player Y-coordinate  
   ADD a, 8                     ; Match floor Y-coordinate   
   CP b                         ; (Player Y-coordinate + 8) == floor Y-coordinate
   JP Z, lxpf_end2              ; *** Left check
;---------------------------------- 
   
   LD hl, RAM_VPOS + 42         ; Player 1 falls
   LD b, 12                     ;
lxpf_pfalling_loop:   
   INC (hl)                     ; Go down
   INC hl                       ; Next sprite
   DEC b                        ;
   JP NZ, lxpf_pfalling_loop    ;
   
   LD de, level_x_jump_frame    ; Falling tiles
   CALL lxmpl_subcopy           ;
   
   LD a, 2                      ; Still falling
   LD (RAM_JUMP_STATE), a       ;   
   JP lxpf_end                  ;
   
lxpf_end2:
   LD a, 0                      ; Ready to jump
   LD (RAM_JUMP_STATE), a       ;
   
lxpf_end:   
   POP AF                       ; Restore registers
   POP HL                       ;
   POP DE                       ;
   POP BC                       ;
   RET                          ; End subroutine  

;----------------------------------
; level_x_player_up
;
level_x_player_up:  
   PUSH BC                      ; Save registers
   PUSH DE                      ;
   PUSH HL                      ;
   PUSH AF                      ; 
   
   LD hl, RAM_VPOS + 42         ; Player 1 jumps
   LD b, 12                     ;
lxpf_prising_loop:   
   DEC (hl)                     ; Go up
   INC hl                       ; Next sprite
   DEC b                        ;
   JP NZ, lxpf_prising_loop     ;

   LD de, level_x_jump_frame    ; Falling tiles
   CALL lxmpl_subcopy           ;   
   
   LD a, (RAM_JUMP_HEIGHT)      ; What is the current state? 
   INC a                        ; Start count up to the maximum
   LD (RAM_JUMP_HEIGHT), a      ;

   CP 7*8                       ; Jump up 3 1/2 blocks maximum
   JP NZ, lxpf_end000           ;
   LD a, 2                      ; Transition state
   LD (RAM_JUMP_STATE), a       ;
   LD a, 0                      ; Reset jump height
   LD (RAM_JUMP_HEIGHT), a      ;
   
lxpf_end000:   
   POP AF                       ; Restore registers
   POP HL                       ;
   POP DE                       ;
   POP BC                       ;
   RET                          ; End subroutine
   
;---------------------------------
; level_x_handle_jumping
;
level_x_handle_jumping:
   PUSH BC                      ; Save registers
   PUSH DE                      ;
   PUSH HL                      ;
   PUSH AF                      ;   

   LD a, (RAM_JUMP_STATE)       ;
   CP 0                         ; on ground?
   JP Z, lxhj_ground            ;
   CP 1                         ; rising to max?
   JP Z, lxhj_rising            ;
   CP 2                         ; falling to ground
   JP Z, lxhj_falling           ;

; Player is on the ground   
lxhj_ground: 
   IN a, (PORT_INPUT1)          ; Press jump?
   BIT 4, a                     ; Go up? 
   JP NZ, lxhj_falling          ; Do not start a jump. Could fall.  
   
   LD a, 1                      ; Transition state
   LD (RAM_JUMP_STATE), a       ;
   CALL sound_jump_sfx          ;
   
   JP lxhj_stay_put             ;

; Player is rising   
lxhj_rising:
   IN a, (PORT_INPUT1)          ; Keep going up if button is pressed
   BIT 4, a                     ; Go up? 
   CALL Z, level_x_player_up    ; Go up 
   
   IN a, (PORT_INPUT1)          ; Keep going up if button is pressed
   BIT 4, a                     ; Go up? 
   JP Z, lxhj_stay_put          ;

   LD a, 2                      ; Transition state
   LD (RAM_JUMP_STATE), a       ;
   LD a, 0                      ; Reset jump height
   LD (RAM_JUMP_HEIGHT), a      ;   
   JP lxhj_stay_put             ;
   
; Player is falling   
lxhj_falling:
   CALL level_x_player_falling  ;
    
lxhj_stay_put:   
   POP AF                       ; Restore registers
   POP HL                       ;
   POP DE                       ;
   POP BC                       ;
   RET                          ; End subroutine  