; -------------------------------------------------------------;
;                          MR. ULTRA                           ;
; -------------------------------------------------------------;

.sdsctag 0.1, "Mr. Ultra", "Mr. Ultra", "Bologna S. Stupid"

.memorymap
defaultslot 0
slotsize $4000 ; ROM
slot 0 $0000
slot 1 $4000
slot 2 $8000
slotsize $2000 ; RAM
slot 3 $c000
.endme

.rombankmap                ; map rom to 2 x 16 kb banks.
       bankstotal 2
       banksize $4000
       banks 2
.endro

.equ   vspeed 7            ; players' vertical speed.
.equ   hspeed 3            ; horiz. speed of player and enemy.
.equ   rightb $dc          ; right border of the road.
.equ   leftb $14           ; left border of the road.

; Map of the sprite attribute table (sat) buffer.
; Contains sprites' vertical position (vpos), horizontal posi-
; tion (hpos) and character codes (cc).

.equ plrvp $c008           ; mr. ultra vpos.
.equ plrhp $c090           ; mr. ultra hpos.
.equ plrcc $c091           ; mr. ultra cc.

.equ cloudvp $c018           ; cloud vpos.
.equ cloudhp $c0b0           ; cloud hpos.
.equ cloudcc $c0b1           ; cloud cc.

.equ cloud2vp $c028           ; second cloud vpos.
.equ cloud2hp $c0d0           ; second cloud hpos.
.equ cloud2cc $c0d1           ; second cloud cc.


.equ endspr $c038          ; first unused sprite.

 ; Organize ram - create the sat buffer and variables.

.enum $c000 export         ; export labels to symbol file.

       satbuf dsb 256      ; sprite attribute table buffer.
                           ; see the map for object offsets.

       scroll db           ; vdp scroll register buffer.
       input db            ; input from player 1 controller.
       iflag db
       frame db            ; frame counter.
       status db           ; vdp status (for collision detect.).

       cloudy db              ; Player y.
       cloudx db              ; Player x

       cloud2y db              ; Player y.
       cloud2x db              ; Player x
       
       thi db
       event   db
       bananaevent  db
       enemyframe   db
       enemycollision  db
       enemyycollision db

       playintro db           ; is intro being played?
       jumping db             ; is player jumping?
       falling db               ; is player falling?

       ply db              ; Player y.
       plx db              ; Player x.
.ende

.bank 0 slot 0
.org 0
       di                  ; disable interrupts.
       im 1                ; interrupt mode 1.
       ld sp,$dff0         ; default stack pointer address.
       jp inigam           ; initialize game.

; Read the vdp status flag at every frame interrupt.
; Sprite collision is read from bit 5 of the status flag.

.orga $0038                ; frame interrupt address.
        ex af,af'           ; save accumulator in its shadow reg.
        in a,$bf            ; get vdp status / satisfy interrupt. 
        ld (status),a       ; save vdp status in ram.
        ld a,1              ; load accumulator with raised flag. 
        ld (iflag),a        ; set interrupt flag. 
        ex af,af'           ; restore accumulator. 
        ei                  ; enable interrupts.
        reti                ; return from interrupt.

; Disable the pause button - this is an unforgiving game!

.orga $0066                ; pause button interrupt.
       retn                ; disable pause button.

; Initialize game.
; Overwrite the first 4 kb of ram with zeroes.



inigam ld hl,$c000         ; point to beginning of ram.
       ld bc,$1000         ; 4 kb to fill.
       ld a,0              ; with value 0.
       call mfill          ; do it!

; Use the initialized ram to clean all of vram.

       ld hl,$0000         ; prepare vram for data at $0000.
       call vrampr
       ld b,4              ; write 4 x 4 kb = 16 kb.
-      push bc             ; save the countter.
       ld hl,$c000         ; source = freshly initialized ram.
       ld bc,$1000         ; 4 kb of zeroes.
       call vramwr         ; purge vram.
       pop bc              ; retrieve counter.
       djnz -


 ; Initialize PSGLib.

       call PSGInit        ; credit goes to sverx!

title_screen



       ld hl,$2000         ; first tile @ index 256.
       call vrampr         ; prepare vram.
       ld hl,pltile1        ; player car tile data.
       ld bc,5*32          ; 4 tiles, 32 bytes each.
       call vramwr         ; write player car tiles to vram.

       ld hl,$2200         ; first tile @ index 272.
       call vrampr         ; prepare vram.
       ld hl,cloudtile     ; cloud tile data.
       ld bc,5*32          ; 16 tiles, 32 bytes each.
       call vramwr         ; write enemy car tiles to vram.

       ld hl,$2400         ; first tile @ index 288.
       call vrampr         ; prepare vram.
       ld hl,cloudtile2
       ld bc,5*32          ; 16 tiles, 32 bytes each.
       call vramwr         ; write crashed player tiles to vram.


       ld hl,$c000         ; color bank 2, color 0.
       call vrampr         ; prepare vram.
       ld hl,bgpal         ; background palette.
       ld bc,32            ; 4 colors.
       call vramwr         ; set background palette.

       ld hl,$c020         ; color bank 2, color 0 (sprites).
       call vrampr         ; prepare vram.
       ld hl,plpal         ; sprite palette data.
       ld bc,32            ; 5 colors.
       call vramwr         ; set sprite palette.

