;
; bread_and_butter_world.txt
;
; V. Crisafulli 
; 01/18/2015 - Begin code for title screen and level 1. 
; 01/25/2015 - Complete intro.
; 01/26/2015 - Added scrolling title screen.
; 01/27/2015 - Added lives, score, level display.
; 01/30/2015 - Column load works.
; 02/05/2015 - Player moves, foes move, bonus item moves
; 02/07/2015 - Level 1-1, 1-2, 1-3 complete; reset; pause
; 02/08/2015 - Different items per level
; 02/16/2015 - Level 1-4 complete; mid ending; final ending
; 02/17/2015 - Sound loop works 
; 02/21/2015 - Add comments; sound effects only version
; 02/22/2015 - DRAFT 001
; 02/23/2015 - Fix hardware artefacts while scrolling
;
;=============================================================
; Files
;
; bread_and_butter_world.txt - This contains h_blank, v_blank routines, 
;                              and utility routines - re-used code common between all games I write.
; intro.txt - Load and run the introduction.
; title_screen.txt - Load and run the title screen.
; score_and_lives.txt - Load and display score and remaining lives between levels.
; sprites_and_bg.txt - This contains tile maps and sprite maps.
; sound.txt - This contains code and data for sound. 
;             (It sucks right now, hopefully it can be replaced).
; level_x.txt - Load background data and run level x.
;               These are the horizontally scrolling stages. 
; level_x_player.txt - Move the player right, left, jump, fall and run. 
;                      This is probably the most complex part of the game.
; level_x_foe_bonus.txt - Move foes, move bonus items.
; level_x_scoring.txt - Handle the score.
; level_x_game_over.txt - Detect game over condition and react.
; level_y.txt - Handle loading and running of level y.
;               These are vertically scrolling stages.
; level_y_player.txt - Handle player movement for vertically scrolling stage.
; ending.txt - Handle the intermediate and final ending.
; bnbw_3x4GPs (tiles).inc - tile data
; bnbw_3x4GPsII (tiles).inc - tile data
; bnbw_3x4GPsIII (tiles).inc - tile data
; bnbw_text (tiles).inc - tile data
; bnbw_3x4bread (tiles).inc - tile data
; bnbw_3x4butter (tiles).inc - tile data
; bnbw_lv1_bg (tiles).inc - tile data
; bnbw_title_screen (tiles).inc - tile data
; bnbw_2x2chickensandeggs (tiles).inc - tile data
; bnbw_2x2milk (tiles).txt - tile data
; bnbw_2x2wheat (tiles).inc - tile data
; bnbw_2x2blocks (tiles).inc - tile data
; breadoflegend (tiles).inc - tile data
; GPMainComputer (tiles).inc - tile data
; GPMainComputer2 (tiles).inc - tile data
; 
;=============================================================
;
; Bread and Butter World
;
; Overview: Level X-1 - collect eggs, avoid blue game police, horizontal scroll
;           Level X-2 - collect milk, avoid red game police, horizontal scroll
;           Level X-3 - collect wheat, avoid green game police, horizontal scroll 
;           Level X-4 - leap to top of game police headquarters 
;                       to release bread of legend to 
;                       destroy main computer, vertical scroll
;           Complete 1-1 to 4-4 to see the final ending.
;
; State Machine
; 0 - run introduction
; 1 - load title screen
; 2 - run title screen
; 3 - load score and lives screen
; 4 - run score and lives screen
; 5 - load a horizontal level
; 6 - run a horizontal level
; 7 - death animation, then goto 3
; 8 - load a vertically scrolling level
; 9 - run a vertically scrolling level
; 10 - load intermediate ending part 1
; 11 - run intermediate ending part 2
; 12 - run intermediate ending part 3
; 13 - load intermediate ending part 4
; 14 - run intermediate ending part 5
; 15 - load final ending
; 16 - run final ending 
;
;
; Page 0: Interrupts
;         Utility Routines
;         All code but sound
;         Sprite and background maps
;
; Page 1: Tile Data
;
; Page 2: Tile Data (ending only)
;         Sound
;         
;
;=============================================================
;

.sdsctag 1.01, "Bread and Butter World", "Version 1.00", "VAC2015"

