;-----------------------------------
; level_x.txt
;
; Run a side scrolling level.
; Load background as screen scrolls.
; Avoid two paratroopers.
; Grab eggs.
;
; New levels load different tiles
; before level begins.
;
; level_x_load_column - load a column, needed for any side scrolling game
; level_x_load_screen - load an entire screen, column by column
; level_x_scroll_right - scroll to the right, load a new column every 8 pixels
; level_x_end_level - when does the level end?
; level_x_col_list_set_HL - Load HL with address of column data to write to screen
; level_x1_column_list - only 12 columns are defined. Read level map (column list)
;                        to know which one to load
; level_x_run - run the level
;-----------------------------------


;-----------------------------------
; level_x_load_column
;
; Load a column while the VDP is NOT active.
;
; HL = VDP address
; DE = RAM or ROM address of column 
;
level_x_load_column:
   PUSH BC                     ; Save registers
   PUSH DE                     ;
   PUSH HL                     ;
   PUSH AF                     ;
   
   LD a, 28                    ; Set for 28 loops
   LD (RAM_COUNTER), a         ;   

lxlc_loop:
; Read from VDP control
   IN a, (VDP_ADDR)            ; Clear state
   
; Set VDP address
   LD a, l                     ; Low address byte
   OUT (VDP_ADDR),a            ;
   LD a, h                     ; High address byte
   OUT (VDP_ADDR),a            ; 

; Load 2 bytes
   LD a, (de)                  ; Data
   OUT (VDP_DATA),a            ; 
   INC de                      ;
   LD a, (de)                  ; Data
   OUT (VDP_DATA),a            ; 
   INC de                      ;

; Advance addresses
   LD bc, $0040                ; Add $0040 to address
   ADD hl, bc                  ;

; Repeat 24 times
   LD a, (RAM_COUNTER)         ; Increment
   DEC a                       ;
   LD (RAM_COUNTER), a         ;
   JP NZ, lxlc_loop            ;
  
   POP AF                      ; Restore registers
   POP HL                      ;
   POP DE                      ;
   POP BC                      ;
   RET                         ; End subroutine

;-----------------------------------
; level_x_load_column_VDP
;
; Load a column while the VDP is active.
; Stop VDP. Load. Start VDP.
;
; HL = VDP address
; DE = RAM or ROM address of column 
;
level_x_load_column_VDP:
   PUSH BC                     ; Save registers
   PUSH DE                     ;
   PUSH HL                     ;
   PUSH AF                     ;
   
   LD a, 28                    ; Set for 28 loops
   LD (RAM_COUNTER), a         ;   

   CALL VDP_off                ; Stop the VDP 
   
lxlc_loop2:
; Read from VDP control
   IN a, (VDP_ADDR)            ; Clear state 
   
; Set VDP address
   LD a, l                     ; Low address byte
   OUT (VDP_ADDR),a            ;
   LD a, h                     ; High address byte
   OUT (VDP_ADDR),a            ; 

; Load 2 bytes
   LD a, (de)                  ; Data
   OUT (VDP_DATA),a            ; 
   INC de                      ;
   LD a, (de)                  ; Data
   OUT (VDP_DATA),a            ; 
   INC de                      ;

; Advance addresses
   LD bc, $0040                ; Add $0040 to address
   ADD hl, bc                  ;

; Repeat 24 times
   LD a, (RAM_COUNTER)         ; Increment
   DEC a                       ;
   LD (RAM_COUNTER), a         ;
   JP NZ, lxlc_loop2           ;

   CALL VDP_on                 ; Start the VDP 
   
   POP AF                      ; Restore registers
   POP HL                      ;
   POP DE                      ;
   POP BC                      ;
   RET                         ; End subroutine
   
   
   
;-----------------------------------
; level_x_load_screen
;
level_x_load_screen:
   PUSH BC                     ; Save registers
   PUSH DE                     ;
   PUSH HL                     ;
   PUSH AF                     ;

   CALL VDP_off                ; Screen off

; Initial background load
   LD b, 32                    ; Number of columns
   LD hl, $37FF                ; VRAM BG

lxls_loop_0:
   LD de, lvlx_col_000         ; ROM source
   CALL level_x_load_column    ; Write a column

   INC hl                      ; Write 32 columns
   INC hl                      ;
   DEC b                       ;
   
   LD de, lvlx_col_001         ; ROM source
   CALL level_x_load_column    ; Write a column  

   INC hl                      ; Write 32 columns
   INC hl                      ;
   DEC b                       ;   
   JP NZ, lxls_loop_0          ;