; Initialize variables - once per game.

       ld a,97           ;
       ld (ply),a          ; set player y.

       ld a,50           ;
       ld (cloudy),a          ; set player y.

       ld a,50           ;
       ld (cloud2y),a          ; set player y.



       ld a,0            ;
       ld (playintro),a          ; set player y.

; Initialize the VDP registers.

       ld hl,regdat        ; point to register init data.
       ld b,11             ; 11 bytes of register data.
       ld c,$80            ; VDP register command byte.

-:     ld a,(hl)           ; load one byte  of data into A.
       out ($bf),a         ; output data to VDP command port.
       ld a,c              ; load the command byte.
       out ($bf),a         ; output it to the VDP command port.
       inc hl              ; inc. pointer to next byte of data.
       inc c               ; inc. command byte to next register.
       djnz -              ; jump back to '-' if b > 0.

; Load assets for main loop.

; Setup the background assets for the main loop.

       ; always put a blank tile for the first tile of the bgmap. The player graphics rely on that.
       ld hl,$0000         ; first tile @ index 0.
       call vrampr         ; prepare vram.
       ld hl,bgtile        ; background tile data (the road).
       ld bc,77*32         ; each tile is 32 bytes.
       call vramwr         ; write background tiles to vram.

       ld hl,$3800         ; point to name table.
       call vrampr         ; prepare vram.
       ld hl,bgmap         ; point to background tilemap data.
       ld bc,32*28*2       ; 32 x 28 tiles, each is 2 bytes.
       call vramwr         ; write name table to vram.

; Put the sprites in.



       ld de,plrcc         ; point to player cc in buffer.
       ld hl,plrcar        ; point to player car graphics.
       call carcc          ; set the char codes for player car.

       ld a,79             ; player starts at the road's center.
       ld (plx),a          ; set x-coordinate.



       ld de,cloudcc       ; point to player cc in buffer.
       ld hl,plrhole       ; point to player car graphics.
       call cloud1cc        ; set the char codes for player car.

       ld a,89             ; player starts at the road's center.
       ld (cloudx),a       ; set x-coordinate.

       ld de,cloud2cc       ; point to player cc in buffer.
       ld hl,plrhole      ; point to player car graphics.
       call cloud1cc        ; set the char codes for player car.

       ld a,97            ; player starts at the road's center.
       ld (cloud2x),a       ; set x-coordinate.

      ; xor a               ; set A = 0.
      ; ld (scroll),a       ; reset scroll register buffer.
       ;ld (frame),a        ; reset frame counter.

       ld hl,endspr        ; point to end of active sprites.
       ld (hl),$d0         ; insert sprite terminator here.

       call upbuf         ; update buffer for cars and digits.
       call ldsat          ; load sat from buffer.

       ld a,%11100000      ; turn screen on - normal sprites.
       ld b,1
       call setreg         ; set register 1.

       ei



       ld hl,titune
       call PSGPlay





; This is the main loop.

mloop  halt                ; start main loop with vblank.

; Update vdp right when vblank begins!

      ; ld a,(scroll)       ; 1-byte scroll reg. buffer in ram.
      ; ld b,9              ; target VDP register 9 (v-scroll).
      ; call setreg         ; now vdp register = buffer, and the
                           ; screen scrolls accordingly.

       call ldsat          ; load sat buffer to vram. The cars
                           ; and the (hi)-score sprites are
                           ; updated on the screen.





       ld a,(playintro)
       cp 1
       jp nc,mp1           ; yes - skip to left test.

       ld a,(cloudx)          ; get player x-coordinate.
       ld b, 1        ; load horizontal speed (constant).
       sub b               ; subtract hspeed from player x.
       ld (cloudx),a          ; update player x-coordinate.

       ld a,(cloud2x)          ; get player x-coordinate.
       ld b, 1        ; load horizontal speed (constant).
       sub b               ; subtract hspeed from player x.
       ld (cloud2x),a          ; update player x-coordinate.

       in     a,($00)
       ;cpl                    ; invert logic so 1 = pressed
       and    %10000000

       jp nz,endchk           ; no - test for left key.




mp1
       ld a,(plx)          ; get player x-coordinate.
       add a,1       ; add constant hspeed
       ld (plx),a          ; update player x-coordinate.

       ld a,(plx)          ; get player's hpos (x-coordinate).
       cp rightb           ; is player over thr right border?
       jp nc,begin_level_1          ; yes - start game


       ld a,1             ; player starts at the road's center.
       ld (playintro),a       ; set x-coordinate.



endchk                     ; end key check

       ld a,(frame)          ; get player x-coordinate.
       add a,1       ; add constant hspeed
       ld (frame),a          ; update player x-coordinate.

       ld a,(frame)          ; get player's hpos (x-coordinate).
       cp 10          ; is player over thr right border?
       jp nc,anim2          ; yes - skip to left test.


       ld hl,$2000         ; first tile @ index 256.
       call vrampr         ; prepare vram.
       ld hl,pltile1        ; player car tile data.
       ld bc,5*32          ; 4 tiles, 32 bytes each.
       call vramwr         ; write player car tiles to vram.

       jp endofanim

anim2
       ld hl,$2000         ; first tile @ index 256.
       call vrampr         ; prepare vram.
       ld hl,pltile2        ; player car tile data.
       ld bc,5*32          ; 4 tiles, 32 bytes each.
       call vramwr         ; write player car tiles to vram.

       ld a,(frame)          ; get player's hpos (x-coordinate).
       cp 20          ; is player over thr right border?
       jp c,endofanim          ; yes - skip to left test.

       ld a,1             ; player starts at the road's center.
       ld (frame),a       ; set x-coordinate.