;---------------------------------------
; Constants 
;---------------------------------------
; This file defines constants used in the program.
; MEMORY --------------------------------------------------------------------
.DEFINE         PAGE_SIZE               $4000
.DEFINE         PAGE_0                  $0000
.DEFINE         PAGE_1                  (PAGE_0 + PAGE_SIZE)
.DEFINE         PAGE_2                  (PAGE_1 + PAGE_SIZE)
.DEFINE         PAGE_3                  (PAGE_2 + PAGE_SIZE)
.DEFINE         RAM                     $C000
.DEFINE         RAM_LEN                 $1FF8
.DEFINE         RAM_MIRROR              $E000
.DEFINE         REG_MAP_SRAM            $FFFC
.DEFINE         REG_MAP_0               $FFFD
.DEFINE         REG_MAP_1               $FFFE
.DEFINE         REG_MAP_2               $FFFF
;----------------------------------------------------------------------------

; VIDEO ---------------------------------------------------------------------
.DEFINE         VDP_DATA                $BE
.DEFINE         VDP_ADDR                $BF
.DEFINE         VDP_STATUS              $BF
.DEFINE         VRAM_TILES              $0000
.DEFINE         VRAM_BG_MAP             $3800
.DEFINE         VRAM_SPR_MAP            $3F00
.DEFINE         VRAM_SPR_LAST           208
;----------------------------------------------------------------------------
.DEFINE         VRAM_SIZE               $4000
.DEFINE         VRAM_TILE_SIZE          32            ; (8 * 8) * 4 bits = 32 bytes
;----------------------------------------------------------------------------
.DEFINE         VREG_CONFIG0            $80
.DEFINE         VREG_CONFIG1            $81
; ..
.DEFINE         VREG_BORDER_COL         $87
.DEFINE         VREG_HSCROLL            $88
.DEFINE         VREG_VSCROLL            $89
.DEFINE         VREG_LINES_CNT          $8A
;----------------------------------------------------------------------------

; INPUTS --------------------------------------------------------------------
.DEFINE         PORT_INPUT1             $DC
.DEFINE         P1_UP                   $01
.DEFINE         P1_DOWN                 $02
.DEFINE         P1_LEFT                 $04
.DEFINE         P1_RIGHT                $08
.DEFINE         P1_BUTTON1              $10
.DEFINE         P1_BUTTON2              $20
.DEFINE         P2_UP                   $40
.DEFINE         P2_DOWN                 $80
;----------------------------------------------------------------------------
.DEFINE         PORT_INPUT2             $DD
.DEFINE         P2_LEFT                 $01
.DEFINE         P2_RIGHT                $02
.DEFINE         P2_BUTTON1              $04
.DEFINE         P2_BUTTON2              $08
.DEFINE         RESET_BUTTON            $10
; Unused                                $20
.DEFINE         LIGHTGUN1               $40
.DEFINE         LIGHTGUN2               $80
;----------------------------------------------------------------------------
.DEFINE         PORT_INPUTGG            $00
.DEFINE         START_BUTTON            $80
;----------------------------------------------------------------------------

; SOUND ---------------------------------------------------------------------
.DEFINE         PORT_PSG                $7F
.DEFINE         PORT_FM_ADDR            $F0
.DEFINE         PORT_FM_DATA            $F1
.DEFINE         PORT_FM_LATCH           $F2
;----------------------------------------------------------------------------

; MISCELLANEOUS -------------------------------------------------------------
.DEFINE         PORT_NATION             $3F
.DEFINE         PORT_VLINE              $7E
.DEFINE         PORT_HLINE              $7F
;----------------------------------------------------------------------------

; HEADER --------------------------------------------------------------------
.DEFINE         HEADER                  $7FF0
.DEFINE         HEADER_ID               $7FF0 ; TMR SEGA
; ..
.DEFINE         HEADER_CHECKSUM         $7FFA
; ..
.DEFINE         HEADER_SYS_SIZE         $7FFF
;----------------------------------------------------------------------------

;----------------------------------------------------------------------------
; WORKING RAM
; 
.DEFINE         RAM_FRAME_CTR               $C000 ; Frame counter
.DEFINE         RAM_SECOND_CTR              $C001 ; Second counter
.DEFINE         RAM_GAME_STATE              $C002 ; Game state

.DEFINE         RAM_CONTROLLER_1_PREV       $C003 ; Controller 1 previous
.DEFINE         RAM_CONTROLLER_2_PREV       $C004 ; Controller 1 previous