; Load sprites   
   LD hl, level_x_sp_vpos      ; Load vpos
   LD de, RAM_VPOS             ;
   LD b, 59                    ; 21+21+12+4+1
   CALL copy_to_RAM_loop       ;

   LD hl, level_x_sp_hpos      ; Load hpos
   LD de, RAM_HPOS             ;
   LD b, 117                   ; ((21+21+12+4)*2)+1
   CALL copy_to_RAM_loop       ;
   
; Go to next state   
   LD hl, RAM_GAME_STATE       ; Run the game      
   INC (hl)                    ;

   CALL VDP_on                 ; Screen on

   POP AF                      ; Restore registers
   POP HL                      ;
   POP DE                      ;
   POP BC                      ;
   RET                         ; End subroutine



   
;-------------------------------------------------------------------
;-------------------------------------------------------------------
;-------------------------------------------------------------------
; Background scrolling
;-------------------------------------------------------------------
;-------------------------------------------------------------------
;-------------------------------------------------------------------

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

; Scroll the background   
   LD a, (RAM_SCROLL_CTR)      ; Load scroll counter
   DEC a                       ;
   LD (RAM_SCROLL_CTR), a      ; Scroll

   OUT (VDP_ADDR),a            ; 
   LD a,$88                    ; R8 is horizontal scroll
   OUT (VDP_ADDR),a            ;
   
; Load a new column?
   LD a, (RAM_SCROLL_CTR)      ; Load scroll counter  
   AND $07                     ;
   CP $00                      ; Every 8 pixels, load a column.
   JP NZ, lxsr_no_load         ;

   CALL level_x_increment_score ; Score a point!
   
   LD a, (RAM_SCROLL_CTR)      ; Load scroll counter 
   CP $00                      ; Reset column?
   JP NZ, lxsr_no_load1        ;

   LD hl, $37FF                ; Reset address of column to write to
   LD (RAM_COLUMN_ADDR), hl    ; 2 bytes

   LD a, (RAM_DIFFICULTY)      ; Save difficulty for later
   LD b, a                     ;
   LD hl, RAM_PEDOMETER        ; increment pedometer 1 per screen
   INC (hl)                    ;
   LD a, (hl)                  ; Stop level at X screens
   CP b                        ; RAM_DIFFICULTY screens
   CALL Z, level_x_end_level   ;
   
lxsr_no_load1:   
   CALL level_x1_column_list   ; Determine RAM_COLUMN_SOURCE contents
   LD hl, (RAM_COLUMN_ADDR)    ; 2 bytes   
   LD de, (RAM_COLUMN_SOURCE)  ; ROM source
   CALL level_x_load_column_VDP ; Write a column. 
                               ; VDP is turned off during writes, 
							   ; then turned on again.  

   INC hl                      ; Prepare for next column.
   INC hl                      ;   
   LD (RAM_COLUMN_ADDR), hl    ; 2 bytes   

   CALL level_x_update_floor_table ; Update the floor table   
   
lxsr_no_load:   
; Change position   
   LD hl, RAM_HPOS             ; Start of foe HPOS
   LD b, 42                    ; 42 sprites
   
lxmpl_loop_3:   
   DEC (hl)                    ; Go left (appear stationary as screen goes right)
   INC hl                      ; Move address
   INC hl                      ;
   DEC b                       ;
   JP NZ, lxmpl_loop_3         ;

   LD hl, RAM_HPOS + 108       ; Start of egg HPOS
   LD b, 4                     ; 4 sprites
   
lxmpl_loop_4:   
   DEC (hl)                    ; Go left (appear stationary as screen goes right)
   INC hl                      ; Move address
   INC hl                      ;
   DEC b                       ;
   JP NZ, lxmpl_loop_4         ;
   
   POP AF                      ; Restore registers
   POP HL                      ;
   POP DE                      ;
   POP BC                      ;
   RET                         ; End subroutine   

;------------------------
; level_x_end_level
;
level_x_end_level:
   PUSH BC                     ; Save registers
   PUSH DE                     ;
   PUSH HL                     ;
   PUSH AF                     ;
   
   CALL title_load_menu00      ; Reset sprites

   LD a, 0                     ; Reset scroll
   LD (RAM_SCROLL_CTR), a      ; Scroll
   LD (RAM_COLUMN_INDEX), a    ;

   LD hl, $3801                ; Address of column to write to
   LD (RAM_COLUMN_ADDR), hl    ; 2 bytes
   LD a, 20*8                  ; Initial floor table value
   LD b, 32                    ;
   LD hl, RAM_FLOOR_TABLE      ;    
   