endofanim
; Update player sprites in the buffer.

       call upbuf          ; update sat buffer.

; Scroll background - update the vertical scroll buffer.

      ; ld a,(scroll)       ; get scroll buffer value.
      ; sub vspeed          ; subtract vertical speed.
      ; ld (scroll),a       ; update scroll buffer.

       jp mloop            ; jump back for another round.

begin_level_1

       xor a
       ld (iflag),a

; Setup the background assets for the main loop.
       ld a,97           ;
       ld (ply),a          ; set player y.

       ld a,0            ; player starts at the road's center.
       ld (jumping),a       ; set x-coordinate.

       ld a,0            ; player starts at the road's center.
       ld (falling),a       ; set x-coordinate.



       ld hl,$c000         ; color bank 1, color 0.
       call vrampr         ; prepare vram.
       ld hl,bgpal         ; background palette.
       ld bc,15             ; 4 colors.
       call vramwr         ; set background palette.

       ld hl,$0000         ; first tile @ index 0.
       call vrampr         ; prepare vram.
       ld hl,level1bgtile        ; background tile data (the road).
       ld bc,77*32          ; 2 tiles (!), each tile is 32 bytes.
       call vramwr         ; write background tiles to vram.

       ld hl,$3800         ; point to name table.
       call vrampr         ; prepare vram.
       ld hl,level1bgmap        ; point to background tilemap data.
       ld bc,32*28*2       ; 32 x 28 tiles, each is 2 bytes.
       call vramwr         ; write name table to vram.

       ld de,plrcc         ; point to player cc in buffer.
       ld hl,plrcar        ; point to player car graphics.
       call carcc          ; set the char codes for player car.

       ld a,80             ; player starts at the road's center.
       ld (plx),a          ; set x-coordinate.

; Put the sprites in.


       ld a,0            ; player starts at the road's center.
       ld (event),a       ; set x-coordinate.

       ;jp this_is_stupid

level1events
       ld a,(event)          ; get player's hpos (x-coordinate).
       cp 20         ; is player over thr right border?
       jp nc,main_game      ; yes - skip to left test.

       ld a,(event)          ; get player's hpos (x-coordinate).
       cp 17                  ; is player over thr right border?
       jp nc,reintroduce_hole       ; yes - skip to left test.

       ld a,(event)          ; get player's hpos (x-coordinate).
       cp 18                  ; is player over thr right border?
       jp nc,reintroduce_hole       ; yes - skip to left test.

       ld a,(event)          ; get player's hpos (x-coordinate).
       cp 19         ; is player over thr right border?
       jp nc,reintroduce_bananas       ; yes - skip to left test.



       ld a,(event)          ; get player's hpos (x-coordinate).
       cp 2          ; is player over thr right border?
       jp c,reintroduce_hole     ; yes - skip to left test.

       ld a,(event)          ; get player's hpos (x-coordinate).
       cp 3          ; is player over thr right border?
       jp c,reintroduce_hole        ; yes - skip to left test.

       ld a,(event)          ; get player's hpos (x-coordinate).
       cp 4         ; is player over thr right border?
       jp c,reintroduce_bananas       ; yes - skip to left test.

       ld a,(event)          ; get player's hpos (x-coordinate).
       cp 5         ; is player over thr right border?
       jp c,reintroduce_hole         ; yes - skip to left test.

       ld a,(event)          ; get player's hpos (x-coordinate).
       cp 6         ; is player over thr right border?
       jp c,reintroduce_bananas       ; yes - skip to left test.

       ld a,(event)          ; get player's hpos (x-coordinate).
       cp 7         ; is player over thr right border?
       jp c,reintroduce_bananas       ; yes - skip to left test.

       ld a,(event)          ; get player's hpos (x-coordinate).
       cp 8         ; is player over thr right border?
       jp c,reintroduce_hole         ; yes - skip to left test.

       ld a,(event)          ; get player's hpos (x-coordinate).
       cp 9        ; is player over thr right border?
       jp c,reintroduce_hole       ; yes - skip to left test.

       ld a,(event)          ; get player's hpos (x-coordinate).
       cp 10         ; is player over thr right border?
       jp c,reintroduce_bananas       ; yes - skip to left test.

       ld a,(event)          ; get player's hpos (x-coordinate).
       cp 11                  ; is player over thr right border?
       jp c,reintroduce_hole       ; yes - skip to left test.

       ld a,(event)          ; get player's hpos (x-coordinate).
       cp 12         ; is player over thr right border?
       jp c,reintroduce_bananas       ; yes - skip to left test.

       ld a,(event)          ; get player's hpos (x-coordinate).
       cp 13         ; is player over thr right border?
       jp c,reintroduce_bananas       ; yes - skip to left test.
       
       ld a,(event)          ; get player's hpos (x-coordinate).
       cp 14         ; is player over thr right border?
       jp c,reintroduce_bananas       ; yes - skip to left test.

       ld a,(event)          ; get player's hpos (x-coordinate).
       cp 15                  ; is player over thr right border?
       jp c,reintroduce_hole       ; yes - skip to left test.

       ld a,(event)          ; get player's hpos (x-coordinate).
       cp 16         ; is player over thr right border?
       jp nc,reintroduce_bananas       ; yes - skip to left test.



       jp reintroduce_hole