.DEFINE         RAM_MENU_STATE              $C005 ; Menu state
.DEFINE         RAM_SCROLL_CTR              $C006 ; Horizontal or vertical scroll counter
.DEFINE         RAM_LEVEL_A                 $C007 ; Level, major
.DEFINE         RAM_LEVEL_B                 $C008 ; Level, minor
.DEFINE         RAM_SCORE_4                 $C009 ; Score, MSD
.DEFINE         RAM_SCORE_3                 $C00A ; Score 
.DEFINE         RAM_SCORE_2                 $C00B ; Score 
.DEFINE         RAM_SCORE_1                 $C00C ; Score 
.DEFINE         RAM_SCORE_0                 $C00D ; Score, LSD 
.DEFINE         RAM_LIVES                   $C00E ; Number of lives
.DEFINE         RAM_COUNTER                 $C00F ; Loop counter

.DEFINE         RAM_COLUMN_ADDR             $C010 ; Address of current column, VRAM target (2 byte)
.DEFINE         RAM_COLUMN_SOURCE           $C012 ; Address of current column, ROM source (2 byte)
.DEFINE         RAM_COLUMN_INDEX            $C014 ; Index to column list
.DEFINE         RAM_TOP_SCORE_4             $C016 ;
.DEFINE         RAM_TOP_SCORE_3             $C017 ;
.DEFINE         RAM_TOP_SCORE_2             $C018 ;
.DEFINE         RAM_TOP_SCORE_1             $C019 ;
.DEFINE         RAM_TOP_SCORE_0             $C01A ; 
.DEFINE         RAM_PLAYER_X_COLUMN         $C01B ; Column (0-31) of player 1
.DEFINE         RAM_JUMP_STATE              $C01C ; Jump state: ready -> rising -> wait for ground
.DEFINE         RAM_JUMP_HEIGHT             $C01D ; Height of jump
.DEFINE         RAM_PEDOMETER               $C01E ; How many screens has player walked?
.DEFINE         RAM_SHOCK_CTR               $C01F ; Display shock
.DEFINE         RAM_FOE_STATE_1             $C020 ; Memory for foe logic
.DEFINE         RAM_FOE_STATE_2             $C021 ; Memory for foe logic
.DEFINE         RAM_DIFFICULTY              $C022 ; Difficulty = # of screens per level

.DEFINE         RAM_COLL_X1                 $C030 ; = x1
.DEFINE         RAM_COLL_Y1                 $C031 ; = y1
.DEFINE         RAM_COLL_X2                 $C032 ; = x1
.DEFINE         RAM_COLL_Y2                 $C033 ; = y1
.DEFINE         RAM_COLL_RESULT             $C034 ; = result, $00 => miss, $01 => hit

.DEFINE         RAM_PAUSE                   $C036 ; Paused? even=>no pause, odd=>paused

.DEFINE         RAM_SOUND_STATE             $C400 ; Sound state
.DEFINE         RAM_SOUND_SONG              $C402 ; Which song?
.DEFINE         RAM_SOUND_INDEX             $C404 ; Volume list within note? 
.DEFINE         RAM_SOUND_STATE2            $C406 ; Sound state
.DEFINE         RAM_SOUND_SONG2             $C408 ; Which song?
.DEFINE         RAM_SOUND_INDEX2            $C40A ; Volume list within note? 
.DEFINE         RAM_SOUND_STATE3            $C40C ; Sound state
.DEFINE         RAM_SOUND_SONG3             $C40E ; Which song?
.DEFINE         RAM_SOUND_INDEX3            $C410 ; Volume list within note? 

.DEFINE         RAM_VPOS                    $C100 ; Sprite data, vertical position
.DEFINE         RAM_HPOS                    $C200 ; Sprite data, horizontal position
.DEFINE         RAM_FLOOR_TABLE             $C300 ; Floor data

;----------------------------------------------------------------------------
; CONSTANTS
.DEFINE         STATE_INTRO                 0     ; Title Screen
.DEFINE         SCREENS_PER_LEVEL          16     ; 

;------------------------------------------
; Assembler Defines
;------------------------------------------
.EMPTYFILL $00


; $0000 - $3FFF = bank 0
; $4000 - $7FFF = bank 1
; $8000 - $BFFF = bank 2 (not mapped for 32kb)
; $C000 - $FFFF = bank 3 (working RAM, not mapped)
.MEMORYMAP
   SLOTSIZE $4000
   SLOT 0 START $0000 
   SLOT 1 START $4000 
   SLOT 2 START $8000 
   DEFAULTSLOT 0
.ENDME

