ZX81 Listing for run3ml.asm


ZX81 assembly listing for **RUN 3 ML*SLR/2022**

ZX81 Assembly Program Listing

**RUN 3 ML*SLR/2022** (run3ml.asm)


;
; Run 3 ML
; v1.03 Steven Reid (c) 2022
;
; A simple little running animation and moving sky.
;
; 1.00 -  2/16/2022 - Initial build.
; 1.01 -  3/19/2022 - Added pixel movement with more skys.
; 1.02 -  3/20/2022 - Adding in some objects. Too slow.
; 1.03 -  4/30/2022 - Added movement to coins with score.
;

; +++
;
; Header and startup
;

        ; start up stuff
        org 16514               ; stored in REM at top (ZX81)
        jr start                ; needed for z80asm

; title and copyright (will show on listing)
copy:
        db $17,$17,$37,$3a,$33,$00,$1f,$00,$32,$31
        db $17,$38,$31,$37,$18,$1e,$1c,$1e,$1e,$17
        db $17,$76  ; **RUN ML***SLR/2022**

start:
        call slow               ; SLOW is required.

; end header and startup
;
; ---


; +++
;
; Main Loop
;

mainloop:

        ; reset variables
        xor a                   ; ld a,0
        ld (runframe),a         ; reset run frame
        ld (skycopy),a          ; reset sky copy time
        inc a                   ; ld a,1
        ld (skyframe),a         ; reset sky frame
        ld (worldnum),a         ; reset world number
        ld (worldframe),a       ; reset world frame
        ld a,5
        ld (scoreframe),a       ; reset score frame
        ld hl,skybuf0upper      ; clear buffers
        ld bc,320
clearskyloop:
        ld (hl),$00
        inc hl
        dec bc
        ld a,b                  ; test 16-bit counter
        or c
        jr nz,clearskyloop

        ; print static elements
        call cls

        ld bc,$0302             ; head
        call printat
        ld a,$80
        rst $10

        ld bc,$0700             ; floor
        call printat
        ld b,32
        ld a,3
floorlp:
        rst $10
        djnz floorlp

animate:

        ; deal with runner
        ld hl,runner
        ld (runframe),hl
        ld b,4
runloop:
        push bc
        call printrunner
        call printsky
;        call printscore
;        call printbox
        call printcoins

        ld hl,50
        call newpause

        pop bc
        djnz runloop

        jp animate

; End of loop!
;

; +++
;
; Routines
;

printrunner:
        ld b,4                  ; load position
        ld c,1
        call printrunrow
        call printrunrow
        call printrunrow
        ret

printrunrow:
        push bc
        call printat            ; print location
        ld hl,(runframe)        ; load run location
        ld b,3                  ; print row
printrunrowlp:
        ld a,(hl)
        rst $10
        inc hl
        djnz printrunrowlp

        ld (runframe),hl        ; save next row
        pop bc
        inc b                   ; move down a row
        ret

printbox:
        ld bc,$0519
        call printat
        ld hl,boxtop
        call print
        ld bc,$0618
        call printat
        ld hl,boxbottom
        jp print

boxtop:         db $b1,$ff
boxbottom:      db $b1,$b1,$b1,$ff 

printscore:
;        ; since we don't have movement yet, clear score area
;        ld a,3
;        ld bc,$0204
;blankloop:
;        push af
;        push bc
;        call printat
;        ld hl,blank
;        call print
;        pop bc
;        inc b
;        pop af
;        dec a
;        jr nz,blankloop

        ld a,(scoreframe)
        dec a
        cp 1
        jr z,scoreframe1
        cp 2
        jr z,scoreframe2
        cp 3
        jr z,scoreframe3
        cp 4
        jr z,scoreframe4
        ; no frame, reset counter
        ld a,5                  ; reset scoreframe and return
        ld hl,defcoinxy
        ld (coinxy),hl
        ld bc,$0204
        jp printblank