reintroduce_bananas

       ld hl,$2200         ; first tile @ index 272.
       call vrampr         ; prepare vram.
       ld hl,bananatile      ; hole tile data.
       ld bc,5*32          ; 16 tiles, 32 bytes each.
       call vramwr         ; write enemy car tiles to vram.

       ld hl,$2400         ; first tile @ index 272.
       call vrampr         ; prepare vram.
       ld hl,bananatile      ; hole tile data.
       ld bc,5*32          ; 16 tiles, 32 bytes each.
       call vramwr         ; write enemy car tiles to vram.

       ; Put the sprites in.
       ld a,210           ; player starts at the road's center.
       ld (cloudx),a       ; set x-coordinate.

       ld a,113        ; player starts at the road's center.
       ld (cloudy),a       ; set x-coordinate.

       ld a,218          ; player starts at the road's center.
       ld (cloud2x),a       ; set x-coordinate.

       ld a,113          ; player starts at the road's center.
       ld (cloud2y),a       ; set x-coordinate.

       ld a,1            ; player starts at the road's center.
       ld (bananaevent),a       ; set x-coordinate.

       jp this_is_stupid




reintroduce_hole



     ;  ld a,(event)          ; get player's hpos (x-coordinate).
     ;  cp 2          ; is player over thr right border?
     ;  jp nc,begin_level_1         ; yes - skip to left test.

       ld hl,$2200         ; first tile @ index 272.
       call vrampr         ; prepare vram.
       ld hl,holetile      ; hole tile data.
       ld bc,5*32          ; 16 tiles, 32 bytes each.
       call vramwr         ; write enemy car tiles to vram.

       ld hl,$2400         ; first tile @ index 272.
       call vrampr         ; prepare vram.
       ld hl,holetile      ; hole tile data.
       ld bc,5*32          ; 16 tiles, 32 bytes each.
       call vramwr         ; write enemy car tiles to vram.




       ld a,0            ; player starts at the road's center.
       ld (enemyframe),a       ; set x-coordinate.

       ld a,210            ; player starts at the road's center.
       ld (cloudx),a       ; set x-coordinate.

       ld a,127         ; player starts at the road's center.
       ld (cloudy),a       ; set x-coordinate.

       ld a,218            ; player starts at the road's center.
       ld (cloud2x),a       ; set x-coordinate.

       ld a,127          ; player starts at the road's center.
       ld (cloud2y),a       ; set x-coordinate.


        ld a,0            ; player starts at the road's center.
       ld (bananaevent),a       ; set x-coordinate.



       ;jp main_game

this_is_stupid

       ld de,cloud2cc       ; point to player cc in buffer.
       ld hl,plrhole       ; point to player car graphics.
       call cloud1cc        ; set the char codes for player car.

       ld de,cloudcc       ; point to player cc in buffer.
       ld hl,plrhole      ; point to player car graphics.
       call cloud1cc        ; set the char codes for player car.

       ld a,(event)          ; get player x-coordinate.
       add a,1       ; add constant hspeed
       ld (event),a          ; update player x-coordinate.




main_game


       call wait



       call ldsat          ; load sat buffer to vram. The cars
                           ; and the (hi)-score sprites are
                           ; updated on the screen.

       call PSGFrame       ; handle music.

       ld a,(event)          ; get player's hpos (x-coordinate).
       cp 20         ; is player over thr right border?
       jp nc,level_1_ending      ; yes - skip to left test.

       jp main_game_1
       
level_1_ending
       ld a,(plx)          ; get player x-coordinate.
       add a,1       ; add constant hspeed
       ld (plx),a          ; update player x-coordinate.

       ld a,(plx)          ; get player's hpos (x-coordinate).
       cp rightb         ; is player over thr right border?
       jp nc,title_screen     ; yes - skip to left test.


       ld a,(frame)          ; get player x-coordinate.
       add a,1       ; add constant hspeed
       ld (frame),a          ; update player x-coordinate.

       ld a,(frame)          ; get player's hpos (x-coordinate).
       cp 10          ; is player over thr right border?
       jp nc,level1endinganim1        ; yes - skip to left test.


       ld hl,$2000         ; first tile @ index 256.
       call vrampr         ; prepare vram.
       ld hl,pltile1        ; player car tile data.
       ld bc,5*32          ; 4 tiles, 32 bytes each.
       call vramwr         ; write player car tiles to vram.

       jp main_game_2

level1endinganim1
       ld hl,$2000         ; first tile @ index 256.
       call vrampr         ; prepare vram.
       ld hl,pltile2        ; player car tile data.
       ld bc,5*32          ; 4 tiles, 32 bytes each.
       call vramwr         ; write player car tiles to vram.

       ld a,(frame)          ; get player's hpos (x-coordinate).
       cp 20          ; is player over thr right border?
       jp c,endlevelend         ; yes - skip to left test.

       ld a,1             ; player starts at the road's center.
       ld (frame),a       ; set x-coordinate.

endlevelend
       jp main_game_3