; 48kb Game
.ROMBANKMAP
   BANKSTOTAL 3
   BANKSIZE $4000
   BANKS 3
.ENDRO


;----------------------------------------
; Vectors at $0000
.BANK 0 SLOT 0
.org $0000

;----------------------------------------
; Power up vector
.org $0000
   JP start_sms                ; Jump to start of program

;---------------------------------------
; H blank/ V blank
.org $0038
   IN a,(VDP_STATUS)           ; Acknowledge the IRQ
   CALL h_blank                ; v_blank routine (no raster line interrupts)
   EI                          ; Enable interrupts
   RETN                        ; End interrupt

;---------------------------------------
; Pause interrupt vector 
.org $0066
   CALL pause_routine          ; Jump to pause routine
   RETN                        ; End interrupt


;---------------------------------------
; The program starts here.
start_sms:
   DI                          ; Disable interrupts
   IM 1                        ; Set SMS interrupt mode
   LD sp,$dff0                 ; Set the stack pointer

; Initialize registers
   LD c,VDP_ADDR               ; Set c <- VDP_ADDR
   LD b,$80                    ; VDP Register
   LD hl, vdp_init_data        ; Set initialization data.
  
vdp_init_loop:
   LD a,(hl)                   ; Load data
   OUT (c), a                  ; Write to VDP
   LD a, b                     ; Load register number
   OUT (c), a                  ;

   INC hl                      ; Increment data pointer
   INC a                       ; Increment B
   LD b, a                     ;
   CP $8B                      ; Stop before 11
   JP NZ, vdp_init_loop        ; Loop

; 0 = enable, ON
; 1 = disable, OFF
; 7654 3210
; +----------- Expansion slot OFF
;  +---------- Cart slot      ON
;   +--------- Card slot      OFF
;    +-------- Work RAM       ON
;      +------ BIOS ROM       OFF
;       +----- I/O Chip       ON
;        +---- Unknown        ON
;         +--- Unknown        ON
;
; BIOS ROM leaves this data in $C000
; But Genesis does not have BIOS ROM so don't rely on it.
; $A8 is the default for SMS carts.
;
   LD a, $A8                   ; Set memory enables
   OUT ($3E), a                ;

; Set up the title screen.
; Clear RAM! SMS BIOS clears RAM, but Genesis does not.
   LD hl, $C000                ;
   LD b, 255                   ;
   CALL tool_clear_RAM_loop    ; Clear working RAM
   CALL clear_vram             ; Clear VRAM
   CALL clear_palette_data     ; Clear palette data

; Load the introduction.
   LD a, 1                     ; Set level
   LD (RAM_LEVEL_A), a         ;
   LD (RAM_LEVEL_B), a         ;
   LD a, 16                    ; Set difficulty
   LD (RAM_DIFFICULTY), a      ;

   CALL intro_load_tiles       ; Load tiles
   CALL intro_load_background  ; Load background
   CALL intro_load_palette     ; Load colors
   CALL intro_load_sprites     ; Load sprites
   CALL reset_scroll           ;

   CALL sound_start_song_1     ; 
   
   LD a, 0                     ; Reset game state
   LD (RAM_GAME_STATE), a      ;

; Turn on the screen
   CALL VDP_on                 ; Screen on

   EI                          ; Enable interrupts

main_loop:
   NOP
   NOP
   NOP
   JP main_loop

; VDP Register initialization data.
; This is kinda important.
vdp_init_data:
 .db $76 $00 $FF $FF $FF $FF $FB $00 $00 $00 $0F

;---------------------------------------
; reset_check 
;
; Reset button pressed?
;---------------------------------------
reset_check:
   IN a, ($DD)                 ; Reset active?
   AND $10                     ;
   CP $00                      ;
   JP NZ, reset_check_end      ;

   CALL VDP_off                ; Screen off

   LD hl, $C000                ;
   LD b, 255                   ;
   CALL tool_clear_RAM_loop    ; Clear working RAM
   CALL clear_vram             ; Clear VRAM
   CALL clear_palette_data     ; Clear palette data
   
; Load the introduction.
   CALL intro_load_tiles       ; Load tiles
   CALL intro_load_background  ; Load background
   CALL intro_load_palette     ; Load colors
   CALL intro_load_sprites     ; Load sprites
   CALL reset_scroll           ;

   CALL sound_start_song_1     ;  

   ; Set level and difficulty   
   LD a, 1                     ; Set level
   LD (RAM_LEVEL_A), a         ;
   LD (RAM_LEVEL_B), a         ;
   LD a, 16                    ; Set difficulty
   LD (RAM_DIFFICULTY), a      ;
   
   LD a, 0                     ; Reset game state
   LD (RAM_GAME_STATE), a      ;

   CALL VDP_on                 ; Screen on

