processor 6502 include "vcs.h" include "macro.h" ;-------------------------- ;-- CONSTANTS ;-------------------------- ARENA_HEIGHT = 72 ;--- Arena Sprite Boundaries ARENA_LEFT = 20 ARENA_RIGHT = 133 ARENA_TOP = 72 ARENA_BOTTOM = 15 VBLANK_TIME = 45 ;--- VSYNC + VBLANK Time for TIM64T OVERSCAN_TIME = 38 ;--- OVERSCAN Time for TIM64T DISPLAY_TIME = 14 ;--- DISPLAY Time for T1024T ;-------------------------- ;-- VARIABLES ;-------------------------- SEG.U vars ORG $80 ; DoDraw Graphic Pointers Player0Ptr: ds 2 ; used for drawing player0 Player1Ptr: ds 2 ; used for drawing player1 Player0Draw: ds 1 ; used for drawing player0 Player1Draw: ds 1 ; used for drawing player1 ; Other graphics drawing pointers / data TitleColors: ds 4 Color0: ds 2 Color0Ptr: ds 2 Color1: ds 2 Color1Ptr: ds 2 ; Sprite positions ObjectX ds 2 ; x coordinate ObjectY ds 2 GameRunning ds 1 LivesDisplay: ds 5 Rand: ds 1 Rand16: ds 1 LiveColor ds 1 PlayfieldColor ds 1 Temp ds 1 ScoreDisplayRight ds 5 ScoreDisplayLeft ds 5 Frame: ds 1 Score: ds 2 ScoreTimer: ds 1 DigitOnes: ds 2 ; stored in $82-83, DigitOnes = Score, DigitOnes+1 = Score+1 DigitTens: ds 2 ; stored in $84-85, DigitTens = Score, DigitTens+1 = Score+1 EndNoise: ds 1 ScoreCounter: ds 1 RevoltMoving: ds 2 BeebotDir: ds 2 Lives: ds 1 BeginningBotPlace: ds 1 ;----------------------------- ; variables used by the bees beesOfs ds 1 ;--- offset into bee graphics (for sprite version) ;--- other bees use BALL object otherBeesX ds 1 otherBeesY ds 1 ;--- Y position of other bees otherBeesYCnt ds 1 ;--- Y counter for other bees otherBeesOfs ds 1 ;--- graphics offset for other bees BeebotSpeed ds 1 BeebotMoveTimer ds 1 BeebotMoveSeconds ds 1 SFXTimer ds 1 ;------------------ ; END OF VARIABLES ;------------------ SEG code ORG $F000 ;--------------------------------------------------------- ;------ Random number generator Random: lda Rand lsr ifconst Rand16 rol Rand16 endif bcc noeor eor #$B4 noeor sta Rand ifconst Rand16 eor Rand16 endif rts ;-------------------------------------------------------- ;------ Position Object ; ;-- reg A = X position ;-- reg X = Object# (0=P0, 1=P1, 2=M0, 3=M1, 4=BL) PosObject: sec sta WSYNC DivideLoop sbc #15 ; 2 2 - each time thru this loop takes 5 cycles, which is bcs DivideLoop ; 2 4 - the same amount of time it takes to draw 15 pixels eor #7 ; 2 6 - The EOR & ASL statements convert the remainder asl ; 2 8 - of position/15 to the value needed to fine tune asl ; 2 10 - the X position asl ; 2 12 asl ; 2 14 sta.wx HMP0,X ; 5 19 - store fine tuning of X sta RESP0,X ; 4 23 - set coarse X position of Player rts ;--------------------------------------------------- ;-- Game boots to here Reset ; Clear RAM and all TIA registers CLEAN_START ;--- Initialize some variables Reset2: lda #$1a sta LiveColor lda #$9c sta PlayfieldColor lda #1 sta GameRunning lda #$00 sta BeebotMoveSeconds lda #88 sta TitleColors+0 lda #98 sta TitleColors+1 sta Rand sta Rand16 lda #$C8 sta TitleColors+2 lda #30 sta TitleColors+3 TitleScreenLoop: lda GameRunning cmp #2 bne TitleScreen jmp Main TitleScreen: lda #$0e sta COLUBK jsr VerticalSync jsr VerticalBlank jsr Kernel jsr StartOverscan jsr Bees_buzzing_at_title_screen lda INPT4 ;--- check if player started the game bmi TitleScreenLoop StartGame: lda #$00 sta Score sta Score+1 sta COLUBK sta AUDV0 jsr VerticalSync jsr VerticalBlank jsr Kernel jsr StartOverscan lda #2 sta GameRunning lda #72 sta ObjectX+1 lda #49 sta ObjectY+1 sta COLUP1 lda #49 sta otherBeesY lda #49 sta otherBeesX Begin_a_new_Beebot: lda #1 sta BeebotSpeed sta BeebotMoveSeconds jsr Random and #3 sta BeginningBotPlace lda BeginningBotPlace cmp #0 beq Beebot_0 cmp #1 beq Beebot_1 cmp #2 beq Beebot_2 Beebot_3: ; lower left lda #10 sta ObjectX+0 lda #22 sta ObjectY+0 jmp Main Beebot_2: ; lower right lda #140 sta ObjectX+0 lda #22 sta ObjectY+0 jmp Main Beebot_1: ; upper left lda #10 sta ObjectX+0 lda #54 sta ObjectY+0 jmp Main Beebot_0: ; upper right lda #140 sta ObjectX+0 lda #54 sta ObjectY+0 Main: jsr VerticalSync jsr VerticalBlank jsr PositionObjects jsr ProcessJoystick jsr Kernel jsr StartOverscan jsr Move_Beebot lda SWCHB ; read the console switches lsr ; shift game reset to carry bcc Reset____ ; skip game reset jmp Main Reset____: jsr VerticalSync jsr VerticalBlank jsr Kernel jsr StartOverscan jmp Reset2 Bees_buzzing_at_title_screen: lda #06 sta AUDC0 sta AUDV0 jsr Random and #$0f adc #$09 sta AUDF0 ;jsr AddScoreTest rts PrepScoreForDisplay: ldx #4 PSFDloop: lda Lives ;Lives digit and #$0F sta Temp asl asl adc Temp sta Temp txa adc Temp tay lda DigitFlippedGfx,y and #$F0 sta LivesDisplay,x lda Score ; thousandths digit and #$F0 lsr lsr sta Temp lsr lsr adc Temp sta Temp txa adc Temp tay lda DigitFlippedGfx,y and #$0F sta ScoreDisplayLeft,x lda Score ;hundredths digit and #$0F sta Temp asl asl adc Temp sta Temp txa adc Temp tay lda DigitFlippedGfx,y and #$F0 ora ScoreDisplayLeft,x sta ScoreDisplayLeft,x lda Score+1 ; tenths digit and #$F0 lsr lsr sta Temp lsr lsr adc Temp sta Temp txa adc Temp tay lda DigitGfx,y and #$F0 sta ScoreDisplayRight,x lda Score+1 ;ones digit and #$0F sta Temp asl asl adc Temp sta Temp txa adc Temp tay lda DigitGfx,y and #$0F ora ScoreDisplayRight,x sta ScoreDisplayRight,x dex bpl PSFDloop rts ;---------------------------------------- ;----- Handle Vertical Sync VerticalSync: OSwait: sta WSYNC lda INTIM bpl OSwait ; wait for the timer to denote end of Overscan lda #$2 ; DGS - LoaD Accumulator with $82 so D7=1 and D1=1 ldx #VBLANK_TIME ; sta WSYNC ; Wait for SYNC (halts CPU until end of scanline) sta VSYNC ; Accumulator D1=1, turns on Vertical Sync signal sta VBLANK ; DGS - turn off video, dump paddles to ground stx TIM64T ; set timer to go off in 41 scanlines (49 * 64) / 76 sta CTRLPF ; D1=1, playfield now in SCORE mode ; lda Frame ;---------- Hmmmm, what is this suppose to do? ; and #$3f ; bne VSskip VSskip: inc Frame ; increment Frame count sta WSYNC ; Wait for Sync - halts CPU until end of 1st scanline of VSYNC lda #0 ;$30 ; sta NUSIZ0 ; set missile0 to be 1x NOT 8x sta NUSIZ1 ; set missile1 to be 1x NOT 8x sta WSYNC ; wait until end of 2nd scanline of VSYNC lda #0 ; LoaD Accumulator with 0 so D1=0 sta PF0 ; blank the playfield sta PF1 ; blank the playfield sta PF2 ; blank the playfield sta GRP0 ; blanks player0 if VDELP0 was off sta GRP1 ; blanks player0 if VDELP0 was on, player1 if VDELP1 was off sta GRP0 ; blanks player1 if VDELP1 was on sta VDELP0 ; turn off Vertical Delay sta VDELP1 ; turn off Vertical Delay sta CXCLR ; clear collision detection latches sta WSYNC ; wait until end of 3rd scanline of VSYNC sta VSYNC ; Accumulator D1=0, turns off Vertical Sync signal Sleep12: ; jsr here to sleep for 12 cycles rts ; ReTurn from Subroutine VerticalBlank: jsr Random jsr PrepScoreForDisplay AddScoreTest: ldx EndNoise inx stx EndNoise ldx EndNoise cpx #15 beq TS_Color_change rts ProcessJoystick: lda SWCHA ; fetch state of both joysticks asl ; shift A bits left, R is now in the carry bit bcs CheckLeft ; branch if joystick not held down ldy ObjectX+1 ; get the object's Y position cpy #ARENA_RIGHT ; test for right of screen beq SaveX ; save Y if we're not at the right iny ; move it down SaveX: sty ObjectX+1 ; save Y CheckLeft: asl ; shift A bits left, L is now in the carry bit bcs CheckDown ; branch if joystick not held up ldy ObjectX+1 ; get the object's Y position cpy #ARENA_LEFT ; test for top of screen beq SaveX2 ; save Y if we're not at the top dey ; move it up SaveX2: sty ObjectX+1 ; save Y CheckDown: asl ; shift A bits left, D is now in the carry bit bcs CheckUp ; branch if joystick not held down ldy ObjectY+1 ; get the object's Y position cpy #ARENA_BOTTOM ; test for bottom of screen beq SaveY ; save Y if we're not at the bottom dey ; move it down SaveY: sty ObjectY+1 ; save Y CheckUp: asl ; shift A bits left, U is now in the carry bit bcs DoneWithJoystick ; branch if joystick not held up ldy ObjectY+1 ; get the object's Y position cpy #ARENA_TOP ; test for top of screen beq SaveY2 ; save Y if we're not at the top iny ; move it up SaveY2: sty ObjectY+1 ; save Y DoneWithJoystick: rts AddOneToScore: sed ; turn on decimal mode clc lda Score+1 ; Score+1 holds the Tens and Ones digits adc #1 ; add 1 to score sta Score+1 lda Score ; Score holds the Thousands and Hundreds digits adc #0 ; add 0 to this digit, carry will inc by 1 if needed sta Score ; cld ; turn off decimal mode rts TS_Color_change: ldx #0 stx EndNoise lda TitleColors+1 sta TitleColors+0 lda TitleColors+2 sta TitleColors+1 lda TitleColors+3 sta TitleColors+2 lda TitleColors+4 sta TitleColors+3 jsr Random sta TitleColors+4 rts PositionObjects: ldx #1 ; position players 0 and 1 POloop: lda #(ARENA_HEIGHT + Beebot_HEIGHT) sec sbc ObjectY sta Player0Draw lda ObjectX,x ; get the Player's X position jsr PosObject ; set coarse X position and fine-tune amount dex ; DEcrement X bpl POloop ; Branch PLus so we position all Players ;----------------- position other bees horizontally lda otherBeesX ldx #4 ;-- other bees use ball jsr PosObject sta WSYNC ; wait for end of scanline sta HMOVE ; Tell TIA to use fine-tune values to set final X positions lda EndNoise cmp #7 bcc Frame2 ; Player0Draw = ARENA_HEIGHT + HUMAN_HEIGHT - Y_position lda #<(BeebotGFX + Beebot_HEIGHT - 1) sec sbc ObjectY+0 sta Player0Ptr lda #>(BeebotGFX + Beebot_HEIGHT - 1) sbc #0 sta Player0Ptr+1 jmp POLoop0 Frame2: ; Player0Draw = ARENA_HEIGHT + HUMAN_HEIGHT - Y_position lda #<(BeebotGFX2 + Beebot_HEIGHT - 1) sec sbc ObjectY+0 sta Player0Ptr lda #>(BeebotGFX2 + Beebot_HEIGHT - 1) sbc #0 sta Player0Ptr+1 POLoop0: ; setup other bees lda Frame lsr and #3 adc #0 sta otherBeesOfs lda #16 sbc otherBeesOfs sta otherBeesOfs ;-- setup player bee graphics offset to random # lda Rand and #7 sta (BeebotColors + Beebot_HEIGHT - 1) ; DGS33 sbc #0 ; DGS33 sta Color0Ptr+1 ; DGS33 ; Player1Draw = ARENA_HEIGHT + BOX_HEIGHT - Y_position lda #(ARENA_HEIGHT + Bees_HEIGHT) sec sbc ObjectY+1 sta Player1Draw ;--- Offset bee graphics lda ObjectY+1 sec sbc beesOfs sta beesOfs ; Set Player1Ptr to proper value for drawing player1 lda #<(BeesGFX + Bees_HEIGHT - 1) sec sbc beesOfs ;adc (BeesGFX + Bees_HEIGHT - 1) sbc #0 sta Player1Ptr+1 lda #$0e sta COLUP1 rts ;------------------------------------------------------------------------------ ;----- Beebot Move Handler MoveBeebotLeft____ jmp MoveBeebotLeft MoveBeebotRight___ jmp MoveBeebotRight Move_Beebot: lda ObjectX+0 cmp #134 bcs MoveBeebotLeft____ lda ObjectX+0 cmp #19 bcc MoveBeebotRight___ lda BeebotMoveTimer cmp BeebotSpeed beq Actually_Move_Beebot inc BeebotMoveTimer lda CXPPMM ; 3 or player/player and and #%10000000 ; 2 mask ball, M0/M0, M0/P0 collisions bne ArghWork jmp Finish_Moving_Beebot Actually_Move_Beebot: lda #1 sta BeebotMoveTimer lda RevoltMoving+0 cmp #2 bcs MoveBeebotOppositeX2 lda CXPPMM ; 3 or player/player and and #%10000000 ; 2 mask ball, M0/M0, M0/P0 collisions bne MoveBeebotOppositeX2 lda RevoltMoving+0 cmp #1 bcs MoveBeebotOppositeX lda #0 sta RevoltMoving+0 lda ObjectX+0 cmp ObjectX+1 bcc MoveBeebotLeft jmp MoveBeebotRight MoveBeebotOppositeX2: lda CXPPMM ; 3 or player/player and and #%10000000 ; 2 mask ball, M0/M0, M0/P0 collisions bne ArghWork jmp Finish_Moving_Beebot_4 ArghWork: inc BeebotMoveSeconds lda BeebotMoveSeconds cmp #32 beq IHATETHIS cmp #33 bcs IHATEHTIS jmp Finish_Moving_Beebot_3 IHATETHIS inc BeebotSpeed IHATEHTIS lda #2 sta AUDC0 sta AUDF0 inc SFXTimer lda SFXTimer cmp #7 bcs Finish_Moving_Beebot_4 lda #6 sta AUDV0 jmp Finish_Moving_Beebot_3 Finish_Moving_Beebot_4: lda #0 sta AUDV0 sta SFXTimer sta BeebotMoveSeconds Finish_Moving_Beebot_3: lda #2 sta RevoltMoving+0 lda BeebotDir+0 cmp #1 beq MoveBeebotLeft jmp MoveBeebotRight MoveBeebotOppositeX: lda #1 sta RevoltMoving+0 lda BeebotDir+0 cmp #2 beq MoveBeebotLeft MoveBeebotRight: lda #2 sta BeebotDir+0 lda ObjectX+0 cmp #ARENA_RIGHT bcs Beebot_RightBorder inc ObjectX+0 lda #0 sta REFP0 jmp Move_Beebot_y Beebot_RightBorder: lda #0 sta RevoltMoving+0 lda #1 sta BeebotDir+0 jmp Move_Beebot_y MoveBeebotLeft: lda #1 sta BeebotDir+0 lda ObjectX+0 cmp #ARENA_LEFT bcc Beebot_LeftBorder dec ObjectX+0 lda #8 sta REFP0 jmp Move_Beebot_y Beebot_LeftBorder: lda #0 sta RevoltMoving+0 lda #2 sta BeebotDir+0 jmp Move_Beebot_y Move_Beebot_y: lda RevoltMoving+1 cmp #2 bcs MoveBeebotOppositeY2 lda CXPPMM ; 3 or player/player and and #%10000000 ; 2 mask ball, M0/M0, M0/P0 collisions bne MoveBeebotOppositeY2 lda RevoltMoving+1 cmp #1 bcs MoveBeebotOppositeY lda #0 sta RevoltMoving+1 lda ObjectY+0 cmp ObjectY+1 bcc MoveBeebotUp jmp MoveBeebotDown MoveBeebotOppositeY2: lda #2 sta RevoltMoving+1 lda BeebotDir+1 cmp #1 beq MoveBeebotUp jmp MoveBeebotDown MoveBeebotOppositeY: lda #1 sta RevoltMoving+1 lda BeebotDir+1 cmp #2 beq MoveBeebotUp MoveBeebotDown: lda #2 sta BeebotDir+1 lda ObjectY+0 cmp #ARENA_TOP bcs Beebot_DownBorder inc ObjectY+0 jmp Finish_Moving_Beebot Beebot_DownBorder: lda #0 sta RevoltMoving+1 lda #1 sta BeebotDir+1 jmp Finish_Moving_Beebot MoveBeebotUp: lda #1 sta BeebotDir+1 lda ObjectY+0 cmp #ARENA_BOTTOM+1 bcc Beebot_UpBorder dec ObjectY+0 jmp Finish_Moving_Beebot Beebot_UpBorder: lda #0 sta RevoltMoving+1 lda #2 sta BeebotDir+1 Finish_Moving_Beebot: sta CXCLR lda BeebotSpeed cmp #5 bcs Score_A_Point rts Score_A_Point sleep 20 lda #200 sta ObjectY+0 lda BeebotSpeed cmp #6 bcs SkipPointAdd jsr AddOneToScore SkipPointAdd: inc BeebotSpeed lda BeebotSpeed cmp #15 beq jumpTo_New_Beebot_2 lda #6 sta AUDC0 sta AUDV0 sta AUDF0 rts jumpTo_New_Beebot_2: jmp New_Beebot_2 ;------------------------------------------------------------------------------ ;---- Main Display Kernel Kernel: jsr Random lda INTIM ; 4 4 - check the timer bne Kernel ; 2 6 - (3 7) Branch if its Not Equal to 0 sta WSYNC ; Wait for SYNC (halts CPU until end of scanline) ; turn on the display sta VBLANK ; 3 9 - Accumulator D1=0, turns off Vertical Blank signal (image output on) lda #$01 ; 2 11 sta CTRLPF ; 3 14 - turn on playfield mirroring ;-- Start the timer for the Display Kernel lda #DISPLAY_TIME sta T1024T ldx #0 ldy #ARENA_HEIGHT ;init loop counter ScoreLoop2: sta WSYNC ;--------------------------------------- lda LivesDisplay,x ; 4 4 sta PF0 ; 3 7 - update PF0 for left side of screen lda LiveColor ; 2 9 sta COLUPF ; 3 12 lda ScoreDisplayLeft,x ; 4 16 sta PF2 ; 3 19 - update PF2 for left side of screen jsr Sleep12 ;12 31 lda PlayfieldColor ; 2 33 sta COLUPF ; 3 36 SLEEP 3 ; 5 41 lda ScoreDisplayRight,x ; 4 45 sta PF2 ; 3 48 - @48 - update PF2 for right side of screen lda #0 ; 2 50 sta PF0 ; 3 53 - update PF0 for right side of screen sta WSYNC ;--------------------------------------- lda LivesDisplay,x ; 4 4 sta PF0 ; 3 7 - update PF0 for left side of screen lda LiveColor ; 2 9 sta COLUPF ; 3 12 lda ScoreDisplayLeft,x ; 4 11 sta PF2 ; 3 14 - update PF2 for left side of screen jsr Sleep12 ;12 26 lda PlayfieldColor ; 2 33 sta COLUPF ; 3 36 SLEEP 3 ; 5 41 lda ScoreDisplayRight,x ; 4 45 sta PF2 ; 3 48 - @48 - update PF2 for right side of screen lda #0 ; 2 50 sta PF0 ; 3 53 - update PF0 for right side of screen inx ; 2 55 cpx #5 ; bne ScoreLoop2 ; 3 58 Rest_of_score_stuff: ;--------------------------------------- lda #0 ; 2 2 sta PF1 sta PF2 tax ; used by Draw_MrCelery loop sta WSYNC ; 3 6 - wait for end of scanline ;--------------------------------------- lda #$00 sta COLUPF ldx GameRunning cpx #1 bne KeepGoing jmp WriteTitle KeepGoing: lda #$00 ; don't forget to close this! sta AUDV0 lda #$00 sta COLUBK lda #$D6 sta COLUPF ;-------------------------------------------------- ;---- Now draw the gameboard sta WSYNC lda #0 sta PF0 sta PF1 sta PF2 sta WSYNC ldy #19 DrawTopBeeBox: sta WSYNC lda TopBoxGfxPF2,y sta PF2 dey bpl DrawTopBeeBox ldy #4 DrawArenaTopBorder: sta WSYNC ; wait till end of scanline lda #%11111111 sta PF1 sta PF2 dey bpl DrawArenaTopBorder ;------------------------------------------------------- ;---- at this point, DRAW the main arena section ldy #ARENA_HEIGHT ;-- used as counter for Arena (playfield and sprites) MainArena: ldx #0 sta WSYNC stx HMCLR stx PF0 lda #%10000000 sta PF1 lda #%00000000 sta PF2 GameBoardLoop: ;--- enters at 29 DrawTheScreen: ;------------------------------------------------ ;-- handle other bees as missile (21 cycles) ldx otherBeesYCnt ;3 32 bne DrawOtherBees ;2 34 -- branch if we are still drawing other bees sta ENABL ;3 37 -- clear other bees cpy otherBeesY ;3 40 --- is it time to draw other bees? bne Draw_sprites_routine ;2 42 --- skip if not ;-- setup to draw other bees lda