main_game_1
       ld de,plx        ; point to score.


       ld a,(cloudx)          ; get player x-coordinate.
       add a,16       ; add constant hspeed
       ld (thi),a          ; update player x-coordinate.

       ld hl,thi       ; point to hiscore.

       ld a,(de)           ; load score digit
       cp (hl)             ; is hiscore digit > score digit?
       jp nc,argh        ; yes - break out of loop.
       


       ld de,plx        ; point to score.
       ld hl,cloudx        ; point to hiscore.


       ld a,(de)           ; load score digit
       cp (hl)             ; is hiscore digit > score digit?
       jp c,argh        ; yes - break out of loop.

       ld a,(ply)          ; get player's hpos (x-coordinate).
       cp 95          ; is player over thr right border?
       jp c,argh         ; yes - skip to left test.



        jp falling_down_hole_code


argh
       ld a,(bananaevent)          ; get player's hpos (x-coordinate).
       cp 1          ; is player over thr right border?
       jp c,enemyanim4         ; yes - skip to left test.

       ld a,(cloudx)          ; get player's hpos (x-coordinate).
       cp 208          ; is player over thr right border?
       jp c,argh2        ; yes - skip to left test.


       call getkey         ; read controller port.
       ld a,(input)        ; read input from ram mirror.
       bit 3,a             ; is right key pressed?
       jp nz,enemyanim4   ; no - test for left key.




argh2
       ld a,(cloudx)          ; get player x-coordinate.
       ld b, 1        ; load horizontal speed (constant).
       sub b               ; subtract hspeed from player x.
       ld (cloudx),a          ; update player x-coordinate.

       ld a,(cloud2x)          ; get player x-coordinate.
       ld b, 1        ; load horizontal speed (constant).
       sub b               ; subtract hspeed from player x.
       ld (cloud2x),a          ; update player x-coordinate.



       ld a,(cloud2x)          ; get player's hpos (x-coordinate).
       cp 20          ; is player over thr right border?
       jp c,level1events         ; yes - skip to left test.

       ld a,(enemyframe)          ; get player x-coordinate.
       add a,1       ; add constant hspeed
       ld (enemyframe),a          ; update player x-coordinate.

       ld a,(enemyframe)          ; get player's hpos (x-coordinate).
       cp 10          ; is player over thr right border?
       jp nc,enemyanim2         ; yes - skip to left test.

       ld hl,$2200         ; first tile @ index 256.
       call vrampr         ; prepare vram.
       ld hl,bananatile        ; player car tile data.
       ld bc,5*32          ; 4 tiles, 32 bytes each.
       call vramwr         ; write player car tiles to vram.


       jp enemyanim3




enemyanim2
       ld hl,$2200         ; first tile @ index 256.
       call vrampr         ; prepare vram.
       ld hl,bananatile2        ; player car tile data.
       ld bc,5*32          ; 4 tiles, 32 bytes each.
       call vramwr         ; write player car tiles to vram.




enemyanim3


       ld a,(enemyframe)          ; get player's hpos (x-coordinate).
       cp 20          ; is player over thr right border?
       jp c,enemyanim4          ; yes - skip to left test.

       ld a,1             ; player starts at the road's center.
       ld (enemyframe),a       ; set x-coordinate.

       jp enemyanim4





enemyanim4

       ld a,(falling)          ; get player's hpos (x-coordinate).
       cp 3          ; is player over thr right border?
       jp nc,falling_down_hole_code         ; yes - skip to left test.



       call getkey         ; read controller port.
       ld a,(input)        ; read input from ram mirror.
       bit 3,a             ; is right key pressed?
       jp nz,main_game_2   ; no - test for left key.


 
       ld a,(cloudx)          ; get player x-coordinate.
       ld b, 1        ; load horizontal speed (constant).
       sub b               ; subtract hspeed from player x.
       ld (cloudx),a          ; update player x-coordinate.

       ld a,(cloud2x)          ; get player x-coordinate.
       ld b, 1        ; load horizontal speed (constant).
       sub b               ; subtract hspeed from player x.
       ld (cloud2x),a          ; update player x-coordinate.

       ld a,(cloud2x)          ; get player's hpos (x-coordinate).
       cp 20          ; is player over thr right border?
       jp c,level1events         ; yes - skip to left test.



       ld a,(frame)          ; get player x-coordinate.
       add a,1       ; add constant hspeed
       ld (frame),a          ; update player x-coordinate.

       ld a,(frame)          ; get player's hpos (x-coordinate).
       cp 10          ; is player over thr right border?
       jp nc,anim2main          ; yes - skip to left test.


       ld hl,$2000         ; first tile @ index 256.
       call vrampr         ; prepare vram.
       ld hl,pltile1        ; player car tile data.
       ld bc,5*32          ; 4 tiles, 32 bytes each.
       call vramwr         ; write player car tiles to vram.

       jp main_game_2

anim2main
       ld hl,$2000         ; first tile @ index 256.
       call vrampr         ; prepare vram.
       ld hl,pltile2        ; player car tile data.
       ld bc,5*32          ; 4 tiles, 32 bytes each.
       call vramwr         ; write player car tiles to vram.

       ld a,(frame)          ; get player's hpos (x-coordinate).
       cp 20          ; is player over thr right border?
       jp c,main_game_2          ; yes - skip to left test.

       ld a,1             ; player starts at the road's center.
       ld (frame),a       ; set x-coordinate.


main_game_2