reset_check_end:
   RET                         ; End subroutine
;---------------------------------------

;----------------------------------------------------------
; sound_off
;
; Turn the sound off
;----------------------------------------------------------
sound_off:
   LD a, $9F                   ; PSG1 off
   OUT (PORT_PSG), a           ;

   LD a, $BF                   ; PSG2 off
   OUT (PORT_PSG), a           ;

   LD a, $DF                   ; PSG3 off
   OUT (PORT_PSG), a           ;

   LD a, $FF                   ; Noise off
   OUT (PORT_PSG), a           ;
   
   RET                         ; End subroutine
;---------------------------------------


;----------------------------------------------------------
; VDP_off (6 lines)
;
; Turn the screen off
;----------------------------------------------------------
VDP_off:
   PUSH AF                     ;
   
   LD a,$80                    ; Set VDP 1 <- $80
   OUT (VDP_ADDR),a            ; IE  = 0
   LD a,$81                    ;
   OUT (VDP_ADDR),a            ;

   POP AF                      ;
   RET                         ;
;---------------------------------------

;----------------------------------------------------------
; VDP_no_int (6 lines)
;
; Screen on, no interrupt
;----------------------------------------------------------
VDP_no_init:
   PUSH AF                     ;
   
   LD a,$C0                    ; Set VDP 1 <- $C0
   OUT (VDP_ADDR),a            ; IE  = 0
   LD a,$81                    ;
   OUT (VDP_ADDR),a            ;

   POP AF                      ;
   RET                         ;
;---------------------------------------

;----------------------------------------------------------
; VDP_on (6 lines)
;
; Turn the screen on
;
; NOTE: Interrupt occurs almost as 
;       soon as you write to register 1.
;----------------------------------------------------------
VDP_on:
   PUSH AF                     ;
   
; Turn on the screen
   LD a, $E0                   ; Set VDP 1 <- $E0
   OUT (VDP_ADDR), a           ; IE  = 1  
   LD a, $81                   ; 
   OUT (VDP_ADDR), a           ; 
   
   POP AF                      ;
   RET                         ;
;---------------------------------------

;------------------------------------------
; h_blank 
;
; This interrupt occurs each horizontal line drawn.
; On line 191, vertical blank interrupt.
;
; v_blank - Most of game takes place here
;------------------------------------------
h_blank:
   PUSH AF                        ;
   
   IN a, (PORT_VLINE)             ; Read current scanline
   CP 191                         ; Only perform vblank on last scanline
   CALL Z, v_blank                ; Perform v_blank operations
   
   LD a, (RAM_GAME_STATE)         ; Game state
   CP 2                           ;    
   CALL Z, title_segmented_scroll ; Segmented scrolling for title screen
   
h_blank_end:
   POP AF                         ;
   RET                            ; End subroutine


;---------------------------------------
; v_blank 
;
; Vertical blank interrupt
; 
; *** This routine implements the state machine!   ***
; *** This is the central part of the of the game! ***
;
v_blank:
   PUSH AF                    ; Save register 
   PUSH BC                    ;
;*****************************************
; Copy sprites from RAM to VRAM
   CALL sprites_to_VRAM       ; Copy the sprite data
;*****************************************    
   
;*****************************************
; Handle the frame counter
   LD a, (RAM_FRAME_CTR)      ;
   INC a                      ; Handle the frame counter
   LD (RAM_FRAME_CTR), a      ;
   CP 60                      ;
   JP NZ,vb_skipfc            ;

   LD a, 0                    ; Reset every 60 frames
   LD (RAM_FRAME_CTR), a      ; 60 frames = 1 second
   
   LD a, (RAM_SECOND_CTR)     ; Increment seconds
   INC a                      ;
   LD (RAM_SECOND_CTR), a     ;
;*****************************************