scoreframe4:
        ld bc,$0304
        call printblank
        ld bc,$0404
        ld hl,score20_1
        jr printscoreframe
scoreframe3:
        ld bc,$0404
        call printblank
        ld bc,$0405
        ld hl,score20_1
        jr printscoreframe
scoreframe2:
        ld bc,$0404
        call printblank
        ld bc,$0305
        ld hl,score20_2
        jr printscoreframe
scoreframe1:
        ld bc,$0304
        call printblank
        ld bc,$0206
        ld hl,score20_2

printblank:
        ld (scoreframe),a
        ld hl,blank
printscoreframe:
        push hl
        call printat
        pop hl
        jp print

scoreframe:     db 0
score20_1:      db $95,$9e,$9c,$ff
score20_2:      db $15,$1e,$1c,$ff
blank:          db $00,$00,$00,$00,$00,$ff

defcoinxy:      equ     $031a
coinxy:         dw $031a

printcoins:
        ld bc,(coinxy)
        dec c                   ; move right
        ld a,c
        cp 3
        jr nz, printcoin
        jp printscore

printcoin:
;        ld bc,$0310
        ld (coinxy),bc
        call printat

        ld hl,coinsrot0
        ld a,(skyframe)
        and a                   ; is a 0?
        jr nz,printcoinstring
        ld hl,coinsrot1
printcoinstring:
        jp print

coinsrot0:      db $34,$00,$34,$00,$34,$00,$ff
coinsrot1:      db $2e,$00,$2e,$00,$2e,$00,$ff

; this is the new routine
printsky:
        ld a,(skycopy)
        and a                   ; is a 0?
        jr nz,getskyframe       ; no

        ; yes, copy in screen
        call copysky            ; copy sky into buffer
        ld a,80                 ; and reset sky counter (double due to frames)

getskyframe:
        dec a                   ; decrement a
        ld (skycopy),a          ; and save it
        ld a,(skyframe)         ; get sky frame (0 or 1)
        xor 1                   ; flip it (0 to 1, 1 to 0)
        ld (skyframe),a         ; and save it!
        and a                   ; is it 0?
        jr nz,printskyframe1
printskyframe0:                 ; print sky from buffer 0
        ld hl,skybuf0upper
        call shiftsky
        ld hl,skybuf0lower
        call shiftsky

        ; trying to poke screen instead of print it
        ld hl,skybuf0upper
        ld de,(d_file)
        inc de                  ; set to 0,0 of screen (1st row)
        ld bc,32                ; 32 characters to copy
        ldir                    ; copy row into screen

        ld hl,skybuf0lower
        inc de                  ; set to 1,0 of screen (2nd row)
        ld bc,32                ; 32 characters to copy
        ldir                    ; copy row into screen

        ret

;        ld bc,$0000
;        call printat
;        ld hl,skybuf0upper
;        call printskyrow

;        ld bc,$0100
;        call printat
;        ld hl,skybuf0lower
;        jp printskyrow

printskyframe1:                 ; print sky from buffer 1
        ld hl,skybuf1upper
        call shiftsky
        ld hl,skybuf1lower
        call shiftsky

        ; trying to poke screen instead of print it
        ld hl,skybuf1upper
        ld de,(d_file)
        inc de                  ; set to 0,0 of screen (1st row)
        ld bc,32                ; 32 characters to copy
        ldir                    ; copy row into screen

        ld hl,skybuf1lower
        inc de                  ; set to 1,0 of screen (2nd row)
        ld bc,32                ; 32 characters to copy
        ldir                    ; copy row into screen

        ret

;        ld bc,$0000
;        call printat
;        ld hl,skybuf1upper
;        call printskyrow

;        ld bc,$0100
;        call printat
;        ld hl,skybuf1lower
;        jp printskyrow

; old routine...
printskyrow:
        ld b,32
printskyrowlp:
        ld a,(hl)
        rst $10
        inc hl
        djnz printskyrowlp
        ret