dont_fall_stupid
       ;call getkey         ; read controller port into ram.
       ld a,(input)        ; read input from ram mirror.
       bit 4,a             ; is button 1 pressed?
       jp nz,falling_code  ; if not then go to rest of code

        ld a,(falling)          ; get player's hpos (x-coordinate).
       cp 1          ; is player over thr right border?
       jp nc,falling_code          ; if not then go to rest of code


       ld a,1             ; player starts at the road's center.
       ld (jumping),a       ; set x-coordinate.

       ld hl,titune        ; load title screen tune.
       call PSGPlayNoRepeat ; play it once.

     ;  ld a,%11100000      ; turn noise volume up to 12 db.
     ;  out ($7f),a         ; write to psg.
     ;  ld a,%11100001      ; make coarse noise - go car engine!
      ; out ($7f),a         ; write to psg.


       ld a,(ply)          ; get player's hpos (x-coordinate).
       cp 47          ; is player over thr right border?
       jp c,falling_code        ; if not then go to rest of code



       ld a,1             ; player starts at the road's center.
       ld (frame),a       ; set x-coordinate.



       ld hl,titune        ; load title screen tune.
       call PSGPlayNoRepeat ; play it once.


       ld a,(ply)          ; get player x-coordinate.
       ld b, 2        ; load horizontal speed (constant).
       sub b               ; subtract hspeed from player x.
       ld (ply),a          ; update player x-coordinate.

       ;ld a,(ply)          ; get player's hpos (x-coordinate).
       ;cp 41          ; is player over thr right border?
       ;jp nc,falling_code          ; if not then go to rest of code




      jp main_game_3



falling_down_hole_code

       ld a,(cloudy)          ; get player's hpos (x-coordinate).
       ld b, 8        ; load horizontal speed (constant).
       sub b               ; subtract hspeed from player x.
       ld (enemyycollision),a          ; update player x-coordinate.



       ld a,(ply)          ; get player x-coordinate.
       add a,4       ; add constant hspeed
       ld (ply),a          ; update player x-coordinate.

       ld a,(ply)          ; get player's hpos (x-coordinate).
       cp 157          ; is player over thr right border?
       jp nc,title_screen

       ld a,3            ; player starts at the road's center.
       ld (falling),a       ; set x-coordinate.

       jp   main_game_3




falling_code


       call quiet          ; kill the noise generator.

       ld a,(ply)          ; get player's hpos (x-coordinate).
       cp 95          ; is player over thr right border?
       jp c,falling_code_2      ; if not then go to rest of code

       ld a,97           ; player starts at the road's center.
       ld (ply),a       ; set x-coordinate.

       jp stop_falling


falling_code_2
       ld a,(ply)          ; get player's hpos (x-coordinate).
       cp 97          ; is player over thr right border?
       jp nc,stop_falling         ; if not then go to rest of code


falling_code_3
       ld a,1            ; player starts at the road's center.
       ld (falling),a       ; set x-coordinate.

        ld a,0            ; player starts at the road's center.
       ld (jumping),a       ; set x-coordinate.

       ld a,(ply)          ; get player x-coordinate.
       add a,4       ; add constant hspeed
       ld (ply),a          ; update player x-coordinate.




      jp main_game_3


stop_falling

       ld a,2            ; player starts at the road's center.
       ld (falling),a       ; set x-coordinate.

       ld a,(input)        ; read input from ram mirror.
       bit 4,a             ; is button 1 pressed?
       jp z,main_game_3  ; if not then go to rest of code

       ld a,0            ; player starts at the road's center.
       ld (falling),a       ; set x-coordinate.
       jp main_game_3




main_game_3    
       call upbufholes




       jp main_game

; --------------------------------------------------------------
; SUBROUTINES
; --------------------------------------------------------------
; --------------------------------------------------------------
; QUIET NOISE GENERATOR.

quiet  ld a,$ff            ; we want to kill the noise channel.
       out ($7f),a         ; write wish to psg port.
       ret


; PREPARE VRAM.
; Set up vdp to recieve data at vram address in HL.

vrampr push af
       ld a,l
       out ($bf),a
       ld a,h
       or $40
       out ($bf),a
       pop af
       ret

; --------------------------------------------------------------
; WRITE TO VRAM
; Write BC amount of bytes from data source pointed to by HL.
; Tip: Use vrampr before calling.

vramwr ld a,(hl)
       out ($be),a
       inc hl
       dec bc
       ld a,c
       or b
       jp nz,vramwr
       ret

; --------------------------------------------------------------
; LOAD SPRITE ATTRIBUTE TABLE
; Load data into sprite attribute table (SAT) from the buffer.

ldsat  ld hl,$3f00         ; point to start of SAT in vram.
       call vrampr         ; prepare vram to recieve data.
       ld b,255            ; amount of bytes to output.
       ld c,$be            ; destination is vdp data port.
       ld hl,satbuf        ; source is start of sat buffer.
       otir                ; output buffer to vdp.
       ret

; --------------------------------------------------------------
; UPDATE SAT BUFFER
; Generate vpos, hpos and cc data for the sprites that make up
; each of the cars (player, Mae and Ash).
; Also generate char code (cc) data from hiscore and score.

; Generate sat buffer data from player's x,y coordinates.

