;Use the Color/BW switch to switch between PAL/NTSC. processor 6502 include vcs.h include macro.h ;FPS = 50 or 60 ;PAL = 0 or 1 #if FPS==50 ;PAL VBLNK equ 48 LINES equ 228 OVERSCN equ 36 #else ;NTSC VBLNK equ 40 LINES equ 192 OVERSCN equ 30 #endif PALPAD equ (228-2*PLAYFIELDH)/2 NTSCPAD equ (192-2*PLAYFIELDH)/2-7 VBLNK64 equ VBLNK*19/16-1 ;value to set TIM64 to for VBLNK OVERS64 equ OVERSCN*19/16 ;ditto for overscan BLH equ 2 PLAYFIELDH equ 80 ;height in kernel lines ;RAM SEG.U VARS org $80 frame ds 1 temp ds 2 p0y ds 1 p1y ds 1 p0h ds 1 p1h ds 1 p0pow ds 1 p1pow ds 1 mxl ds 2 ;missile Xs lo mxh ds 2 ;missile Xs hi mvl ds 2 ;missile velocities lo mvh ds 2 ;missile velocities hi m0y ds 1 m1y ds 1 blx ds 2 bly ds 2 blvx ds 2 blvy ds 2 ;state: ; ; ; ;b7 = holding missile p0state ds 1 p1state ds 1 p0score ds 1 p1score ds 1 paddle0 ds 1 paddle1 ds 1 gameover ds 1 ptr ds 2 rand ds 1 echo "RAM:", ($100 - *), "bytes left" ;ROM SEG CODE org $1000 include utils.asm ScoreMask .byte %00000000 .byte %00000001 .byte %00000101 .byte %00010101 .byte %01010101 PlayerXs .byte 12 .byte 152 PlayerMissileXs ;"home column" .byte 5 .byte 157 ButtonMasks .byte #$80 .byte #$40 Noises .byte 1 .byte 3 PlayBounce lda #8 sta AUDF0 lda #4 sta AUDC0 lda #3 sta AUDF0 rts ResetSpeeds .byte $02 .byte $FE ResetBall lda rand lsr lsr and #1 tax lda ResetSpeeds,X sta blvx+1 sta blvy+1 lda #80 sta blx+1 lda rand and #63 clc adc #(PLAYFIELDH-64)/2 sta bly+1 rts ;makes 16-bit @ (ptr) negative MakeNegative sty temp ldy #1 lda (ptr),Y bmi SignCorrect bpl Invert ;makes 16-bit @ (ptr) positive MakePositive sty temp ldy #1 lda (ptr),Y bpl SignCorrect Invert lda #0 sec ldy #0 sbc (ptr),Y sta (ptr),Y iny lda #0 sbc (ptr),Y sta (ptr),Y SignCorrect ldy temp rts Start CLEAN_START lda #$80 sta p0state sta p1state lda #4 sta p0pow lda #<-4 sta p1pow jsr ResetBall MainLoop VERTICAL_SYNC lda #VBLNK64 sta TIM64T inc frame txa rol adc rand rol adc frame sta rand lda #$9E sta COLUPF ;bright blue lda #$64 sta COLUP0 ;red lda #$54 sta COLUP1 ;green lda gameover beq NormalLogic ;freeze until gameover == 0 ;varying frequency lda frame sta AUDF0 sta AUDF1 sta AUDV0 sta AUDV1 sta HMCLR lda PlayerMissileXs sta mxh ldx #2 jsr PositionObject lda PlayerMissileXs+1 sta mxh+1 ldx #3 jsr PositionObject dec gameover beq ResetPlayers GotoGameLogicEnd jmp GameLogicEnd ResetPlayers lda #$80 sta p0state sta p1state jsr ResetBall bne GotoGameLogicEnd NormalLogic ;STFU lda #0 sta AUDV0 sta AUDV1 sta AUDF0 sta AUDF1 sta AUDC0 sta AUDC1 ldy #1 SetupMissiles lda p0state,Y bpl MoveMissile lda ButtonMasks,Y bit SWCHA bne NoButton lda #0 sta p0state,Y lda p0pow,Y sta mvh,Y lda #0 sta mvl,Y beq MoveMissile NoButton ;missile held lda p0h,Y lsr clc adc p0y,Y sta m0y,Y lda #0 sta mxl,Y lda PlayerMissileXs,Y sta mxh,Y bne PositionMissile MoveMissile lda mvl,Y clc adc mxl,Y sta mxl,Y lda mvh,Y adc mxh,Y sta mxh,Y ;check whether we reached the other side ;if so, re-take hold of missile cpy #1 beq Player1OtherSide cmp PlayerMissileXs+1 bcc PositionMissile lda #$80 sta p0state bne PositionMissile Player1OtherSide cmp PlayerMissileXs beq ResetMissile1 bcs PositionMissile ResetMissile1 lda #$80 sta p1state PositionMissile tya clc adc #2 tax lda #mxh,Y jsr PositionObject ;Mx ;check if we hit the other player lda CXM0P,Y bpl NoHit tya ;eor #1 tax GameoverMan inc p0score,X ;Y = 0 or 1 lda #FPS/20*16 sta gameover lda #0 sta frame lda #8 sta AUDV0,X lda Noises,X sta AUDC0,X lda #$03 sta AUDF0,X bne FinishGameOver NoHit ;check if they missed the ball cpy #1 beq CheckBallPlayer1 ;player 0 touched it? lda CXP0FB and #$40 beq NoPlayer0BallTouching ;ball is not being touched lda #blvx sta ptr+1 jsr MakePositive jsr PlayBounce jmp FinishGameOver NoPlayer0BallTouching ;miss? ldx #1 lda blx+1 cmp PlayerMissileXs bcs FinishGameOver bcc GameoverMan CheckBallPlayer1 ;player 1 touched it? lda CXP1FB and #$40 beq NoPlayer1BallTouching ;ball is not being touched lda #blvx sta ptr+1 jsr MakeNegative jsr PlayBounce jmp FinishGameOver NoPlayer1BallTouching ;miss? ldx #0 lda blx+1 cmp PlayerMissileXs+1 bcc FinishGameOver bcs GameoverMan FinishGameOver tya tax lda PlayerXs,Y jsr PositionObject ;Px dey bmi DoneSetupMissiles jmp SetupMissiles DoneSetupMissiles ;move ball lda #blvy sta ptr+1 lda bly+1 cmp #2 bcs YNotTooLow jsr MakePositive YNotTooLow lda bly+1 cmp #PLAYFIELDH-2 bcc YNotTooHigh jsr MakeNegative YNotTooHigh lda blvx clc adc blx sta blx lda blx+1 adc blvx+1 sta blx+1 lda blvy clc adc bly sta bly lda bly+1 adc blvy+1 sta bly+1 lda blx+1 ldx #4 jsr PositionObject ;BL lda paddle0 sta p0y lda paddle1 sta p1y GameLogicEnd sta WSYNC sta HMOVE lda #16 sta p0h sta p1h ;delay P0 and ball lda #1 sta VDELBL ;strobed by write to GRP1 sta VDELP0 ;-"- lda #$10 sta CTRLPF ;2 px ball lda #$30 sta NUSIZ0 sta NUSIZ1 ;4 px missiles sta CXCLR WaitForVblankEnd lda INTIM bmi WaitForVblankEnd_Overflow bne WaitForVblankEnd WaitForVblankEnd_Overflow lda #0 ;charge paddle caps sta VBLANK ;NOTE: Don't set COLUBK before VBLANK has been turned off (above) ; Otherwise you get ugly colors for the first few lines lda SWCHB and #$08 bne PalPadTop ldx #NTSCPAD-2 .byte $0C PalPadTop ldx #PALPAD-2 PadTop sta WSYNC lda #$0E sta COLUPF ldy p0score lda ScoreMask,Y sta PF1 SLEEP 30 ldy p1score lda ScoreMask,Y sta PF1 dex bne PadTop sta WSYNC lda #$0E ;white sta COLUBK lda #0 sta PF1 sta WSYNC lda #$22 sta COLUBK ;brown ldy #PLAYFIELDH Kernel sta WSYNC lda INPT0 bpl NotCharged0 .byte $0C NotCharged0 sty paddle0 lda INPT1 bpl NotCharged1 .byte $0C NotCharged1 sty paddle1 tya sec sbc p0y bmi NoP0 cmp p0h bcs NoP0 lda #$F0 .byte $0C NoP0 lda #0 sta GRP0 tya sec sbc bly+1 bmi NoBL cmp #BLH bcs NoBL lda #2 .byte $0C NoBL lda #0 sta ENABL ;P0 and BL set up tya sec sbc p1y bmi NoP1 cmp p1h bcs NoP1 lda #$F0 .byte $0C NoP1 lda #0 sta temp cpy m0y bne NoM0 lda #2 .byte $0C NoM0 lda #0 sta temp+1 cpy m1y bne NoM1 lda #2 .byte $0C NoM1 lda #0 ;TODO: we need to improve the timing a bit here so the writes happen so that there's no artefacts sta ENAM1 lda temp sta GRP1 lda temp+1 sta ENAM0 dey bne Kernel sta WSYNC lda #$0E ;white sta COLUBK lda #0 sta ENAM0 sta ENAM1 sta ENABL sta GRP0 sta GRP1 lda SWCHB and #$08 bne PalBottomTop ldx #NTSCPAD-1 .byte $0C PalBottomTop ldx #PALPAD-1 PadBottom sta WSYNC lda #0 sta COLUBK dex bne PadBottom lda #OVERS64 sta TIM64T lda #$82 ;clear paddle caps sta VBLANK WaitForOverscanEnd lda INTIM bmi WaitForOverscanEnd_Overflow bne WaitForOverscanEnd WaitForOverscanEnd_Overflow jmp MainLoop echo "ROM:", ($1FFC - *), "bytes left" org $1FFC .word Start .word Start