shiftsky:
        ld a,(hl)       ; grab first character
        ld d,h          ; load hl into de
        ld e,l
        inc hl
        ld bc,79
        ldir            ; shift line to the left
        ld (de),a       ; replace last char with first
        ret

; copy sky (hl) into sky buffer (de)
copysky:
        ; first, check routines
        ld a,(worldframe)       ; get which frame of world we are on
        dec a
        jr nz,saveworldframe    ; not zero, keep going

        ; is zero, update world
        ld hl,(world)           ; load in world
        ld bc,10                ; skip transition and 4 addresses (10 bytes)
        add hl,bc               ; set new world address
        ld (world),hl           ; and then save it

        ld a,(worldnum)         ; check world number
        dec a
        jr nz,getnextworld      ; not zero, get next world
        ; is zero, reset worlds
        ld hl,worlds
        ld (world),hl           ; set address to world start
        ld a,numworlds          ; reset world number

getnextworld:
        ld (worldnum),a         ; save new world number

        ld hl,(world)           ; load in new sky

        ld e,(hl)               ; sky upper frame 0
        inc hl
        ld d,(hl)
        inc hl
        ex de,hl
        ld (skyupper0),hl
        ex de,hl

        ld e,(hl)               ; sky lower frame 0
        inc hl
        ld d,(hl)
        inc hl
        ex de,hl
        ld (skylower0),hl
        ex de,hl

        ld e,(hl)               ; sky upper frame 1
        inc hl
        ld d,(hl)
        inc hl
        ex de,hl
        ld (skyupper1),hl
        ex de,hl

        ld e,(hl)               ; sky lower frame 1
        inc hl
        ld d,(hl)
        inc hl
        ex de,hl
        ld (skylower1),hl
        ex de,hl

        ; okay, copy in transition
        ld e,(hl)               ; get upper transition byte
        inc hl
        ld d,(hl)               ; get lower transition byte

        ld hl,skybuf1uppertrans
        ld (hl),e               ; set upper transition

        ld hl,skybuf1lowertrans
        ld (hl),d               ; set lower transition

        ld a,worldrepeat        ; reset world frame

saveworldframe:
        ld (worldframe),a

        ld hl,(skyupper0)
        ld de,skybuf0uppercopy
        ld bc,40        ; 40 characters to copy
        ldir
        ld hl,(skylower0)
        ld de,skybuf0lowercopy
        ld bc,40        ; 40 characters to copy
        ldir
        ld hl,(skyupper1)
        ld de,skybuf1uppercopy
        ld bc,40        ; 40 characters to copy
        ldir
        ld hl,(skylower1)
        ld de,skybuf1lowercopy
        ld bc,40        ; 40 characters to copy
        ldir            ; shift line to the left
        ret

;
; Print string at HL
; stops when reaches $FF
;
print:
        ld a,(hl)               ; load character
        inc hl                  ; increment memory
        cp $ff                  ; last character?
        ret z                   ; yep, return
        rst $10                 ; nope, print it!
        jr print                ; loop

;
; Delay
;
; set bc to speed
; press space to 

pframe: dw $0000
newpause:
        ld (pframe),hl

        call kscan              ; get key press
        inc l
        jr z,lppause            ; not yet loop
        dec l
        ld b,h
        ld c,l
        call findchar           ; yep, grab character pressed
        ld a,(hl)

        push af
        call wait
        pop af

        and a                   ; pressed space (break)
        jp z,stop               ; stop!
        ret                     ; or return!

        ; loop!
lppause:
        ld hl,(pframe)
        dec hl
        ld a,h
        or l
        jr nz,newpause          ; not zero, keep going!

        ret                     ; pause is done!

wait:   call kscan              ; Wait for human to take finger off of key.
        inc l
        jr nz,wait
        ret

; +++
;
; Data and Defines
;

; ZX81 system vars
d_file:         equ $400c
d_fcc:          equ 16398
frames:         equ 16436