upbuf
       ld a,(ply)          ; load player's current y-coordinate.
       ld hl,plrvp         ; point to sat buffer.
       call cary           ; refresh buffer according to y.

       ld a,(plx)          ; load player's current x-coordinate.
       ld hl,plrhp         ; point to sat buffer.
       call carx           ; refresh buffer according to x.


       ld a,(cloudy)          ; load player's current y-coordinate.
       ld hl,cloudvp         ; point to sat buffer.
       call holey2          ; refresh buffer according to y.


       ld a,(cloudx)          ; load player's current x-coordinate.
       ld hl,cloudhp         ; point to sat buffer.
       call holex2          ; refresh buffer according to x.

       ld a,(cloud2y)          ; load player's current y-coordinate.
       ld hl,cloud2vp         ; point to sat buffer.
       call holey2           ; refresh buffer according to y.


       ld a,(cloud2x)          ; load player's current x-coordinate.
       ld hl,cloud2hp         ; point to sat buffer.
       call holex2          ; refresh buffer according to x.




       ret

upbufholes
        ld a,(ply)          ; load player's current y-coordinate.
       ld hl,plrvp         ; point to sat buffer.
       call cary           ; refresh buffer according to y.

       ld a,(plx)          ; load player's current x-coordinate.
       ld hl,plrhp         ; point to sat buffer.
       call carx           ; refresh buffer according to x.

       ld a,(cloudy)          ; load player's current y-coordinate.
       ld hl,cloudvp         ; point to sat buffer.
       call holey2          ; refresh buffer according to y.


       ld a,(cloudx)          ; load player's current x-coordinate.
       ld hl,cloudhp         ; point to sat buffer.
       call holex2          ; refresh buffer according to x.

       ld a,(cloud2y)          ; load player's current y-coordinate.
       ld hl,cloud2vp         ; point to sat buffer.
       call holey2           ; refresh buffer according to y.


       ld a,(cloud2x)          ; load player's current x-coordinate.
       ld hl,cloud2hp         ; point to sat buffer.
       call holex2          ; refresh buffer according to x.

       ret

; --------------------------------------------------------------
; CAR Y TO SPRITES' VERTICAL POSITIONS (VPOS) IN BUFFER.
; Generate vpos sat buffer data from a car's y position.
; A = car's y (i.e. ply), HL = buffer address of car vpos.

cloud1y  ld c,a              ; save hpos in C
       .rept 2             ; wladx: Repeat code four times.
       ld a,c              ; load hpos into A
       ld b,2             ; loop: Repeat four times.