initft_001:
   LD (hl), a                  ; Initialize floor table
   INC hl                      ;
   DEC b                       ;
   JP NZ, initft_001           ;
   LD a, 5                     ; Initial player column (0-31)
   LD (RAM_PLAYER_X_COLUMN), a ; Player X-coordinate (sprite 53)    
   
   LD a, (RAM_LEVEL_B)         ; Go to next sub level
   INC a                       ;
   LD (RAM_LEVEL_B), a         ;

   LD a, 0                     ; Reset pedometer
   LD (RAM_PEDOMETER), a       ;
   
   LD a, 3                     ; Display score
   LD (RAM_GAME_STATE), a      ;
   
   POP AF                      ; Restore registers
   POP HL                      ;
   POP DE                      ;
   POP BC                      ;
   RET                         ; End subroutine  

;--------------------------------------
; level_x_col_list_set_HL
; 
; Base address is left in HL.
;
level_x_col_list_set_HL: 
   PUSH AF                     ; Save registers
   
   LD a, (RAM_LEVEL_A)         ;
   CP 1                        ;
   JP Z, lx1cl_level_1a        ;
   CP 2                        ;
   JP Z, lx1cl_level_2a        ;   
   CP 3                        ;
   JP Z, lx1cl_level_3a        ;
   CP 3                        ;
   JP Z, lx1cl_level_4a        ;

lx1cl_level_1a:   
   LD a, (RAM_LEVEL_B)         ;
   CP 1                        ;
   JP Z, lx1cl_level_1         ;
   CP 2                        ;
   JP Z, lx1cl_level_2         ;   
   CP 3                        ;
   JP Z, lx1cl_level_3         ;   
   
lx1cl_level_2a:   
   LD a, (RAM_LEVEL_B)         ;
   CP 1                        ;
   JP Z, lx1cl_level_4         ;
   CP 2                        ;
   JP Z, lx1cl_level_5         ;   
   CP 3                        ;
   JP Z, lx1cl_level_6         ;   
   
lx1cl_level_3a:   
   LD a, (RAM_LEVEL_B)         ;
   CP 1                        ;
   JP Z, lx1cl_level_2         ;
   CP 2                        ;
   JP Z, lx1cl_level_3         ;   
   CP 3                        ;
   JP Z, lx1cl_level_5         ;  

lx1cl_level_4a:   
   LD a, (RAM_LEVEL_B)         ;
   CP 1                        ;
   JP Z, lx1cl_level_6         ;
   CP 2                        ;
   JP Z, lx1cl_level_4         ;   
   CP 3                        ;
   JP Z, lx1cl_level_1         ;     

lx1cl_level_1:   
   LD hl, level_1_column_list  ; Point to column list
   JP lx1cl_HL_end             ;
lx1cl_level_2:
   LD hl, level_2_column_list  ; Point to column list
   JP lx1cl_HL_end             ;
lx1cl_level_3:
   LD hl, level_3_column_list  ; Point to column list
   JP lx1cl_HL_end             ;
lx1cl_level_4:
   LD hl, level_4_column_list  ; Point to column list
   JP lx1cl_HL_end             ;
lx1cl_level_5:
   LD hl, level_5_column_list  ; Point to column list
   JP lx1cl_HL_end             ;   
lx1cl_level_6:   
   LD hl, level_6_column_list  ; Point to column list
   
lx1cl_HL_end:   
   POP AF                      ; Restore registers   
   RET                         ; End subroutine 
   
;-------------------------------
; level_x1_column_list
;     
; Leave column address in 
; RAM_COLUMN_SOURCE
level_x1_column_list:
   PUSH BC                     ; Save registers
   PUSH DE                     ;
   PUSH HL                     ;
   PUSH AF                     ;

   CALL level_x_col_list_set_HL ; Select column list
   