; ZX81 ROM functions
kscan:          equ $02bb
findchar:       equ $07bd
stop:           equ $0cdc
slow:           equ $0f2b
fast:           equ $02e7
save:           equ $02f9
printat:        equ $08f5
pause:          equ $0f35
cls:            equ $0a2a

; end defines
; ---

; +++
; Data
;

;
; constants
;
worldrepeat:    equ 2   ; repeate each world's sky 10 times
numworlds:      equ 4   ; currently two worlds

;
; vars
;

runframe:       dw 0    ; runner frame to display (0-3)
skyframe:       db 0    ; sky frame to display (0-1)
skycopy:        db 0    ; time to copy in sky
world:          dw 0    ; world we are on
worldnum:       db 0    ; at first world
worldframe:     db 0    ; frames to display

; these determe sky to use
skyupper0:       dw 0
skylower0:       dw 0
skyupper1:       dw 0
skylower1:       dw 0

worlds:
        dw skyupper0_cloudy
        dw skylower0_cloudy
        dw skyupper1_cloudy
        dw skylower1_cloudy
        db $00,$00      ; transition from day
        dw skyupper0_mountain
        dw skylower0_mountain
        dw skyupper1_mountain
        dw skylower1_mountain
        db $00,$87      ; transition from cloudy
        dw skyupper0_dark
        dw skylower0_dark
        dw skyupper1_dark
        dw skylower1_dark
        db $85,$85      ; transition from mountain
        dw skyupper0_day
        dw skylower0_day
        dw skyupper1_day
        dw skylower1_day
        db $05,$05      ; transition from dark

;
; runner
;

runner:
        db $87, $82, $04, $01, $05, $00, $06, $02, $04
        db $87, $82, $00, $02, $05, $01, $87, $84, $00
        db $87, $82, $00, $00, $07, $00, $00, $07, $00
        db $87, $82, $00, $02, $05, $01, $87, $84, $00
;
; sky
;

skyupper0_cloudy:
        db $00, $00, $01, $03, $80, $07, $01, $01, $00, $00
        db $00, $00, $83, $00, $00, $87, $07, $04, $00, $00
        db $83, $00, $00, $00, $00, $00, $87, $07, $04, $00
        db $87, $04, $00, $00, $00, $00, $00, $87, $07, $04
skylower0_cloudy:
        db $00, $00, $87, $01, $87, $00, $86, $00, $00, $00
        db $83, $81, $82, $01, $03, $03, $03, $00, $87, $81
        db $82, $01, $00, $00, $00, $02, $03, $03, $87, $83
        db $80, $06, $00, $00, $00, $00, $03, $03, $03, $00
skyupper1_cloudy:
        db $00, $02, $02, $84, $80, $03, $02, $00, $00, $00
        db $00, $87, $04, $00, $00, $81, $86, $00, $00, $87
        db $04, $00, $00, $00, $00, $00, $81, $86, $00, $00
        db $83, $00, $00, $00, $00, $00, $00, $81, $86, $00
skylower1_cloudy:
        db $00, $00, $06, $00, $04, $02, $04, $00, $00, $87
        db $83, $80, $06, $02, $03, $03, $01, $00, $83, $80
        db $06, $00, $00, $00, $00, $03, $03, $01, $83, $81
        db $82, $01, $00, $00, $00, $02, $03, $03, $01, $00