-      ld (hl),a           ; write value too buffer at address.
       inc hl              ; skip over the char code byte.
       inc hl              ; point to next hpos byte in buffer.
       add a,0             ; add 8 (a tile's width in pixels).
       djnz -              ; jump back
       .endr               ; end of wladx repeat directive.
       ret

; --------------------------------------------------------------
; CAR X TO SPRITES' HORIZONTAL POSITIONS (HPOS) IN BUFFER.
; Generates hpos sat buffer data from a car's x position.
; A = car's x (i.e. plx), HL = buffer address of car hpos.

cloud1x ld c,a              ; save hpos in C
       .rept 1             ; wladx: Repeat code four times.
       ld a,c              ; load hpos into A

       ld b,1             ; loop: Repeat four times.
-      ld (hl),a           ; write value too buffer at address.
       inc hl              ; skip over the char code byte.
       inc hl              ; point to next hpos byte in buffer.
       add a,8             ; add 8 (a tile's width in pixels).
       djnz -              ; jump back
       .endr               ; end of wladx repeat directive.


       

       ret


; --------------------------------------------------------------
; holes.

holey2   ld c,a              ; save hpos in C
       .rept 5             ; wladx: Repeat code four times.
       ld a,c              ; load hpos into A
       ld b,5             ; loop: Repeat four times.
-      ld (hl),a           ; write value too buffer at address.
       inc hl              ; skip over the char code byte.
       inc hl              ; point to next hpos byte in buffer.
       add a,8             ; add 8 (a tile's width in pixels).
       djnz -              ; jump back
       .endr               ; end of wladx repeat directive.
       ret

; --------------------------------------------------------------
holex2  ld c,a              ; save hpos in C
       .rept 4             ; wladx: Repeat code four times.
       ld a,c              ; load hpos into A
       ld b,4             ; loop: Repeat four times.
-      ld (hl),a           ; write value too buffer at address.
       inc hl              ; skip over the char code byte.
       inc hl              ; point to next hpos byte in buffer.
       add a,0             ; add 8 (a tile's width in pixels).
       djnz -              ; jump back
       .endr               ; end of wladx repeat directive.
       ret
; --------------------------------------------------------------
; CAR Y TO SPRITES' VERTICAL POSITIONS (VPOS) IN BUFFER.
; Generate vpos sat buffer data from a car's y position.
; A = car's y (i.e. ply), HL = buffer address of car vpos.

cary   ld c,a              ; save hpos in C
       .rept 4             ; wladx: Repeat code four times.
       ld a,c              ; load hpos into A
       ld b,4             ; loop: Repeat four times.
-      ld (hl),a           ; write value too buffer at address.
       inc hl              ; skip over the char code byte.
       inc hl              ; point to next hpos byte in buffer.
       add a,8             ; add 8 (a tile's width in pixels).
       djnz -              ; jump back
       .endr               ; end of wladx repeat directive.
       ret

; --------------------------------------------------------------
; CAR X TO SPRITES' HORIZONTAL POSITIONS (HPOS) IN BUFFER.
; Generates hpos sat buffer data from a car's x position.
; A = car's x (i.e. plx), HL = buffer address of car hpos.

carx   ld c,a              ; save hpos in C
       .rept 3             ; wladx: Repeat code four times.
       ld a,c              ; load hpos into A
       ld b,3             ; loop: Repeat four times.
-      ld (hl),a           ; write value too buffer at address.
       inc hl              ; skip over the char code byte.
       inc hl              ; point to next hpos byte in buffer.
       add a,0             ; add 8 (a tile's width in pixels).
       djnz -              ; jump back
       .endr               ; end of wladx repeat directive.
       ret


; SET CLOUD SPRITES' CHARACTER CODES (CC)
; HL = pointer to 16 byte char codes block, DE = buffer index.

cloud1cc ld bc,16
-      ldi
       inc de
       ld a,b
       or c
       jp nz,-
       ret
; --------------------------------------------------------------

; --------------------------------------------------------------
; SET CAR SPRITES' CHARACTER CODES (CC)
; HL = pointer to 16 byte char codes block, DE = buffer index.

carcc ld bc,16
-      ldi
       inc de
       ld a,b
       or c
       jp nz,-
       ret
; --------------------------------------------------------------
; GET KEYS.
; Read player 1 keys (port $dc) into ram mirror (input).

getkey in a,$dc            ; read player 1 input port $dc.
       ld (input),a        ; let variable mirror port status.
       ret

; --------------------------------------------------------------
; SET VDP REGISTER.
; Write to target register.
; A = byte to be loaded into vdp register.
; B = target register 0-10.

setreg out ($bf),a         ; output command word 1/2.
       ld a,$80
       or b
       out ($bf),a         ; output command word 2/2.
       ret
; --------------------------------------------------------------
; Wait for vertical blanking phase.
wait   ld a,(iflag)        ; load frame interrupt flag.
       or a                ; is it set?
       jp z,wait           ; no? - keep looping.
       xor a               ; else - reset flag.
       ld (iflag),a
       ret                 ; return.
; --------------------------------------------------------------
; MEMORY FILL.
; HL = base address, BC = area size, A = fill byte.

mfill  ld (hl),a           ; load filler byte to base address.
       ld d,h              ; make DE = HL.
       ld e,l
       inc de              ; increment DE to HL + 1.
       dec bc              ; decrement counter.
       ld a,b              ; was BC = 0001 to begin with?
       or c
       ret z               ; yes - then just return.
       ldir                ; else - write filler byte BC times,
                           ; while incrementing DE and HL...
       ret

; --------------------------------------------------------------
; DATA
; --------------------------------------------------------------
; Initial values for the 11 vdp registers.

regdat .db %00000110       ; reg. 0, display and interrupt mode.
                           ; bit 4 = line interrupt (disabled).
                           ; 5 = blank left column (disabled).
                           ; 6 = hori. scroll inhibit (disabled).
                           ; 7 = vert. scroll inhibit (disabled).

       .db %10100001       ; reg. 1, display and interrupt mode.
                           ; bit 0 = zoomed sprites (enabled).
                           ; 1 = 8 x 16 sprites (disabled).
                           ; 5 = frame interrupt (enabled).
                           ; 6 = display (blanked).

       .db $ff             ; reg. 2, name table address.
                           ; $ff = name table at $3800.

       .db $ff             ; reg. 3, n.a.
                           ; always set it to $ff.

       .db $ff             ; reg. 4, n.a.
                           ; always set it to $ff.

       .db $ff             ; reg. 5, sprite attribute table.
                           ; $ff = sprite attrib. table at $3F00.

       .db $ff             ; reg. 6, sprite tile address.
                           ; $ff = sprite tiles in bank 2.

       .db %11110011       ; reg. 7, border color.
                           ; set to color 3 in bank 2.

       .db $00             ; reg. 8, horizontal scroll value = 0.

       .db $00             ; reg. 9, vertical scroll value = 0.

       .db $ff             ; reg. 10, raster line interrupt.
                           ; turn off line int. requests.

; Charcodes for player, enemy and invisible car.



bgpal  .include "filestouse\background (palette).inc"
bgtile .include "filestouse\background (tiles)2.inc"
bgmap  .include "filestouse\background (tilemap)2.inc"

level1bgtile .include "filestouse\level1bg (tiles).inc"
level1bgmap  .include "filestouse\level1bg (tilemap).inc"

; Sprite assets. The plrcar one is all screwed up but works perfectly.
plrcar .dw $0000
       .dw $0102
       .dw $0103
       .dw $0104
       .dw $0101

plrhole2 .dw $0920
         .dw $0921
         .dw $0922
         .dw $0923
         .dw $0924


plrhole .dw $0910
       .dw $0911
       .dw $0912
       .dw $0913
       .dw $0914


plpal  .include "filestouse\background (palette).inc"
pltile1 .include "filestouse\player (ingametiles1).inc"
pltile2 .include "filestouse\player (ingametiles2).inc"
holetile .include "filestouse\hole (tilemap).inc"
cloudtile .include "filestouse\cloud (tilemap).inc"
cloudtile2 .include "filestouse\cloud (tilemap)2.inc"
bananatile .include "filestouse\banana (tilemap).inc"
bananatile2 .include "filestouse\banana (tilemap)2.inc"
titune .incbin "filestouse\jumping5.psg"
.include "filestouse\PSGlib.inc"