processor 6502 include "vcs.h" include "macro.h" include "xmacro.h" ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; seg.u Variables org $80 Temp byte PlyrXPos byte ; player X position PlyrYPos byte ; player Y position TrailFrac byte ; 8-bit fractional trail position TrailPos word ; current 16-bit position along trail Speed byte ; velocity along trail Random word PF1Mask byte PF2Mask byte YP0 byte ; sprite 0 vertical counter YP1 byte ; sprite 1 vertical counter SpritePtr0 word ; sprite 0 pointer SpritePtr1 word ; sprite 1 pointer YStop byte ; temp. register NextHeight byte ; next sprite height ObsIndex byte ; current obstacle index (0-7) ; Y offset into first obstacle TrailObsYOffset byte ; next 8 bytes of trail data, starting from top of screen TrailData ds 8 ; Data for all 8 obstacle sprites ObsXpos ds 8 ObsColor ds 8 ObsPtrLo ds 8 ObsPtrHi ds 8 SpriteHeight equ 20 ; Height of all sprites TrailDisplayHeight equ 160 ; Height of trail dispaly area ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; seg Code org $f000 Start CLEAN_START lda #1 sta Random lda #70 sta PlyrXPos lda #70 sta ObsXpos+0 lda #$7f sta ObsColor+0 lda #Frame0 sta ObsPtrHi+0 lda #40 sta ObsXpos+1 lda #$68 sta ObsColor+1 lda #Frame0 sta ObsPtrHi+1 lda #60 sta ObsXpos+2 lda #$28 sta ObsColor+2 lda #Frame0 sta ObsPtrHi+2 lda #$40 sta Speed NextFrame VERTICAL_SYNC TIMER_SETUP 37 lda #150 sta YP0 lda #$ff sta PF1Mask lda #$0f sta PF2Mask lda #Frame0 sta SpritePtr0+1 lda #$ff sta COLUP0 lda PlyrXPos ldx #0 jsr SetHorizPos sta WSYNC sta HMOVE TIMER_WAIT TIMER_SETUP 192 jsr DrawTrail TIMER_WAIT TIMER_SETUP 30 jsr MoveAlongTrail TIMER_WAIT jmp NextFrame ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; Move player along the trail MoveAlongTrail subroutine lda TrailFrac sec adc Speed sta TrailFrac php lda TrailPos adc #0 sta TrailPos lda TrailPos+1 adc #0 sta TrailPos+1 plp lda TrailObsYOffset adc #0 cmp #SpriteHeight+4 bcc .NoNextObstacle ; Move obstacles up one slot ldx #6 .MoveLoop lda ObsXpos,x sta ObsXpos+1,x lda ObsColor,x sta ObsColor+1,x lda ObsPtrLo,x sta ObsPtrLo+1,x lda ObsPtrHi,x sta ObsPtrHi+1,x dex bpl .MoveLoop ; Generate new obstacle jsr NextRandom sta ObsColor and #$5f sta ObsXpos ; Reset TrailObsYOffset lda #0 .NoNextObstacle sta TrailObsYOffset rts ; Put the trail edges into the PF1 and PF2 registers. ; X = trail position lo byte MAC TRAIL_PLAYFIELD lda PF1Mask and $f000,x sta PF1 lda PF2Mask and $f100,x sta PF2 dex ENDM ; Get next bitmap byte of sprite 0 MAC DRAW_SPRITE0 sec ; ensure carry set for subtraction lda #SpriteHeight isb YP0 ; INC yp0, then SBC yp0 tay bcs .DoDraw ; outside bounds? lda #0 ; clear bitmap .byte $2c ; (BIT aaaa, skips next 2 bytes) .DoDraw lda (SpritePtr0),y ; lookup sprite bitmap sta GRP0 ; A -> GRP0 ENDM ; Draw the trail DrawTrail subroutine lda TrailObsYOffset sta NextHeight lda #$c4 sta COLUPF lda #$F0 sta PF0 lda #%0000001 sta CTRLPF ; lda #1 ; sta VDELP0 ; Set up ObsIndex (index of next obstacle to draw) ldy #0 sty ObsIndex ; Set up X register with trail position lo byte, ; which displays the scrolling "forest" mask. ; We decrement this value every scanline and when it ; hits "YStop" we are done drawing. lda TrailPos sta YStop clc adc #TrailDisplayHeight tax ; Set position of sprite .SetSpritePos sta HMCLR ; clear fine offsets DRAW_SPRITE0 ; Set up more values for sprite 1 ldy ObsIndex lda ObsPtrLo,y sta SpritePtr1 lda ObsPtrHi,y sta SpritePtr1+1 lda ObsColor,y sta COLUP1 ; Update the playfield masks ; lda PFMask1,x ; sta PFMask1 ; lda PFMask2,x ; sta PFMask2 ; Set next height lda NextHeight sta YP1 lda #SpriteHeight sta NextHeight ; Make sure grass texture is aligned dex cpx YStop beq .NoMoreObjects dex cpx YStop beq .NoMoreObjects dex cpx YStop beq .NoMoreObjects ; Redraw sprite DRAW_SPRITE0 ; Position object horizontally sta WSYNC ldy ObsIndex lda ObsXpos,y iny sty ObsIndex sec .DivideLoop sbc #15 ; subtract 15 bcs .DivideLoop ; branch until negative eor #7 asl asl asl asl sta HMP1 ; set fine offset sta RESP1 ; fix coarse position .Loop sta WSYNC ; Draw sprite 0, with skipdraw DRAW_SPRITE0 ; Draw the playfield TRAIL_PLAYFIELD ; Should we exit? cpx YStop beq .NoMoreObjects ; Draw sprite 1, no skipdraw ldy YP1 lda (SpritePtr1),y dey sty YP1 ; YP1-- sta GRP1 ; A -> GRP1 ; repeat until sprite 1 finished drawing (YP1<0) bpl .Loop ; If not out of scanlines, position next sprite and continue jmp .SetSpritePos ; Clean up playfield .NoMoreObjects lda #0 sta PF0 sta PF1 sta PF2 sta GRP0 sta GRP1 rts ; Random number generation NextRandom subroutine lda Random lsr ror Random+1 bcc .NoEor eor #$d4 .NoEor: sta Random eor Random+1 rts PrevRandom subroutine lda Random asl rol Random+1 bcc .NoEor eor #$a9 .NoEor: sta Random eor Random+1 rts SetHorizPos sta WSYNC ; start a new line sec ; set carry flag DivideLoop sbc #15 ; subtract 15 bcs DivideLoop ; branch until negative eor #7 ; calculate fine offset asl asl asl asl sta HMP0,x ; set fine offset sta RESP0,x ; fix coarse position rts ; return to caller ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; align $100 PFMask1 byte #%00000000 byte #%10000000 byte #%11000000 byte #%11100000 byte #%11110000 byte #%11111000 byte #%11111100 byte #%11111110 byte #%11111111 byte #%11111111 byte #%11111111 byte #%11111111 byte #%11111111 byte #%11111111 byte #%11111111 byte #%11111111 byte #%11111111 PFMask2 byte #%00000000 byte #%00000000 byte #%00000000 byte #%00000000 byte #%00000000 byte #%00000000 byte #%00000000 byte #%00000000 byte #%00000001 byte #%00000011 byte #%00000111 byte #%00001111 byte #%00011111 byte #%00111111 byte #%01111111 byte #%11111111 ; Bitmap data "standing" position Frame0 .byte #0 .byte #%01101100;$F6 .byte #%00101000;$86 .byte #%00101000;$86 .byte #%00111000;$86 .byte #%10111010;$C2 .byte #%10111010;$C2 .byte #%01111100;$C2 .byte #%00111000;$C2 .byte #%00111000;$16 .byte #%01000100;$16 .byte #%01111100;$16 .byte #%01111100;$18 .byte #%01010100;$18 .byte #%01111100;$18 .byte #%11111110;$F2 .byte #%00111000;$F4 .byte 0,0,0,0,0,0,0 HMoveTable hex 7060504030201000f0e0d0c0b0a09080 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; Epilogue org $fffc .word Start .word Start