; old cloud sky
;skyupper0_cloudy:
;        db $00, $00, $00, $00, $00, $00, $00, $00, $00, $00
;        db $83, $00, $00, $87, $07, $04, $00, $00, $00, $00
;        db $00, $02, $04, $02, $00, $06, $00, $00, $00, $00
;        db $00, $00, $00, $00, $00, $00, $00, $87, $07, $04
;skylower0_cloudy:
;        db $00, $00, $00, $00, $00, $00, $00, $00, $83, $81
;        db $82, $01, $03, $03, $03, $00, $00, $00, $00, $00
;        db $00, $04, $83, $80, $82, $04, $04, $00, $00, $00
;        db $00, $00, $00, $00, $00, $00, $03, $03, $03, $00
;skyupper1_cloudy:
;        db $00, $00, $00, $00, $00, $00, $00, $00, $00, $87
;        db $04, $00, $00, $81, $86, $00, $00, $00, $00, $00
;        db $00, $86, $00, $01, $87, $01, $00, $00, $00, $00
;        db $00, $00, $00, $00, $00, $00, $00, $81, $86, $00
;skylower1_cloudy:
;        db $00, $00, $00, $00, $00, $00, $00, $87, $83, $80
;        db $06, $02, $03, $03, $01, $00, $00, $00, $00, $00
;        db $87, $87, $81, $80, $83, $87, $00, $00, $00, $00
;        db $00, $00, $00, $00, $00, $02, $03, $03, $01, $00

skyupper0_mountain:
        db $00, $06, $83, $00, $02, $04, $00, $01, $00, $06
        db $00, $87, $06, $86, $04, $87, $86, $00, $00, $06
        db $86, $00, $87, $86, $87, $86, $00, $00, $87, $87
        db $03, $04, $00, $00, $87, $03, $83, $87, $04, $00
skylower0_mountain:
        db $06, $00, $00, $03, $83, $87, $81, $80, $83, $87
        db $06, $01, $00, $00, $02, $86, $04, $86, $06, $00
        db $00, $86, $01, $00, $86, $00, $86, $87, $01, $86
        db $00, $85, $00, $87, $01, $00, $87, $01, $02, $04
skyupper1_mountain:
        db $87, $86, $04, $00, $86, $00, $02, $00, $87, $01
        db $00, $83, $03, $83, $00, $06, $04, $00, $87, $03
        db $04, $00, $06, $04, $06, $04, $00, $00, $04, $06
        db $86, $00, $00, $00, $06, $86, $04, $83, $00, $00
skylower1_mountain:
        db $01, $00, $02, $86, $04, $83, $80, $82, $04, $83
        db $03, $00, $00, $00, $03, $83, $02, $83, $01, $00
        db $02, $06, $00, $02, $04, $02, $04, $06, $02, $04
        db $00, $05, $00, $06, $00, $00, $06, $00, $86, $87

skyupper0_dark:
        db $80, $84, $80, $07, $80, $07, $87, $02, $80, $80
        db $03, $80, $80, $84, $80, $07, $80, $80, $80, $80
        db $03, $07, $01, $83, $80, $07, $84, $80, $80, $80
        db $82, $80, $84, $80, $07, $01, $83, $07, $84, $80
skylower0_dark:
        db $80, $80, $81, $80, $80, $00, $01, $04, $85, $83
        db $81, $80, $81, $80, $80, $80, $80, $81, $80, $83
        db $81, $80, $80, $80, $83, $83, $80, $80, $81, $07
        db $80, $80, $80, $81, $80, $80, $82, $83, $80, $84
skyupper1_dark:
        db $07, $80, $80, $84, $80, $01, $04, $84, $80, $07
        db $84, $80, $07, $80, $80, $84, $80, $80, $80, $07
        db $84, $03, $87, $81, $80, $03, $80, $80, $80, $80
        db $81, $07, $80, $80, $03, $87, $81, $03, $80, $80
skylower1_dark:
        db $80, $82, $80, $80, $05, $02, $87, $00, $82, $83
        db $80, $82, $80, $80, $80, $80, $82, $80, $82, $83
        db $80, $80, $80, $82, $83, $81, $80, $82, $80, $84
        db $80, $80, $82, $80, $80, $80, $83, $81, $07, $80

skyupper0_day:
        db $00, $00, $00, $02, $04, $00, $02, $00, $00, $06
        db $00, $00, $00, $00, $00, $87, $81, $03, $00, $83
        db $83, $00, $00, $00, $00, $87, $81, $01, $00, $87
        db $83, $00, $00, $00, $00, $00, $03, $84, $83, $04