vb_skipfc:
;*****************************************
; Handle the state machine  
   LD a, (RAM_GAME_STATE)       ; Game state
   CP 0                         ; 
   CALL Z, intro_run            ; Run the introduction
   LD a, (RAM_GAME_STATE)       ; Game state
   CP 1                         ; 
   CALL Z, title_screen_load    ; Load title screen
   LD a, (RAM_GAME_STATE)       ; Game state
   CP 2                         ; 
   CALL Z, tile_run_menu        ; Run title screen
   LD a, (RAM_GAME_STATE)       ; Game state
   CP 3                         ; 
   CALL Z, score_and_lives_load ; Load score and lives
   LD a, (RAM_GAME_STATE)       ; Game state
   CP 4                         ; 
   CALL Z, score_and_lives_run  ; Run score and lives
   LD a, (RAM_GAME_STATE)       ; Game state
   CP 5                         ; 
   CALL Z, level_x_load_screen  ; Load horizontal level
   LD a, (RAM_GAME_STATE)       ; Game state
   CP 6                         ; 
   CALL Z, level_x_run          ; Run the level
   LD a, (RAM_GAME_STATE)       ; Game state
   CP 7                         ; 
   CALL Z, level_x_ouch         ; Player lost a life
   LD a, (RAM_GAME_STATE)       ; Game state
   CP 8                         ; 
   CALL Z, level_y_load_bg      ; Load vertical level   
   LD a, (RAM_GAME_STATE)       ; Game state
   CP 9                         ; 
   CALL Z,level_y_run           ; Run vertical level
;*****************************************   
   LD a, (RAM_GAME_STATE)       ; Game state
   CP 10                        ; 
   CALL Z,ending_load_001       ; Load intermediate ending part 1 
   LD a, (RAM_GAME_STATE)       ; Game state
   CP 11                        ; 
   CALL Z,ending_run_002        ; Run intermediate ending part 2
   LD a, (RAM_GAME_STATE)       ; Game state
   CP 12                        ; 
   CALL Z,ending_run_003        ; Run intermediate ending part 3  
   LD a, (RAM_GAME_STATE)       ; Game state
   CP 13                        ; 
   CALL Z,ending_load_004       ; Load intermediate ending part 4     
   LD a, (RAM_GAME_STATE)       ; Game state
   CP 14                        ; 
   CALL Z,ending_run_005        ; Run intermediate ending part 5  
   LD a, (RAM_GAME_STATE)       ; Game state
   CP 15                        ; 
   CALL Z,ending_load_006       ; Load final ending 
   LD a, (RAM_GAME_STATE)       ; Game state
   CP 16                        ; 
   CALL Z, ending_run_007       ; Run final ending. No exit but reset.
;*****************************************

;*****************************************
; Store previous controller values
   IN a, (PORT_INPUT1)           ;
   LD (RAM_CONTROLLER_1_PREV), a ;
   IN a, (PORT_INPUT2)           ;
   LD (RAM_CONTROLLER_2_PREV), a ;
;*****************************************

;*****************************************
   CALL sound_state_machine_piano   ; sound, channel 1
   CALL sound_state_machine_piano2  ; sound, channel 2
   CALL sound_state_machine_guitar3 ; sound, channel 3 
;*****************************************
   
   CALL reset_check           ; Reset button pressed?
   
   POP BC                     ; Restore register
   POP AF                     ; 
   RET                        ; End subroutine

;---------------------------------------
; pause_routine 
;
; Value in RAM determines 
; if game is paused.
; If odd, pause the game
; If even, unpause the game
;---------------------------------------
pause_routine:
   LD a, (RAM_PAUSE)          ; Load
   INC a                      ; Increment
   LD (RAM_PAUSE), a          ; Store

   RET                        ; End subroutine
;---------------------------------------

;----------------------------------------
; Utility Routines
;----------------------------------------

;----------------------------------------
; reset_scroll 
; 
;----------------------------------------
reset_scroll:
   LD a, $00                  ; No scroll
   OUT (VDP_ADDR),a           ; 
   LD a,$88                   ; R8 is horizontal scroll
   OUT (VDP_ADDR),a           ;

   LD a, $00                  ; No scroll
   OUT (VDP_ADDR),a           ; 
   LD a,$89                   ; R9 is vertical scroll
   OUT (VDP_ADDR),a           ;
   
   RET                        ; End subroutine
;----------------------------------------

;----------------------------------------
; vertical_scroll 
; 
;----------------------------------------
vertical_scroll:
   LD a, (RAM_SCROLL_CTR)     ; Load scroll
   OUT (VDP_ADDR),a           ; 
   LD a,$89                   ; R9 is horizontal scroll
   OUT (VDP_ADDR),a           ;
   
   RET                        ; End subroutine
;----------------------------------------