lx1cl_level_selected:   
   LD de, (RAM_COLUMN_INDEX)   ; Get index within list
   ADD hl, de                  ; 
   
   LD a, (hl)                  ; Load offset
   CP 0                        ;
   JP Z, lx1cl_jump_000        ;
   CP 1                        ;
   JP Z, lx1cl_jump_001        ;
   CP 2                        ;
   JP Z, lx1cl_jump_002        ;
   CP 3                        ;
   JP Z, lx1cl_jump_003        ;
   CP 4                        ;
   JP Z, lx1cl_jump_004        ;
   CP 5                        ;
   JP Z, lx1cl_jump_005        ;
   CP 6                        ;
   JP Z, lx1cl_jump_006        ;
   CP 7                        ;
   JP Z, lx1cl_jump_007        ;
   CP 8                        ;
   JP Z, lx1cl_jump_008        ;
   CP 9                        ;
   JP Z, lx1cl_jump_009        ;
   CP 10                       ;
   JP Z, lx1cl_jump_010        ;
   CP 11                       ;
   JP Z, lx1cl_jump_011        ;
   
lx1cl_jump_000:   
   LD hl, lvlx_col_000         ; Base address
   LD (RAM_COLUMN_SOURCE), hl  ; Copy to location for use after routine
   JP lx1cl_jump_end           ;
lx1cl_jump_001:   
   LD hl, lvlx_col_001         ; Base address
   LD (RAM_COLUMN_SOURCE), hl  ; Copy to location for use after routine
   JP lx1cl_jump_end           ;
lx1cl_jump_002:   
   LD hl, lvlx_col_002         ; Base address
   LD (RAM_COLUMN_SOURCE), hl  ; Copy to location for use after routine
   JP lx1cl_jump_end           ;
lx1cl_jump_003:   
   LD hl, lvlx_col_003         ; Base address
   LD (RAM_COLUMN_SOURCE), hl  ; Copy to location for use after routine
   JP lx1cl_jump_end           ;   
lx1cl_jump_004:   
   LD hl, lvlx_col_004         ; Base address
   LD (RAM_COLUMN_SOURCE), hl  ; Copy to location for use after routine
   JP lx1cl_jump_end           ;
lx1cl_jump_005:   
   LD hl, lvlx_col_005         ; Base address
   LD (RAM_COLUMN_SOURCE), hl  ; Copy to location for use after routine
   JP lx1cl_jump_end           ;
lx1cl_jump_006:   
   LD hl, lvlx_col_006         ; Base address
   LD (RAM_COLUMN_SOURCE), hl  ; Copy to location for use after routine
   JP lx1cl_jump_end           ;
lx1cl_jump_007:   
   LD hl, lvlx_col_007         ; Base address
   LD (RAM_COLUMN_SOURCE), hl  ; Copy to location for use after routine
   JP lx1cl_jump_end           ; 
lx1cl_jump_008:   
   LD hl, lvlx_col_008         ; Base address
   LD (RAM_COLUMN_SOURCE), hl  ; Copy to location for use after routine
   JP lx1cl_jump_end           ;
lx1cl_jump_009:   
   LD hl, lvlx_col_009         ; Base address
   LD (RAM_COLUMN_SOURCE), hl  ; Copy to location for use after routine
   JP lx1cl_jump_end           ;
lx1cl_jump_010:   
   LD hl, lvlx_col_010         ; Base address
   LD (RAM_COLUMN_SOURCE), hl  ; Copy to location for use after routine
   JP lx1cl_jump_end           ;
lx1cl_jump_011:   
   LD hl, lvlx_col_011         ; Base address
   LD (RAM_COLUMN_SOURCE), hl  ; Copy to location for use after routine
   
lx1cl_jump_end:
   LD a, (RAM_COLUMN_INDEX)    ; Increment for next run
   INC a                       ;
   LD (RAM_COLUMN_INDEX), a    ;
   
   POP AF                      ; Restore registers
   POP HL                      ;
   POP DE                      ;
   POP BC                      ;
   RET                         ; End subroutine   

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

   LD a, (RAM_PAUSE)           ; even=run, odd=paused
   AND $01                     ;
   JP NZ, lxrun_paused         ;

; Move the player   
   CALL level_x_move_player    ;  VDP writes may occur. Do this first.
   
; Move GP down. 
   CALL level_x_move_foes      ;

; Move the bonus item   
   CALL level_x_move_bonus_points ;
   
; Collision with bonus item   
   CALL level_x_hit_a_bonus    ;

; Collision with foe or floor
   CALL level_x_detect_loss_of_life ;   

lxrun_paused:   
   POP AF                      ; Restore registers
   POP HL                      ;
   POP DE                      ;
   POP BC                      ;
   RET                         ; End subroutine

   
; Player movement   
.include "level_x_player.txt"
   
; Foe movement and bonus items
.include "level_x_foe_bonus.txt"

; Handle scoring
.include "level_x_scoring.txt"

; Handle game over
.include "level_x_game_over.txt"  

   