skylower0_day:
        db $00, $00, $87, $83, $00, $83, $80, $82, $04, $87
        db $83, $00, $00, $00, $00, $00, $00, $02, $03, $01
        db $00, $00, $00, $03, $84, $83, $00, $00, $02, $03
        db $00, $00, $00, $87, $83, $81, $03, $00, $00, $00
skyupper1_day:
        db $00, $00, $00, $86, $00, $00, $01, $00, $87, $01
        db $00, $00, $00, $00, $00, $83, $07, $01, $87, $83
        db $04, $00, $00, $00, $00, $83, $07, $00, $00, $83
        db $04, $00, $00, $00, $00, $02, $03, $82, $83, $00
skylower1_day:
        db $00, $00, $83, $04, $87, $81, $80, $83, $00, $83
        db $04, $00, $00, $00, $00, $00, $00, $03, $03, $00
        db $00, $00, $02, $03, $82, $04, $00, $00, $03, $01
        db $00, $00, $00, $83, $83, $07, $01, $00, $00, $00

;
; Buffers
;

skybuf0upper:
        db $00, $00, $00, $00, $00, $00, $00, $00, $00, $00
        db $00, $00, $00, $00, $00, $00, $00, $00, $00, $00
        db $00, $00, $00, $00, $00, $00, $00, $00, $00, $00
        db $00, $00, $00, $00, $00, $00, $00, $00, $00, $00
skybuf0uppercopy:
        db $00, $00, $00, $00, $00, $00, $00, $00, $00, $00
        db $00, $00, $00, $00, $00, $00, $00, $00, $00, $00
        db $00, $00, $00, $00, $00, $00, $00, $00, $00, $00
        db $00, $00, $00, $00, $00, $00, $00, $00, $00, $00
skybuf0lower:
        db $00, $00, $00, $00, $00, $00, $00, $00, $00, $00
        db $00, $00, $00, $00, $00, $00, $00, $00, $00, $00
        db $00, $00, $00, $00, $00, $00, $00, $00, $00, $00
        db $00, $00, $00, $00, $00, $00, $00, $00, $00, $00
skybuf0lowercopy:
        db $00, $00, $00, $00, $00, $00, $00, $00, $00, $00
        db $00, $00, $00, $00, $00, $00, $00, $00, $00, $00
        db $00, $00, $00, $00, $00, $00, $00, $00, $00, $00
        db $00, $00, $00, $00, $00, $00, $00, $00, $00, $00

skybuf1upper:
        db $00, $00, $00, $00, $00, $00, $00, $00, $00, $00
        db $00, $00, $00, $00, $00, $00, $00, $00, $00, $00
        db $00, $00, $00, $00, $00, $00, $00, $00, $00, $00
        db $00, $00, $00, $00, $00, $00, $00, $00, $00
skybuf1uppertrans:
        db $00
skybuf1uppercopy:
        db $00, $00, $00, $00, $00, $00, $00, $00, $00, $00
        db $00, $00, $00, $00, $00, $00, $00, $00, $00, $00
        db $00, $00, $00, $00, $00, $00, $00, $00, $00, $00
        db $00, $00, $00, $00, $00, $00, $00, $00, $00, $00
skybuf1lower:
        db $00, $00, $00, $00, $00, $00, $00, $00, $00, $00
        db $00, $00, $00, $00, $00, $00, $00, $00, $00, $00
        db $00, $00, $00, $00, $00, $00, $00, $00, $00, $00
        db $00, $00, $00, $00, $00, $00, $00, $00, $00
skybuf1lowertrans:
        db $00
skybuf1lowercopy:
        db $00, $00, $00, $00, $00, $00, $00, $00, $00, $00
        db $00, $00, $00, $00, $00, $00, $00, $00, $00, $00
        db $00, $00, $00, $00, $00, $00, $00, $00, $00, $00
        db $00, $00, $00, $00, $00, $00, $00, $00, $00, $00

; end data
; ---