;-----------------------------------------------------
; tool_clear_RAM_loop
;
; Set hl before calling this routine
; Set b before calling this routine
;-----------------------------------------------------
tool_clear_RAM_loop:
   LD a, $00                   ; Clear register
   LD (hl), a                  ; Clear
   INC hl                      ;
   DEC b                       ;
   CP b                        ; a - b
   JP NZ, tool_clear_RAM_loop  ;

   RET                         ; End subroutine 
;---------------------------------------

;----------------------------------------------------------
; clear_vram 
;
; Set all of VRAM to $00
;----------------------------------------------------------
clear_vram:
; Clear VDP RAM
   LD a, $00                   ; Low address byte
   OUT (VDP_ADDR),a            ;
   LD a, $40                   ; High address byte
   OUT (VDP_ADDR),a            ;

   LD de, $4000                ; Set up counter
   
clear_vram_loop:
   LD a, $00                   ; Write $00 to all items
   OUT (VDP_DATA), a           ;
   DEC de                      ; Decrement counter
   LD a, d                     ; A <- D
   OR e                        ; A OR E
   JP NZ, clear_vram_loop      ; Loop until de is empty.

   RET                         ; End subroutine  
;---------------------------------------

;----------------------------------------------------------
; clear_vram_bg_only 
;
; Set background VRAM to $00
;----------------------------------------------------------
clear_vram_bg_only:
; Clear VDP RAM
   LD a, $FF                   ; Low address byte
   OUT (VDP_ADDR),a            ;
   LD a, $37                   ; High address byte
   OUT (VDP_ADDR),a            ;

   LD de, 24*64                ; Set up counter
   
clear_vram_loop0:
   LD a, $00                   ; Write $00 to all items
   OUT (VDP_DATA), a           ;
   DEC de                      ; Decrement counter
   LD a, d                     ; A <- D
   OR e                        ; A OR E
   JP NZ, clear_vram_loop0     ; Loop until de is empty.

   RET                         ; End subroutine  
;---------------------------------------

;----------------------------------------------------------
; clear_palette_data
;
; Clear palette data to $C000.
;----------------------------------------------------------
clear_palette_data:
   LD a, $00                   ; Low address byte
   OUT (VDP_ADDR),a            ;
   LD a, $C0                   ; High address byte
   OUT (VDP_ADDR),a            ;

   LD b, 32                    ; 32 bytes for color

cpd32_loop:
   LD a, $00                   ; Copy $00 to VDP
   OUT (VDP_DATA), a           ;
   DEC b                       ; Decrement counter
   LD a, b                     ; a <- b 
   CP $00                      ; is b zero?
   JP NZ, cpd32_loop           ; If not zero jump

   RET                         ; End subroutine  
;---------------------------------------

;-----------------------------------------
; intro_no_sprites
;
; Load sprites for this screen.
;-----------------------------------------
intro_no_sprites:
   LD a, $D0                   ; Copy sprite data to RAM
   LD (RAM_VPOS), a            ; vpos
   LD (RAM_HPOS), a            ; Hpos

;---------------------------------------
sprites_to_VRAM:
   NOP                         ; Let VRAM rest
   NOP                         ; Let VRAM rest

   LD a, $FF                   ; Low address byte
   OUT (VDP_ADDR),a            ;
   LD a, $3E                   ; High address byte
   OUT (VDP_ADDR),a            ;

   LD hl, RAM_VPOS             ; tile_data is defined below 
   LD b, 59                    ; Set up counter (vpos)
   CALL copy_to_vdp_loop       ; Copy data from HL to C 

   LD a, $7F                   ; Low address byte
   OUT (VDP_ADDR),a            ;
   LD a, $3F                   ; High address byte
   OUT (VDP_ADDR),a            ;

   LD hl, RAM_HPOS             ; tile_data is defined below 
   LD b, 117                   ; Set up counter (hpos, tile)
   CALL copy_to_vdp_loop       ; Copy data from HL to C 

   RET                         ; End subroutine
;---------------------------------------

;---------------------------------------
; copy_to_vdp_loop 
;
; Copy data from HL to VDP
; Length counter is B
;---------------------------------------
copy_to_vdp_loop:              
   LD a, (hl)                  ;
   NOP                         ;
   OUT (VDP_DATA), a           ; Write to VDP

   INC hl                      ; Increment HL
   DEC b                       ; Decrement B
   JP NZ, copy_to_vdp_loop     ;
   
   RET                         ;
;---------------------------------------

;---------------------------------------
; copy_to_vdp_loop_long 
;
; Copy data from HL to VDP
; Length counter is DE
;---------------------------------------
copy_to_vdp_loop_long:              
   LD a, (hl)                   ;
   NOP                          ;
   OUT (VDP_DATA), a            ; Write to VDP

   INC hl                       ; Increment HL
   DEC de                       ; Decrement DE
   LD a, d                      ; A <- D
   OR e                         ; A OR E
   JP NZ, copy_to_vdp_loop_long ;
   
   RET                          ;
;---------------------------------------

;---------------------------------------
; copy_to_RAM_loop 
;
; Copy data from HL to DE
; Length counter is B
;---------------------------------------
copy_to_RAM_loop:              
   LD a, (hl)                   ;
   LD (de), a                   ;

   INC hl                       ; Increment HL
   INC de                       ; Increment DE
   DEC b                        ; Decrement B
   JP NZ, copy_to_RAM_loop      ;
   
   RET                          ;
;---------------------------------------

;-----------------------------------------
; xy_collision_detect16 
;
; RAM_COLL_X1     = x1
; RAM_COLL_Y1     = y1
; RAM_COLL_X2     = x1
; RAM_COLL_Y2     = y1
; RAM_COLL_RESULT = result, $00 => miss, $01 => hit
;
; Is (x2,y2) within 16x16 box with
; top corner at (x1,y1)?
;
;-----------------------------------------
xy_collision_detect16:
   LD a, $00                   ; Assume miss until hit
   LD (RAM_COLL_RESULT), a     ;

   LD a, (RAM_COLL_Y1)         ; y1
   SUB 4                       ; center is 4 pixels from top corner
   LD b, a                     ;
   LD a, (RAM_COLL_Y2)         ; y2
   SUB b                       ; a = y2 - y1
   AND $F0                     ; mask unwanted bits
   CP $00                      ; If difference is less than 16 pixels, declare hit
   JP NZ, xycds_end16          ;

   LD a, (RAM_COLL_X1)         ; x1
   SUB 4                       ; center is 4 pixels from top corner
   LD b, a                     ;
   LD a, (RAM_COLL_X2)         ; x2
   SUB b                       ; a = x2 - x1
   AND $F0                     ; mask unwanted bits
   CP $00                      ; If difference is less than 16 pixels, declare hit
   JP NZ, xycds_end16          ;

   LD a, $7F                   ; Proven hit
   LD (RAM_COLL_RESULT), a     ;

xycds_end16: 
   RET                         ; End subroutine

;========
;= Code =
;========
.include "intro.txt"
.include "title_screen.txt"
.include "score_and_lives.txt"
.include "level_x.txt"
.include "level_y.txt"
.include "ending.txt"

;==============================
;= Sprite and background data =
;==============================
.include "sprites_and_bg.txt"

;----------------------------------------
; Include Files
.BANK 1 SLOT 1
.org $0000

;=============
;= Tile data =
;=============
bnbw_GP_tiles:
.include "bnbw_3x4GPs (tiles).inc"

bnbw_GPII_tiles:
.include "bnbw_3x4GPsII (tiles).inc"

bnbw_GPIII_tiles:
.include "bnbw_3x4GPsIII (tiles).inc"

bnbw_text_tiles:
.include "bnbw_text (tiles).inc"

bnbw_bread_tiles:
.include "bnbw_3x4bread (tiles).inc"

bnbw_butter_tiles:
.include "bnbw_3x4butter (tiles).inc"

level_1_bg_tiles:
.include "bnbw_lv1_bg (tiles).inc"

title_bg_tiles :
.include "bnbw_title_screen (tiles).inc"

chickens_eggs_tiles:
.include "bnbw_2x2chickensandeggs (tiles).inc" 

milk_tiles:
.include "bnbw_2x2milk (tiles).txt" 

wheat_tiles:
.include "bnbw_2x2wheat (tiles).inc" 

level_1_bg_tiles2:
.include "bnbw_2x2blocks (tiles).inc"

bread_of_legend_tiles:
.include "breadoflegend (tiles).inc"


;----------------------------------------
; Include Files
.BANK 2 SLOT 2
.org $0000

ending_1_tiles:
.include "GPMainComputer (tiles).inc"

ending_2_tiles:
.include "GPMainComputer2 (tiles).inc"

;========
;= Code =
;========
.include "sound.txt"






