[stella] Animating the Marbles

Subject: [stella] Animating the Marbles
From: Paul Slocum <paul-stella@xxxxxxxxxxxxxx>
Date: Tue, 02 Jul 2002 22:17:37 -0500
I just spent a couple of hours playing with my kernal, and I don't think it's going to be possible to animate the marbles. The problem is that there is so much going on in my kernal that I had to resort to filling zeros into the page that has my player image data. Not only that, but I couldn't even find enough time or memory to cut off the drawing of it near the top of the page, so I had to use TWO pages to represent the player image with two different offsets. So as is, I have to use 512 bytes for each player shape! Ouch! :o(

In my kernal I'm drawing two player graphics with single scanline resolution, drawing an asymetric playfield on every line, shading the playfield independently on each side, drawing a missile, and reading the paddles. So the kernal is really stacked! I actually have two separate kernals that alternate each frame to interlace the playfield shading. And I don't have any memory left either. Allowing two players at once eats up memory fast.

If I could find a way to reduce it to 256 bytes per player graphics shape, I could add at least a few different shapes. But I haven't been able to figure out a way to do it. I've pretty much conceded that I won't be able to animate the marbles, but I figured I'd post my kernal and see if anyone wants to try to squeeze a few cycles out. Kernal A has less free cycles than Kernal B, so that's the one to look at. I only found about 10 free cycles in the 13 line kernal loop (one of the WSYNCs can be removed).

-Paul
;---------------------------------------------------------------------------
; Marble Craze by Paul Slocum
;---------------------------------------------------------------------------

;------------------------------
; Marble Craze bank 1
;------------------------------
; Includes:
;
; - Game Kernal
; - Variable Initialization
; - Game Loop Logic
;------------------------------

	; LEVEL IDEAS
	; Easy wall level (1st)
	; Adventure
	; Combat
	; Easy Does It
	; Dungeon
	; Earthworld
	; Fireworld
	; Jump level
	; Intersection Puzzler
	; Get the Gems
	; Grand Prix
	; Grand Prix 2
	; Waterworld
	; Airworld
	; Video Game Characters
	; Up,Down,Right,Left Power Bars
	; Slope level
	; Slope level 2
	; Key level
	; Tightrope
	; Rainbow Road
	; Diagonal Paths
	; Warps?
	; Big open level
	; Invisible Maze (catacombs)
	; Power up extensions (get power up on each screen to extend path)

	; MUSIC IDEAS
	; Techno beat w/ arpeggiated music
	; Slower song with 2 part arpeggiated melody
	; Reverberated square song


	processor 6502	
	include vcs.h	


	;--------------------------- TODO
	;
	; Switch to 32k
	;
	; GENERALIZE LEVEL READING
	;   SLOPE DATA STRUCTURE
	; Check PF
	; 2637
	; 2666 = 47 bytes
	; Load Screen
	; 2778
	; 2837 = 191 bytes
	; Get Value = 20 bytes?
	;
	; Allow alternate songs
	;
	; Slow animation/allow turn off
	;
	; Look into modifying kernal for more animation
	;
	;--------------------------------

	;------------------------ TODO LATER
	;
	; Fall off animation/fading
	; Jump handling
	;
	; Slope handling
	;
	; Write C program to generate levels
	;
	; Stop, Up, Down etc power ups
	;	
	; Warp power ups?
	;
	; (Lives bug)?
	;
	; Add friction?
	;
	;------------------------------------
	
	;-------------------- SUGGESTIONS:
	;
	; Fat paddle center
	;
	; Friction
	;
	; Time about up indicator (sound or visual)
	;
	; Clean up respawn handling (restart sound? indicator?)
	;
	; Preview next screen
	;
	; Show ball rolling/falling off
	;
	; Track Ball control
	;
	; ------------------------------------



;---------------------------------------------------------------------------
; Constants
;---------------------------------------------------------------------------

LASTLEVEL equ 2

KERNAL_DELAY equ 8

TIMECOLOR equ $86
STATUSCOLOR equ $48
INTROCOLOR equ $8A

; Flags in level variable
ENDGAME equ %10000000
NEXTLEVEL equ %01000000
WINGAME equ %00100000

NUMBEROFLIVES equ 8

;---------------------------- status
;Status bits
FLASH equ 16
NOGAME equ 32
NOTIME equ 64
DONE equ 128

; Status
NORMAL equ 0
FALLOFF equ 1 + FLASH
RESET equ 2 + FLASH
SCREENLOAD equ 3
LOADREADY equ 6
FINISHED equ 4 + NOTIME + DONE
STARTUP equ 5 + FLASH + NOTIME
GETREADY equ 7 + FLASH + NOTIME
GAMEOVER equ 8 + NOTIME + FLASH + DONE + NOGAME
INACTIVE equ 9 + NOTIME + DONE + NOGAME
ENDLEVEL equ 10 + NOTIME ;+ SKIPLOGIC
TIMEUP equ 11 + FLASH
;--------------------------------------


;-------------------------- power ups
PWR20PTS equ 	%00000001
PWR50PTS equ 	%00000010
PWR100PTS equ 	%00000011
PWR5SEC equ 	%00000100
PWR10SEC equ 	%00000101
PWR20SEC equ 	%00000110
PWRWALLS equ 	%00000111
PWR1UP equ 		%00001000
PWRKEY equ 		%00001001

HPWR20PTS equ 	%00010000
HPWR50PTS equ 	%00100000
HPWR100PTS equ 	%00110000
HPWR5SEC equ 	%01000000
HPWR10SEC equ 	%01010000
HPWR20SEC equ 	%01100000
HPWRWALLS equ 	%01110000
HPWR1UP equ 	%10000000
HPWRKEY equ 	%10010000
;-------------------------------------

; Bankswitching
BANK1 equ $1FF6
BANK2 equ $1FF7
BANK3 equ $1FF8
BANK4 equ $1FF9


;---------------------------------------------------------------------------
; RAM Variables 
;---------------------------------------------------------------------------

playField equ $80 			; 72 bytes (12 lines * 5) + 12 color bytes


; Variables for title screen only
option equ $80
paddle equ $81
debounce equ $84
bounce equ $85
titleBlank equ $86
startGame equ $87

;------------------------------------ 8 bytes 
; 16 bit temp (overlaps with pfBuffer)
temp16L equ $C8
temp16H equ $C9

levelL equ $CA	; temp level pointer (during game logic)
levelH equ $CB

screenL equ $CC	; temp screen pointer (during game logic)
screenH equ $CD

temp equ $CE 	; two more temps (for game logic)
temp2 equ $CF

;------
pfBuffer equ $C8	; 8 bytes
;------------------------------------

pMarble equ $D0; 2 bytes
pMarble2 equ $D2; 2 bytes
pfColor equ $D4

frame equ $D5

p1x equ $D6
p2x equ $D7

p1y equ $D8
p2y equ $D9

p1xVel equ $DA
p2xVel equ $DB

p1yVel equ $DC
p2yVel equ $DD

pwr1x equ $DE
pwr2x equ $DF

pwr1y equ $E0
pwr2y equ $E1

padVal1 equ $E2
padVal3 equ $E3

padVal2 equ $E4
padVal4 equ $E5 ; 102 bytes total

level equ $E6

p1Screen equ $E7	; bit 7 = WALLS flag, bit 6 & 5 = falling count
p2Screen equ $E8	; ""

p1Status equ $E9
p2Status equ $EA

p1Counter equ $EB
p2Counter equ $EC

p1TimeL equ $ED
p2TimeL equ $EE

p1TimeH equ $EF
p2TimeH equ $F0

temp5 equ $F1

p1Lives equ $F2		; High 4 bits store power up type
p2Lives equ $F3		; High 4 bits store power up type

bkColor equ $F4

pwrArray1 equ $F5
pwrArray2 equ $F6

beat equ $F7
measure equ $F8

p1ScoreL equ $F9
p2ScoreL equ $FA

p1ScoreH equ $FB
p2ScoreH equ $FC

titleOptions equ $FD

; 126 bytes total (added titleOptions)

;-------------------------------------------------
; Temporary Game Logic Variables
;-------------------------------------------------
screen equ pMarble
player equ pMarble+1

status equ temp5

;--------------------------------------------------







; These two temp variables are in the stack area,
; and are only used during the kernal where
; the stack is not used.
temp3 equ $FE
temp4 equ $FF















;---------------------------------------------------------------------------
;---------------------------------------------------------------------------
	org $1000
;---------------------------------------------------------------------------
;---------------------------------------------------------------------------

marbleData2
	byte 0,0,0,0,0,0,0,0
	byte 0,0,0,0,0,0,0,0
	byte 0,0,0,0,0,0,0,0
	byte 0,0,0,0,0,0,0,0
	byte 0,0,0,0,0,0,0,0
	byte 0,0,0,0,0,0,0,0
	byte 0,0,0,0,0,0,0,0
	byte 0,0,0,0,0,0,0,0

	byte 0,0,0,0,0,0,0,0
	byte 0,0,0,0,0,0,0,0
	byte 0,0,0,0,0,0,0,0
	byte 0,0,0,0,0,0,0,0
	byte 0,0,0,0,0,0,0,0
	byte 0,0,0,0,0,0,0,0
	byte 0,0,0,0,0,0,0,0
	byte 0,0,0,0,0,0,0,0

	byte 0,0,0,0,0,0,0,0
	byte 0,0,0,0,0,0,0,0
	byte 0,0,0,0,0,0,0

	byte #%00111100
	byte #%01111110
	byte #%01111110
	byte #%11111111
	byte #%11111111
	byte #%11111111
	byte #%11111111
	byte #%11111111
	byte #%11111111
	byte #%01111110
	byte #%01111110
	byte #%00111100


	align 256
marbleData3
	byte 0,0,0,0,0,0,0,0
	byte 0,0,0,0,0,0,0,0
	byte 0,0,0,0,0,0,0,0
	byte 0,0,0,0,0,0,0,0
	byte 0,0,0,0,0,0,0,0
	byte 0,0,0,0,0,0,0,0
	byte 0,0,0,0,0,0,0,0
	byte 0,0,0,0,0,0,0,0

	byte 0,0,0,0,0,0,0,0
	byte 0,0,0,0,0,0,0,0
	byte 0,0,0,0,0,0,0

	byte #%00111100
	byte #%01111110
	byte #%01111110
	byte #%11111111
	byte #%11111111
	byte #%11111111
	byte #%11111111
	byte #%11111111
	byte #%11111111
	byte #%01111110
	byte #%01111110
	byte #%00111100		; total = 99 bytes

	byte 0,0,0,0,0,0,0,0
	byte 0,0,0,0,0,0,0,0
	byte 0,0,0,0,0,0,0,0
	byte 0,0,0,0,0,0,0,0
	byte 0,0,0,0,0,0,0,0
	byte 0,0,0,0,0,0,0,0
	byte 0,0,0,0,0,0,0,0
	byte 0,0,0,0,0,0,0,0



	align 256

movement
	byte #%01110001, #%01100001, #%01010001, #%01000001, #%00110001, #%00100001, #%00010001, #%00000001
	byte #%11110001, #%11100001, #%11010001, #%11000001, #%10110001, #%10100001, #%10010001

	byte #%01110010, #%01100010, #%01010010, #%01000010, #%00110010, #%00100010, #%00010010, #%00000010
	byte #%11110010, #%11100010, #%11010010, #%11000010, #%10110010, #%10100010, #%10010010

	byte #%01110011, #%01100011, #%01010011, #%01000011, #%00110011, #%00100011, #%00010011, #%00000011
	byte #%11110011, #%11100011, #%11010011, #%11000011, #%10110011, #%10100011, #%10010011

	byte #%01110100, #%01100100, #%01010100, #%01000100, #%00110100, #%00100100, #%00010100, #%00000100
	byte #%11110100, #%11100100, #%11010100, #%11000100, #%10110100, #%10100100, #%10010100

	byte #%01110101, #%01100101, #%01010101, #%01000101, #%00110101, #%00100101, #%00010101, #%00000101
	byte #%11110101, #%11100101, #%11010101, #%11000101, #%10110101, #%10100101, #%10010101

	byte #%01110110, #%01100110, #%01010110, #%01000110, #%00110110, #%00100110, #%00010110, #%00000110
	byte #%11110110, #%11100110, #%11010110, #%11000110, #%10110110, #%10100110, #%10010110

	byte #%01110111, #%01100111, #%01010111, #%01000111, #%00110111, #%00100111, #%00010111, #%00000111
	byte #%11110111, #%11100111, #%11010111, #%11000111, #%10110111, #%10100111, #%10010111

	byte #%01111000, #%01101000, #%01011000, #%01001000, #%00111000, #%00101000, #%00011000, #%00001000
	byte #%11111000, #%11101000, #%11011000, #%11001000, #%10111000, #%10101000, #%10011000

	byte #%01111001, #%01101001, #%01011001, #%01001001, #%00111001, #%00101001, #%00011001, #%00001001
	byte #%11111001, #%11101001, #%11011001, #%11001001, #%10111001, #%10101001, #%10011001

	byte #%01111010, #%01101010, #%01011010, #%01001010, #%00111010, #%00101010, #%00011010, #%00001010
	byte #%11111010, #%11101010, #%11011010, #%11001010, #%10111010, #%10101010, #%10011010



paddleDecode
	byte 0,0,0,0,0,0,1,1,1,1,1,1,1
	byte 2,2,2,2,2,2,3,3,3,3,3,3,3
	byte 4,4,4,4,4,4,5,5,5,5,5,5,5
	byte 5,5,5,5,5,5,6,6,6,6,6,6,6
	byte 6,6,6,6,6,6,7,7,7,7,7,7,7
	byte 7,7,7,7,7,7,8,8,8,8,8,8,8
	byte 8,8,8,8,8,8,8,8,8,8,8,8,8
	byte 9,9,9,9,9,9,9,9,9,9,9,9,9
	byte 10,10,10,10,10,10,10,10,10,10,10,10,10
	byte 11,11,11,11,11,11,11,11,11,11,11,11,11
	byte 12,12,12,12,12,12,12,12,12,12,12,12,12
	byte 13,13,13,13,13,13,14,14,14,14,14,14,14
	byte 15,15,15,15,15,15





;--------------------------------------------------------------------------
; Draw Screen
;--------------------------------------------------------------------------
drawScreen

	;******************* Position P0/P1 for Score ***********************

	sta HMCLR
	; Set horizontal player positions for score

	sta WSYNC
	lda #%11000000
	sta HMM0
	lda #%11010000
	sta HMM1
	nop
	lda (temp),x
	lda (temp),x
	lda temp
	sta RESP0
	lda temp
	lda (temp),x
	sta RESM0
	lda temp
	sta RESBL
	nop
	lda temp
	sta RESP1	

	lda #%00100000
	sta HMP0
	lda #%00010000
	sta HMBL
	sta RESM1
	sta WSYNC
	sta HMOVE

	lda #0
	sta COLUBK
	
	; ************** Score Draw Loop ********************

	jmp callDrawScore

rtnCallDrawScore


	; ************** Future Status and Timer (22 lines) ****************


	lda #$0F
	sta COLUPF


	; ***************** Position Game Objects *********************

	; DEBUG LIVES PROBLEM
;	lda p1Lives
;	sta PF2
;	nop	

	nop
	lda temp ; waste 3 cycles
	sta temp
	
	; Set sizes
	lda #32		;2
	sta NUSIZ1	;3
	lda #0
	sta NUSIZ0	;3


	; ***************** Position M0 (Divider Line) *********************

	
	sta RESM0
	sta PF1		;3

	; DEBUG LIVES PROBLEM
;	lda #$0F
;	sta PF2		;3

	sta HMCLR
	lda #%01000000
	sta HMM0

	lda #6
	sta temp4

	; preLoad playfield color buffer
	lda playField+71+6
	sta pfBuffer+7


	sta WSYNC


	; Set player colors to white
	lda #$0F		;2
	sta COLUP0		;3
	sta COLUP1		;3


	;**************** Position P0 (Left Marble) ***************

	lda p1x
	lsr
	tax
	STA WSYNC
	; Uses a lookup table to get the fine and course movement
	lda movement,x
	STA HMP0
	AND #$0F
	TAY

pPos1
	DEY
	BPL pPos1
	STA RESP0


	STA WSYNC
	STA HMOVE

	;**************** Position P1 (Right Marble) ***************

	nop
	nop	

	lda p2x
	clc
	adc #5
	
	lsr
	tax

	; Uses a lookup table to get the fine and course movement
	lda movement,x
	STA HMP1

	ldx #0
	stx HMP0
	stx HMM0

	AND #$0F
	TAY

pPos2
	DEY
	BPL pPos2

	STA RESP1

	; **************** Position M1 (Power Ups) *********************

	; DBEUG LIVES PROBLEM
;	lda #0
;	sta PF2

	STA WSYNC
	STA HMOVE
	

	; Power up flickers between player 1 and 2
	; power up.
	ldx pwr1x
	lda frame
	and #%00000001
	beq powerUp1

	lda pwr2x	
	clc
	adc #77
	tax

powerUp1

	; Uses a lookup table to get the fine and course movement
	lda movement,x
	ldy #$0F


	sta WSYNC
	sta HMCLR

	STA HMM1

	AND #$0F
	TAY
pPos3
	DEY
	BPL pPos3
	STA RESM1


	sta WSYNC
	sta HMOVE

	; The Ball is used to show the center divider in the score
	; area, but M0 is used in the game area.  Turn on M0 here.
	lda #$FF
	sta ENAM0

	;******* Calculate line position of Vertical Paddle bar (Ball) *******

	; temp16L stores the position
	; of the vertical paddle indicator
	ldx padVal1

	lda frame
	and #1
	beq vertPad1

	ldx padVal3
vertPad1

	lda paddleDecode,x

	sta temp3
	lda #14
	sec
	sbc temp3
	bcc padZero

	clc
	adc #1
	jmp notPadZero

padZero 
	lda #1
notPadZero

	sta temp3

	ldx #$0

	cmp #13
	bmi ballOff

	ldx #$FF

ballOff

	stx ENABL

	lda #%00010000
	sta CTRLPF

	sta WSYNC

	; Draw top white line
	lda #$0F
	sta COLUBK
	sta COLUBK
	

	;*********** Position Ball (shows vertical Paddle position) ***********

	; The ball graphics flickers between the left side and right side
	; to indicate both player's vertical paddle positions

	lda frame
	and #1
	bne right

	ldx #4
ballL
	dex
	bne ballL

	lda #%11010000
	sta HMBL	

	nop
	sta RESBL

	jmp endBallPos

right
	ldx #9
ballR
	dex
	bne ballR

	lda #%10110000
	sta HMBL	

	nop
	sta RESBL

endBallPos

	sta WSYNC
	sta HMOVE

	lda bkColor
	sta COLUBK
	
	lda #$FF
	sta ENAM0



	;--------------------------- set startup text to display (or not)
	; 147 = no intro display
	ldx #147

	; Check for GAMEOVER/ENDLEVEL flags
	lda level
	and #%11100000
	bne showDisplay

	; Check for startup
	lda p1Status
	cmp #STARTUP
	bne noStartup
showDisplay
	ldx #148 ; 148 = show display
noStartup
	stx temp5
	;------------------------------------------

	;***************** General Setup for Screen Drawing *******************




	; Alternate the two kernals every frame
	lda frame
	and #%00000001
	beq gotoScanLoop2

	jmp gotoScanLoop3	




gotoScanLoop2
	
	; Playfield Reference
	;
	; pfBuffer
	; 0 = PF0.1
	; 1 = PF1.1
	; 2 = PF2.1
	; 3 = PF0.2
	; 4 = PF1.2
	; 5 = PF2.2
	; 6 = PFCOLOR1
	; 7 = PFCOLOR2
	;
	;  0  Hblank  22 PF0 28   PF1   38   PF2   48 PF0 56   PF1   66   PF2   76
	;  |----22----||--6--||---10----||---10----||--6--||---10----||---10----||
	;               4---7  7-------0  0-------7  4---7  7-------0  0-------7

;==========================================================================
;
; KERNAL A
;
;==========================================================================
	
	; ********* Draw Horizontal Paddle Indicator Left *********

	lda pfColor
	sta COLUPF

	; Don't show paddles if INACTIVE
	lda p1Status
	cmp #INACTIVE
	bne showBall
	
	lda #255
	sta temp3 ; location of ball line position
	sta WSYNC
	sta WSYNC	
	jmp	endPaddleDisplay


showBall
	; Get paddle value
	ldx padVal2
	lda paddleDecode,x

	ldy #2

hLoopA	
	sta WSYNC
	
	asl
	asl
	tax
	
	; Use array to convert paddle value
	; to playfield data
	lda hPaddleDisplay,x
	sta PF0
	lda hPaddleDisplay+1,x
	sta PF1
	lda hPaddleDisplay+2,x
	sta PF2
	
	ldx #2
hPadA
	dex
	bne hPadA

	; Turn off display
	lda #0
	sta PF0
	sta PF1
	sta PF2
	
	; Get paddle value
	ldx padVal2
	lda paddleDecode,x

	dey
	bne hLoopA

endPaddleDisplay
	sta WSYNC

	; ***************** Prepare for Kernal Loop ****************

	; Set starting Paddle counter values
	lda #161
	sta padVal1
	sta padVal2

	; Delay a bit before start of kernal loop
	ldx #6
kBDelay
	dex
	bne kBDelay

	; PreLoad the next right-playfield color
	lda playField+71
	sta pfBuffer+7

	; preload temp2 value (x/2)
	lda #6
	sta temp4


	; number of blocks
	ldx #12			;2 = 18

	; Use Y to track the actual line
	ldy #156		;2 20

scanLoop2

;	lda pfColor	; waste cycles
	txs			; waste cycles

	lda playField-1,x	;4 76

	; 1A) setup
	;---------------------------------------

	sta PF0				;3
	sta pfBuffer		;3
	lda (pMarble),y		;5*
	sta GRP0			;3
	lda playField+11,x	;4
	sta PF1				;3
	lda playField+23,x	;4
	sta PF2				;3

	lda (pMarble2),y		;5*
	sta GRP1			;3

	lda pfBuffer		;3
	asl					;2
	asl					;2
	asl					;2
	asl					;2
	sta PF0				;3 48
	sta pfBuffer+3		;3

	lda playField+35,x	;4
	sta PF1				;3 55
	lda playField+47,x	;4
	sta PF2				;3
;	sta pfBuffer+5		;3
	dey				;2
	lda (pMarble),y		;5*
	
	; 2A) colors
	;---------------------------------------
	sta GRP0			;3

	lda pfBuffer		;3
	sta PF0				;3

	ldx temp4
	lda playField+59,x	;4 66 
	sta COLUPF			;3
	sta pfBuffer+6		;3 
	tsx

	lda playField+11,x	;4
	sta PF1				;3
	lda playField+23,x	;4
	sta PF2				;3 34

	lda (pMarble2),y		;4
	sta GRP1			;3
	
;	nop
	
	lda pfBuffer+3		;3
	sta PF0				;3 52

	lda playField+35,x	;4
	sta PF1				;3

	lda pfBuffer+7		;3
	sta COLUPF			;3

;	lda pfBuffer+5		;4
	lda playField+47,x	;4
	sta PF2				;3
	sta pfBuffer+5		;3

	dey					;2
	lda (pMarble),y		;4*
	sta GRP0			;3

	; 3A) paddles
	;---------------------------------------

	lda pfBuffer		;3
	sta PF0				;3
	lda pfColor			;3
	sta COLUPF			;3

	lda playField+11,x	;4
	sta PF1				;3
	sta pfBuffer+1		;3

	lda playField+23,x	;4
	sta PF2				;3

	lda (pMarble2),y		;4
	sta GRP1			;3 39
	
;	nop

	lda pfBuffer+3		;3
	sta PF0				;3 52

	lda playField+35,x	;4
	sta PF1				;3

	lda pfBuffer+5		;4
	sta PF2				;3

	dey					;2
	lda (pMarble),y		;4*
	sta GRP0			;3 68

	lda INPT0			;3
	bmi paddles1		;2 or 3
	sty padVal1			;3
paddles1

	lda pfBuffer		;3
	sta PF0				;3

	sta WSYNC

	; 4A) colors
	;---------------------------------------

	lda pfBuffer+6		;3
	sta COLUPF			;3

	lda pfBuffer+1		;4
	sta PF1				;3

	lda playField+23,x	;4
	sta PF2				;3 29
	sta pfBuffer+2		;3

	lda (pMarble2),y		;4
	sta GRP1			;3
	

	lda pfBuffer+3		;3
	sta PF0				;3 52

	lda playField+35,x	;4
	sta PF1				;3

	lda pfBuffer+7		;3
	sta COLUPF			;3

	lda pfBuffer+5		;4
	sta PF2				;3

	dey					;2

	lda (pMarble),y		;4*
	sta GRP0			;3

	lda pfBuffer		;3
	sta PF0				;3

	; 5A) paddles
	;---------------------------------------

	lda pfBuffer		;3
	sta PF0				;3

	lda pfColor			;3
	sta COLUPF			;3

	lda pfBuffer+1		;3
	sta PF1				;3

	lda pfBuffer+2		;3
	sta PF2				;3 29

	lda (pMarble2),y		;4
	sta GRP1			;3
	
	lda pfBuffer+3		;3
	sta PF0				;3 52

	lda playField+35,x	;4
	sta PF1				;3
	sta pfBuffer+4

	lda pfBuffer+5		;4
	sta PF2				;3

	dey					;2
	lda (pMarble),y		;4*
	sta GRP0			;3
	lda pfBuffer		;3
	sta PF0				;3
	
	lda INPT1			;3
	bmi paddles2		;2 or 3
	sty padVal2			;3
paddles2

	sta WSYNC

	; 6A) colors
	;---------------------------------------

	lda pfBuffer+6		;3
	sta COLUPF			;3

	txs
	ldx pfBuffer+1		;3
	stx PF1				;3

	lda pfBuffer+2		;3
	sta PF2				;3

	lda (pMarble2),y		;4
	sta GRP1			;3

	dey					;2
	
	lda pfBuffer+3		;3
	sta PF0				;3

	lda pfBuffer+4		;3
	sta PF1				;3

	lda pfBuffer+7		;3
	sta COLUPF			;3

	lda pfBuffer+5		;4
	sta PF2				;3


	lda (pMarble),y		;4*
	sta GRP0			;3

	lda pfBuffer		;3
	sta PF0				;3

	; 7A) more setup
	;---------------------------------------

;	lda pfBuffer		;3
;	sta PF0				;3

	lda pfColor			;3
	stx PF1				;3
	sta COLUPF			;3




	; Draw the power up (using missile 1)
	tsx					;2
	txa					;2
	ldx #ENABL			;2
	txs					;2

	cmp temp3
	php
	cmp pwr1y			;2
	php					;3
	tax

	lda pfBuffer+2		;3
	sta PF2				;3

	lda (pMarble2),y	;4
	sta GRP1			;3

	lda pfBuffer+3		;3
	sta PF0				;3


	lda pfBuffer+4		;3
	sta PF1				;3

	lda pfBuffer+5		;4
	sta PF2				;3

	dey					;2
	lda (pMarble),y		;4*
	sta GRP0			;3
	
	txs
	nop

	lda pfBuffer		;3
	sta WSYNC

	sta PF0				;3
	ldx pfBuffer+1		;3

	; 8A) colors
	;---------------------------------------

	lda pfBuffer+6		;3
	sta COLUPF			;3

	stx PF1				;3

	lda pfBuffer+2		;3
	sta PF2				;3

	lda (pMarble2),y		;4
	sta GRP1			;3

	dey					;2
	
	lda pfBuffer+3		;3
	sta PF0				;3

	lda pfBuffer+4		;3
	sta PF1				;3


	lda pfBuffer+7		;3
	sta COLUPF			;3

	lda pfBuffer+5		;4
	sta PF2				;3

	lda (pMarble),y		;4*
	sta GRP0			;3

	lda pfBuffer		;3
	sta PF0				;3

	; 9A) paddles
	;---------------------------------------

	lda pfBuffer		;3
	sta PF0				;3

	lda pfColor			;3
	sta COLUPF			;3

	stx PF1				;3

	lda pfBuffer+2		;3
	sta PF2				;3

	lda (pMarble2),y		;4
	sta GRP1			;3


	cpy temp5			; Check for message display
	bne noMessageDisplay	; display message
	
	jmp messageDisplay

noMessageDisplay

	nop


	lda pfBuffer+3		;3
	sta PF0				;3

	lda pfBuffer+4		;3
	sta PF1				;3

	lda pfBuffer+5		;4
	sta PF2				;3

	dey					;2
	lda (pMarble),y		;4*
	sta GRP0			;3
	lda pfBuffer		;3
	sta PF0				;3
	
	lda INPT0			;3
	bmi paddles3		;2 or 3
	sty padVal1			;3
paddles3

	sta WSYNC


	; 10A) colors
	;---------------------------------------

	lda pfBuffer+6		;3
	sta COLUPF			;3

	stx PF1				;3

	lda #0
	sta ENAM1

	lda pfBuffer+2		;3
	sta PF2				;3

	lda (pMarble2),y		;4
	sta GRP1			;3

	;nop
	
	lda pfBuffer+3		;3
	sta PF0				;3

	lda pfBuffer+4		;3
	sta PF1				;3

	dey					;2

	lda pfBuffer+7		;3
	sta COLUPF			;3

	lda pfBuffer+5		;4
	sta PF2				;3

	lda (pMarble),y		;4*
	sta GRP0			;3

	lda pfBuffer		;3
	sta PF0				;3

	; 11A) paddles
	;---------------------------------------

	lda pfBuffer		;3
	sta PF0				;3

	lda pfColor			;3
	sta COLUPF			;3

	stx PF1				;3

	lda pfBuffer+2		;3
	sta PF2				;3

	lda (pMarble2),y		;4
	sta GRP1			;3

	; This gets X out of the stack register,
	; divides it by two and stores it for use
	; with the color shading.
	tsx
	txa
	lsr
	sta temp4

	lda pfBuffer+3		;3
	sta PF0				;3

	lda pfBuffer+4		;3
	sta PF1				;3

	lda pfBuffer+5		;4
	sta PF2				;3

	dey					;2
	lda (pMarble),y		;4*
	sta GRP0			;3
	lda pfBuffer		;3
	sta PF0				;3

	lda INPT1			;3
	bmi paddles4		;2 or 3
	sty padVal2			;3
paddles4

	sta WSYNC

	; 12A) colors
	;---------------------------------------

	lda pfBuffer+6		;3
	sta COLUPF			;3

	lda pfBuffer+1		;3
	sta PF1				;3

	lda pfBuffer+2		;3
	sta PF2				;3

	lda (pMarble2),y		;4
	sta GRP1			;3

	; Grab that color pointer
	ldx temp4
	dey					;2
	
	lda pfBuffer+3		;3
	sta PF0				;3

	lda pfBuffer+4		;3
	sta PF1				;3

	lda pfBuffer+7		;3
	sta COLUPF			;3

	lda pfBuffer+5		;4
	sta PF2				;3

	lda (pMarble),y		;4*
	sta GRP0			;3

	lda pfBuffer		;3
	sta PF0				;3

	; 13A) setup for loop
	;---------------------------------------

	lda pfColor			;3
	sta COLUPF			;3

	lda pfBuffer+1		;3
	sta PF1				;3
	;nop

	; Load the next right-playfield color
	lda playField+65,x	;4 66 
	sta pfBuffer+7			;3 

	lda pfBuffer+2		;3
	sta PF2				;3

	lda (pMarble2),y
	sta GRP1

	tsx					;2
	dey

	lda pfBuffer+3		;3
	sta PF0				;3
	lda pfBuffer+4		;4
	sta PF1				;3
	lda pfBuffer+5		;3
	sta PF2				;3


    dex					;2
    beq quitScanLoop2   ;2
	jmp scanLoop2		;3 must be 70

	;******************* End Of Kernal A *******************

;==========================================================================
;
; KERNAL CLEAN UP
;
;==========================================================================
quitScanLoop2
	sta WSYNC

	; Draw the white line at the bottom
	lda #$0F
	sta COLUPF
	lda #255
	sta PF0
	sta PF1
	sta PF2

endOfScreen
	
	; One more scanline
	sta WSYNC
	lda #0
	sta COLUBK
	sta PF0
	sta ENABL
	sta ENAM0
	sta PF1
	sta PF2
	sta COLUP0
	sta COLUP1

	; restore stack
	ldx #255
	txs

    jmp rtnDrawScreen



;==========================================================================
;
; messageDisplay
;
;--------------------------------------------------------------------------
; Displays text in middle of game screen
;==========================================================================
messageDisplay

	; Finish current line (cuts in a 9th scanline in loop)
	lda pfBuffer+3		;3
	sta PF0				;3

	lda pfBuffer+4		;3
	sta PF1				;3

	lda pfBuffer+5		;4
	sta PF2				;3

	lda frame
	and #1
	beq padFrame01

	lda INPT2
	bmi paddles13		;2 or 3
	sty padVal3			;3

	jmp paddles13

padFrame01
	lda INPT0			;3
	bmi paddles13		;2 or 3
	sty padVal1			;3

paddles13

	sta WSYNC

	; call function to display text in bank 3
	jmp callIntroMessage
rtnCallIntroMessage
		
;	sta WSYNC

	; Set player colors to white
	lda #$0F		;2
	sta COLUP0		;3
	sta COLUP1		;3

	; Now, have to reposition the player graphics
	; since they were moved to display the text..
	
	;**************** Position P0 (Left Marble) ***************

	lda p1x
	lsr
	tax
	STA WSYNC
	; Uses a lookup table to get the fine and course movement
	lda movement,x
	STA HMP0
	AND #$0F
	TAY

pPos5
	DEY
	BPL pPos5
	STA RESP0


	STA WSYNC
	STA HMOVE

	;**************** Position P1 (Right Marble) ***************

	nop
	nop	

	lda p2x
	clc
	adc #5
	
	lsr
	tax

	; Uses a lookup table to get the fine and course movement
	lda movement,x
	STA HMP1

	ldx #0
	stx HMP0
	stx HMM0

	AND #$0F
	TAY

pPos6
	DEY
	BPL pPos6

	STA RESP1

	STA WSYNC
	STA HMOVE

	lda #255
	sta PF1
	sta PF2

	; ***********************************************************

	; Restore remaining registers and variables to resume
	; drawing the screen...

	; restore X and Y
	ldx pfBuffer+1
	txs
	ldy pfBuffer+2


	lda #32		;2
	sta  NUSIZ1

	lda  #$00           ; set both players to normal
	sta  NUSIZ0
	sta  VDELP0
	sta  VDELP1


;	sta WSYNC

	tya
	sec
	sbc #31
	tay

	sta WSYNC

	lda bkColor
	sta COLUBK

	lda #0
	sta PF1
	sta PF2


	tsx
	dex
	dex
	txa
	lsr
	sta temp4
	tax

	; Load the next right-playfield color
	lda playField+65,x	;4 66 
	sta pfBuffer+7			;3 

	lda playField+59,x	;4 66 
	sta pfBuffer+6

	tsx
	dex
	dex
	dex
	txs

	; Don't change number of cycles after this...
	sta WSYNC
	
	lda #0
	sta PF1
	sta PF2

	lda #%00010000
	sta CTRLPF

	lda pfColor			;3
	sta COLUPF			;3

	lda #255
	sta ENAM0


	lda frame
	and #1

	beq reEnterLoop2


	ldx #3
messageLoop1
	dex
	bne messageLoop1

	nop
	nop

	tsx	

	jmp scanLoop3



reEnterLoop2

	ldx #3
messageLoop2
	dex
	bne messageLoop2
	
	lda temp

	tsx	

	jmp scanLoop2




hPaddleDisplay	; 64 bytes
	byte %00010000, %00000000, %00000000, %00000000
	byte %00010000, %00000000, %00000000, %00000000
	byte %00010000, %00000000, %00000000, %00000000
	byte %00010000, %00000000, %00000000, %00000000
	byte %01100000, %00000000, %00000000, %00000000
	byte %10000000, %10000000, %00000000, %00000000
	byte %00000000, %01100000, %00000000, %00000000
	byte %00000000, %00011000, %00000000, %00000000
	byte %00000000, %00000110, %00000000, %00000000
	byte %00000000, %00000001, %00000001, %00000000
	byte %00000000, %00000000, %00000110, %00000000
	byte %00000000, %00000000, %00011000, %00000000
	byte %00000000, %00000000, %01100000, %00000000
	byte %00000000, %00000000, %10000000, %00000000
	byte %00000000, %00000000, %10000000, %00000000
	byte %00000000, %00000000, %10000000, %00000000



;==========================================================================
;
; KERNAL B
;
;==========================================================================
gotoScanLoop3

	; ******* Draw horizontal Paddle Indicator Right *******	

	lda pfColor
	sta COLUPF
	
	lda p2Status
	cmp #INACTIVE
	bne showBall2
	
	lda #255
	sta temp3 ; location of ball line position
	sta WSYNC
	sta WSYNC	
	jmp	endPaddleDisplay2

showBall2 

	ldy #2
hLoopB
	sta WSYNC

	; Get paddle value
	ldx padVal4
	lda paddleDecode,x

	ldx #0
	stx PF0
	stx PF1
	stx PF2

	asl
	asl
	
	ldx #2
hPadB
	dex
	bne hPadB

	tax
	lda hPaddleDisplay,x
	sta PF0
	lda hPaddleDisplay+1,x
	sta PF1
	lda hPaddleDisplay+2,x
	sta PF2


	dey
	bne hLoopB

endPaddleDisplay2
	sta WSYNC

	ldx #0
	stx PF0
	stx PF1
	stx PF2

	ldx #4
kADelay
	dex
	bne kADelay

	; PreLoad the next right-playfield color
	lda playField+71
	sta pfBuffer+7

	; PreLoad the next left-playfield color
	lda playField+59+6;
;	lda #$54
	sta pfBuffer+6



	; Set starting paddle counter values
	lda #161
	sta padVal3
	sta padVal4

	; number of blocks
	ldx #12			;2 = 18

	; Use Y to track the actual line
	ldy #156		;2 20


scanLoop3
	lda pfColor
;	sta COLUPF

	lda playField-1,x	;4 76

	; 1B) setup
	;---------------------------------------

	sta PF0				;3
	sta pfBuffer		;3
	lda (pMarble),y		;5*
	sta GRP0			;3
	lda playField+11,x	;4
	sta PF1				;3
	lda playField+23,x	;4
	sta PF2				;3

	lda (pMarble2),y		;5*
	sta GRP1			;3

	lda pfBuffer		;3
	asl					;2
	asl					;2
	asl					;2
	asl					;2
	sta PF0				;3 48
	sta pfBuffer+3		;3

	lda playField+35,x	;4
	sta PF1				;3 55
	lda playField+47,x	;4
	sta PF2				;3
	sta pfBuffer+5		;3
	dey				;2

	lda (pMarble),y		;4*
	sta GRP0			;3 68


	; 2B) paddles
	;---------------------------------------

	lda pfBuffer		;3
	sta PF0				;3

	lda playField+11,x	;4
	sta PF1				;3
	sta pfBuffer+1		;3

	lda playField+23,x	;4
	sta PF2				;3
	sta pfBuffer+2		;3

	lda (pMarble2),y		;4
	sta GRP1			;3 39
	
;	nop
;	nop
;	nop
	dey					;2

	lda pfBuffer+3		;3
	sta PF0				;3 52

	lda playField+35,x	;4
	sta PF1				;3
	sta pfBuffer+4		;3

	lda pfBuffer+5		;4
	sta PF2				;3

	lda (pMarble),y		;4*
	sta GRP0			;3 68

	lda INPT2			;3
	bmi paddles5		;2 or 3
	sty padVal3			;3
paddles5

	lda pfBuffer		;3
	sta PF0				;3



;	lda (pMarble),y		;5*
;	sta GRP0			;3
	sta WSYNC


	
	; 3B) colors
	;---------------------------------------

	lda pfBuffer+6		;4 66 
	sta COLUPF			;3
;	sta pfBuffer+6		;3 
	nop
	nop

	lda pfBuffer+1		;3
	sta PF1				;3
	lda pfBuffer+2		;3
	sta PF2				;3 34

	lda (pMarble2),y		;4
	sta GRP1			;3
	
	nop
	nop
	nop
	
	lda pfBuffer+3		;3
	sta PF0				;3 52

	lda pfBuffer+7		;3
	sta COLUPF			;3

	lda pfBuffer+4		;3
	sta PF1				;3



	lda pfBuffer+5		;4
	sta PF2				;3

	dey					;2
	lda (pMarble),y		;4*
	sta GRP0			;3

	; 4B) paddles
	;---------------------------------------

	lda pfBuffer		;3
	sta PF0				;3

	lda pfColor			;3
	sta COLUPF			;3

	lda pfBuffer+1		;3
	sta PF1				;3

	lda pfBuffer+2		;3
	sta PF2				;3 29

	lda (pMarble2),y		;4
	sta GRP1			;3

	dey					;2
	nop
	nop
	
	lda pfBuffer+3		;3
	sta PF0				;3 52

	lda pfBuffer+4		;3
	sta PF1				;3

	lda pfBuffer+5		;4
	sta PF2				;3

	lda (pMarble),y		;4*
	sta GRP0			;3
	lda pfBuffer		;3
	sta PF0				;3
	
	lda INPT3			;3
	bmi paddles6		;2 or 3
	sty padVal4			;3
paddles6

	sta WSYNC

	; 5B) colors
	;---------------------------------------

	lda pfBuffer+6		;3
	sta COLUPF			;3

	lda pfBuffer+1		;4
	sta PF1				;3

	lda playField+23,x	;4
	sta PF2				;3 29
	sta pfBuffer+2		;3

	lda (pMarble2),y		;4
	sta GRP1			;3
	
	lda pfBuffer+3		;3
	sta PF0				;3 52

	lda playField+35,x	;4
	sta PF1				;3

	lda pfBuffer+7		;3
	sta COLUPF			;3

	lda pfBuffer+5		;4
	sta PF2				;3

	dey					;2

	lda (pMarble),y		;4*
	sta GRP0			;3

	lda pfBuffer		;3
	sta PF0				;3


	; 6B) more setup
	;---------------------------------------

	lda pfColor			;3
	sta COLUPF			;3

	lda pfBuffer+1		;3
	sta PF1				;3

	lda pfBuffer+2		;3
	sta PF2				;3

	lda (pMarble2),y		;4
	sta GRP1			;3

	; Draw the power up (using missile 1)
	txa					;2
	ldx #ENABL			;2
	txs					;2
	cmp temp3
	php
	cmp pwr2y			;2
	php					;3
	tax


	lda pfBuffer+3		;3
	sta PF0				;3

	lda pfBuffer+4		;3
	sta PF1				;3

	lda pfBuffer+5		;4
	sta PF2				;3

	dey					;2
	lda (pMarble),y		;4*
	sta GRP0			;3
	

	lda pfBuffer		;3
	sta PF0				;3
	nop


	; 7B) colors
	;---------------------------------------

	lda pfBuffer+6		;3
	sta COLUPF			;3

	txs
	ldx pfBuffer+1		;3
	stx PF1				;3

	lda pfBuffer+2		;3
	sta PF2				;3

	lda (pMarble2),y		;4
	sta GRP1			;3

	dey					;2

	nop
	lda temp3	; waste 3 cycles
	
	lda pfBuffer+3		;3
	sta PF0				;3

	lda pfBuffer+7		;3
	sta COLUPF			;3

	lda pfBuffer+4		;3
	sta PF1				;3

	lda pfBuffer+5		;4
	sta PF2				;3


	lda (pMarble),y		;4*
	sta GRP0			;3


	; 8B) paddles
	;---------------------------------------

	lda pfBuffer		;3
	sta PF0				;3

	lda pfColor			;3
	sta COLUPF			;3

	stx PF1				;3

	lda pfBuffer+2		;3
	sta PF2				;3

	lda (pMarble2),y		;4
	sta GRP1			;3

	nop					;8
	nop
	nop
	nop
	
	lda pfBuffer+3		;3
	sta PF0				;3

	lda pfBuffer+4		;3
	sta PF1				;3

	lda pfBuffer+5		;4
	sta PF2				;3

	dey					;2
	lda (pMarble),y		;4*
	sta GRP0			;3
	lda pfBuffer		;3
	sta PF0				;3
	
	lda INPT2			;3
	bmi paddles7		;2 or 3
	sty padVal3			;3
paddles7

	sta WSYNC



	; 9B) colors
	;---------------------------------------

	lda pfBuffer+6		;3
	sta COLUPF			;3

	stx PF1				;3

	lda pfBuffer+2		;3
	sta PF2				;3

	lda (pMarble2),y		;4
	sta GRP1			;3

	cpy temp5
	bne noMessage2

	jmp messageDisplay

noMessage2

	dey					;2
	lda #0				;2
	sta ENAM1			;3
	
	lda pfBuffer+3		;3
	sta PF0				;3

	lda pfBuffer+7		;3
	sta COLUPF			;3

	lda pfBuffer+4		;3
	sta PF1				;3


	lda pfBuffer+5		;4
	sta PF2				;3

	lda (pMarble),y		;4*
	sta GRP0			;3


	; 10B) paddles
	;---------------------------------------

	lda pfBuffer		;3
	sta PF0				;3

	lda pfColor			;3
	sta COLUPF			;3

	stx PF1				;3

	lda pfBuffer+2		;3
	sta PF2				;3

	lda (pMarble2),y		;4
	sta GRP1			;3

	lda temp3  ; waste 3 cycles
	nop
	nop
	nop
	dey					;2

	lda pfBuffer+3		;3
	sta PF0				;3

	lda pfBuffer+4		;3
	sta PF1				;3

	lda pfBuffer+5		;4
	sta PF2				;3

	lda (pMarble),y		;4*
	sta GRP0			;3
	lda pfBuffer		;3
	sta PF0				;3
	
	lda INPT3			;3
	bmi paddles8		;2 or 3
	sty padVal4			;3
paddles8

	sta WSYNC


	; 11B) colors
	;---------------------------------------

	lda pfBuffer+6		;3
	sta COLUPF			;3

	stx PF1				;3

	lda pfBuffer+2		;3
	sta PF2				;3

	lda (pMarble2),y		;4
	sta GRP1			;3

	lda temp3	; waste 3 cycles
	nop
	nop
	nop
	nop
	dey					;2
	
	lda pfBuffer+3		;3
	sta PF0				;3

	lda pfBuffer+7		;3
	sta COLUPF			;3

	lda pfBuffer+4		;3
	sta PF1				;3


	lda pfBuffer+5		;4
	sta PF2				;3

	lda (pMarble),y		;4*
	sta GRP0			;3

	lda pfBuffer		;3
	sta PF0				;3


	; 12B) nothing
	;---------------------------------------

	lda pfColor			;3
	sta COLUPF			;3

	stx PF1				;3

	lda pfBuffer+2		;3
	sta PF2				;3

	lda (pMarble2),y		;4
	sta GRP1			;3

	; This gets X out of the stack register,
	; divides it by two and stores it for use
	; with the color shading.
	tsx
	txa
	lsr
	nop
	tax
	lda playField+59,x	;4 66 
	sta pfBuffer+6
	
	lda pfBuffer+3		;3
	sta PF0				;3

	lda pfBuffer+4		;3
	sta PF1				;3

	lda pfBuffer+5		;4
	sta PF2				;3

	dey					;2
	lda (pMarble),y		;4*
	sta GRP0			;3

	nop

	lda pfBuffer		;3
	sta PF0				;3

	; 13B) setup for loop
	;---------------------------------------


	lda pfBuffer+1		;3
	sta PF1				;3

	; Load the next right-playfield color
	lda playField+65,x	;4 66 
	sta pfBuffer+7			;3 
	tsx

	lda pfBuffer+2		;3
	sta PF2				;3

	lda (pMarble2),y
	sta GRP1

	nop
	dey

	lda pfBuffer+3		;3
	sta PF0				;3
	lda pfBuffer+4		;4
	sta PF1				;3
	lda pfBuffer+5		;3
	sta PF2				;3


    dex					;2
    beq quitScanLoop3   ;2
	jmp scanLoop3		;3 must be 70

quitScanLoop3
	sta WSYNC

	lda #$0F
	sta COLUPF
	lda #255
	sta PF0
	sta PF1
	sta PF2
	
	jmp endOfScreen

	; ******************* End of Kernal B ******************






			
;==========================================================================
;
; Start of Program
;
;--------------------------------------------------------------------------
; Clear memory, locate character graphics positions and such,
; initialize key memory values, start GameLoop.
;==========================================================================
Start
	sei  	
	 cld  		
	ldx #$FF
	txs  		
	lda #0
clear   
	sta 0,x
	dex
	bne clear	

	; Initialize Variables
	jsr initVar
	



;==========================================================================
;
; GameLoop
;
;==========================================================================
GameLoop


	jmp VSync 	;start vertical retrace
rtnVSync


	lda level
	cmp #255
	beq noGameSelect

	lda SWCHB
	and #2
	beq resetGame


	; ----------------------------------------
	; Reset game when level = 254

	lda level
	cmp #254
	bne noGameSelect

resetGame
	lda #0
	ldx #$78
clrVar
	sta $80,x
	dex
	bpl clrVar

	; Variables for title screen only
	lda #0
;	sta option
;	sta paddle
;	sta debounce
;	sta bounce
;	sta titleBlank
;	sta startGame
;	sta beat
;	sta measure


	sta AUDV0
	sta AUDV1
	
	lda #255
	sta level

	lda #50
	sta titleBlank
	sta debounce

noGameSelect
	;---------------------------------------



	; if the level is set to 255, the title
	; screen is run.
	lda level
	cmp #255
	bne gameMode

	jmp callTitleScreen

gameMode
	jmp VBlank    	; spare time during screen blank
					; uses jmp to avoid extra stack usage
VBlankReturn

	sta CXCLR

	inc frame	

	jmp drawScreen	; draw one screen
rtnDrawScreen

rtnCallTitleScreen



	jmp overscan	; do overscan
rtnOverscan

	jmp GameLoop    ;back to top



;==========================================================================
;
; Initialize variables
;
;==========================================================================
initVar

	; Set initialization flag.
	; This stays set until the first frame is drawn.
	lda #$0f	;set text color to white
	sta COLUP0
	sta COLUP1	

	lda #80
	sta padVal1
	sta padVal2
	sta padVal3
	sta padVal4

	lda #128
	sta p1xVel
	sta p1yVel
	sta p2xVel
	sta p2yVel

	lda #120
	sta p2xVel

	lda #STARTUP
	sta p1Status
	sta p2Status

	lda #200
	sta p1Counter
	sta p2Counter

	lda #$25
	sta p2TimeH
	sta p2TimeL

	lda #3
	sta p1Lives
;	sta p2Lives

	lda #255
	sta level

	lda #1
	;sta p1Screen
	;sta p2Screen

	rts


;==========================================================================
;
; VSync
;
;-------------------------------------------------------------------------
; Game timers are elapsed during VSync
;==========================================================================
VSync

	lda #2		;bit 1 needs to be 1 to start retrace
	sta VSYNC	;start retrace
	sta WSYNC 	;wait a few lines


	;--------------- elapse game timer 1
	lda p1Status	;3
	and #NOTIME		;2
	bne noDecTime1	;2

	; Handle Time
	ldx #0			;2
	jsr elapseTime	;5

noDecTime1
	;------------------------------------


	lda #44		;prepare timer to exit blank period (44)
	sta WSYNC 
	sta TIM64T	;turn it on


	;--------------- elapse game timer 2
	lda p2Status	;3
	and #NOTIME		;2
	bne noDecTime2	;2

	; Handle Time
	ldx #1			;2
	jsr elapseTime	;5

noDecTime2
	;------------------------------------


	lda #44		;bit 1 needs to be 1 to start retrace
	sta WSYNC 	;wait one more
	sta VSYNC 	;done with retrace, write 0 to bit 1

	jmp rtnVSync





;==========================================================================
;
; VBlank
;
;--------------------------------------------------------------------------
; Handle user input and display setup during the VBLANK period
;==========================================================================
VBlank

	jmp callVBlank2 ; call VBlank routines in bank 2
VBlank2Return

	; ------- Cycle headroom: remove these in release version
	sta WSYNC
	sta WSYNC
	sta WSYNC
	sta WSYNC

	;---------------------------------------------------------

	jmp VBlankReturn ; use jmps to avoid extra stack usage	





;==========================================================================
;
; incScore
;
;--------------------------------------------------------------------------
; Increase BCD score by one
; 
; preload
; X: player number (0 or 1)
;==========================================================================
incScore

	sed
	
	lda #1
	clc
	adc p1ScoreL,x
	sta p1ScoreL,x
		
	lda #0
	adc p1ScoreH,x
	sta p1ScoreH,x
	
	cld
	
	rts

;==========================================================================
;
; decTime
;
;--------------------------------------------------------------------------
; Elapse 1/10th of a second of time
;
; preload:
; X: number of player (0 or 1)
;==========================================================================
decTime
	
	sed

	; Make sure it's not already at zero
	lda p1TimeL,x
	bne contDecTime2
	lda p1TimeH,x
	bne contDecTime2
	
	cld	

	rts

contDecTime2
	lda p1TimeL,x
	and #$0F
	sec
	sbc #1
	and #$0F
	sta p1TimeL,x

	lda p1TimeH,x
	sbc #0
	sta p1TimeH,x

	cld
	
	rts	; other rts



;==========================================================================
;
; elapseTime
;
;--------------------------------------------------------------------------
; Elapse 1 frame of time
;
; Max cycles = about 52
;
; preload:
; X: number of player (0 or 1)
;==========================================================================
elapseTime
	
	lda p1TimeL,x	;4
	and #$F0		;2
	bne noDecTime	;2

	sed				;2

	lda p1TimeL,x	;4
	and #$0F		;2
	sec				;2
	sbc #1			;2
	and #$0F		;2
	sta p1TimeL,x	;4

	lda p1TimeH,x	;4
	sbc #0			;2

	; If carry is clear then time rolled...
	bcc setTimeZero	;2

	sta p1TimeH,x	;4

endElapseTime

	cld				;2

	lda p1TimeL,x	;4
	ora #%01010000	;2
	sta p1TimeL,x	;4

	rts	; other rts	;5
	
setTimeZero
	cld
	lda #0
	sta p1TimeL,x
	sta p1TimeH,x
	rts

noDecTime

	lda p1TimeL,x
	sec
	sbc #%00010000
	sta p1TimeL,x

	rts







;==========================================================================
;
; Overscan
;
;==========================================================================
overscan

	sta WSYNC	
	lda #33		; Use the timer to make sure overscan takes (34)
	sta TIM64T	; 30 scan lines.  29 scan lines * 76 = 2204 / 64 = 34.4


	; Skip OS processing if in Title Screen mode
	lda level
	cmp #255
	bne doOS
	jmp endOS
doOS
	

	;-------------------------------------
	; Invert vertical paddle values (1&3)

	sec			;2 -- about 22 cycles max

	lda frame	;3
	and #1		;2
	bne invPad3	;2*

	lda #161	;2
	sbc padVal1	;3
	sta padVal1	;3
	jmp quitInv	;3

invPad3
	lda #161	;2
	sbc padVal3	;3
	sta padVal3	;3

quitInv
	;--------------------------------------



	;----------------------------------------
	; Call game logic routines in bank 2

	jmp callProcessGameLogic
rtnCallProcessGameLogic
	;-----------------------------------------



	; --------------- status state machine
	ldx #0
	jsr handleStatus

	ldx #1
	jsr handleStatus
	;------------------------------------


	;------------------- check for end of game
	;jmp endGameCheck
	lda level
	and #%11100000
	bne endGameCheck

	lda p1Status
	and #DONE
	beq endGameCheck
	
	lda p2Status
	and #DONE
	beq endGameCheck

	lda #255
	sta p1Counter
	sta p2Counter

	ldx #0
	jsr endSetup

	ldx #1
	jsr endSetup

	; default to NEXTLEVEL flag
	ldx #NEXTLEVEL

	lda p1Status
	and #NOGAME
	beq setFlag
	
	lda p2Status
	and #NOGAME
	beq setFlag
	
	ldx #ENDGAME

setFlag
	txa
	ora level
	sta level

endGameCheck
	;-------------------------------------



	;----------------------------------handle game/level end flags
	lda p1Counter
	bne endFlags

	lda level
	and #ENDGAME
	beq checkEndLevel

	; signal to go back to title screen
	lda #254
	sta level

	; Not doing this causes one extra
	; point to be added to scores at end
	lda #0
	sta pwrArray1
	sta pwrArray2
	
	jmp endFlags

	; check for next level flag
checkEndLevel
	lda level
	and #NEXTLEVEL
	beq gameEnd2

	ldx #0
	jsr nextLevelSetup
	ldx #1
	jsr nextLevelSetup

	; reset flags
	inc level
	lda #%00011111
	and level
	sta level	

	lda #0
	sta pwrArray1
	sta pwrArray2
;	sta p1x
;	sta p1y
;	sta p2x
;	sta p2y

	; Check to see if the last level was completed
	lda level
	cmp #LASTLEVEL
	bne notLastLevel

	lda level
	ora #WINGAME
	sta level

	ldx #0

	lda p1Status
	cmp #STARTUP
	bne noP1Win

	ldx #255

noP1Win
	stx pwrArray1

	ldx #0

	lda p2Status
	cmp #STARTUP
	bne noP2Win

	ldx #255

noP2Win
	stx pwrArray2

	lda #INACTIVE
	sta p1Status
	sta p2Status

notLastLevel

	lda #250
	sta p1Counter
	sta p2Counter
	sta pfColor

	jmp endFlags

gameEnd2

	; After finishing all levels, go to game over
	lda level
	and #WINGAME
	beq endFlags

	lda level
	and #%00011111
	ora #ENDGAME
	sta level

	lda #255
	sta p1Counter
	sta p2Counter

endFlags
	;---------------------------------------------------


	;----------------------- score end of level
	lda p1Status
	cmp #ENDLEVEL
	bne notScore1
	ldx #0
	jsr scoreLevel
notScore1

	lda p2Status
	cmp #ENDLEVEL
	bne notScore2
	ldx #1
	jsr scoreLevel
notScore2
	;------------------------------------------



	;------------------------ end of game bonus
	lda level
	and #WINGAME
	beq noBonus2

	lda pwrArray1
	beq noBonus1
	ldx #0
	jsr incScore

noBonus1
	lda pwrArray2
	beq noBonus2
	ldx #1
	jsr incScore	

noBonus2
	;-----------------------------------------------



endOS	

	;---------------- OS cycle overhead: remove in release version
	sta WSYNC
	sta WSYNC
	sta WSYNC
	sta WSYNC

	sta WSYNC
	sta WSYNC
	sta WSYNC
	sta WSYNC
	;---------------------------------------------------------	

endOSLoop
	lda INTIM	; We finished, but wait for timer
	bne endOSLoop	; by looping till zero
	
	sta WSYNC	; End last scanline

	lda #$82
	sta VBLANK

	jmp rtnOverscan




;==========================================================================
;
; scoreLevel
;
;==========================================================================
scoreLevel

	sed

	; Decrease two 1/10th seconds 
	ldy #2

	;--------------------------
scoreLoop
	; Check that score isn't at zero
	lda p1TimeL,x
	bne point
	lda p1TimeH,x
	bne point

	cld

endScoreLevel
	rts

point
	; dec time
	lda p1TimeL,x
	sec
	sbc #1
	and #$0F
	sta p1TimeL,x

	lda p1TimeH,x
	sbc #0
	sta p1TimeH,x

	dey
	bne scoreLoop
	;---------------------------

	lda p1ScoreL,x
	clc
	adc #1
	sta p1ScoreL,x

	lda p1ScoreH,x
	adc #0
	sta p1ScoreH,x

	cld

	rts ; other rts


;==========================================================================
;
; nextLevelSetup
;
;==========================================================================
nextLevelSetup
	lda p1Status,x
	cmp #ENDLEVEL
	bne endLevelSetup

	lda #STARTUP
	sta p1Status,x

	lda #0
	sta p1Screen,x
	
	lda #200
	sta p1Counter,x

endLevelSetup
	lda p1Status,x
	cmp #GAMEOVER
	bne doneLevelSetup
	
	lda #INACTIVE
	sta p1Status,x

doneLevelSetup
	rts



;==========================================================================
;
; endSetup
;
;--------------------------------------------------------------------------
; Adjusts status at end of level/game
;==========================================================================
endSetup
	lda p1Status,x
	cmp #FINISHED
	bne checkGameOver

	lda #ENDLEVEL
	sta p1Status,x

	rts

checkGameOver
;	cmp #GAMEOVER
;	bne doneEndSetup
	
;	lda #INACTIVE
;	sta p1Status,x

doneEndSetup
	rts ; multiple rts



;==========================================================================
;
; handleStatus
;
;--------------------------------------------------------------------------
; Status state machine
;
; Preload:
; X: Player number (0 or 1)
;==========================================================================
handleStatus


	lda p1Counter,x
	beq check
	sec
	sbc #1
	sta p1Counter,x
	rts

check
	; skip all this if WINGAME flag set
	lda level
	and #WINGAME
	bne endStatus	


	lda p1Status,x
	beq endStatus

	cmp #FALLOFF
	bne nextCheck

	lda #RESET
	ldy #130
	jmp endStatus

nextCheck
	cmp #RESET
	bne nextCheck2

	lda #NORMAL
	jmp endStatus

nextCheck2
	cmp #STARTUP
	bne nextCheck3

	lda #GETREADY
	ldy #150
	jmp endStatus

nextCheck3
	cmp #GETREADY
	bne nextCheck4
	
	lda #NORMAL
	jmp endStatus

nextCheck4
	cmp #TIMEUP
	bne endStatus

	lda #$15
	sta p1TimeH,x


	lda #RESET
	ldy #120
	jmp endStatus

endStatus
	sta p1Status,x
	tya
	sta p1Counter,x

	rts ; other rts	in function


;==========================================================================
;
; callProcessGameLogic
;--------------------------------------------------------------------------
; Call to bank 2
;==========================================================================

	org $1FA0

callProcessGameLogic
	ldx BANK2
	nop      
	nop      
	nop      
	nop      
	nop      
	nop      
	jmp rtnCallProcessGameLogic


;==========================================================================
;
; callIntroMessage
;
;--------------------------------------------------------------------------
; Call to bank 3
;==========================================================================

	org $1FB0

callIntroMessage
	ldx BANK3
	nop      
	nop      
	nop      
	nop      
	nop      
	nop      
	jmp rtnCallIntroMessage



;==========================================================================
;
; callTitleScreen
;
;--------------------------------------------------------------------------
; Call to bank 3
;==========================================================================

	org $1FC0

callTitleScreen
	ldx BANK3
	nop      
	nop      
	nop      
	nop      
	nop      
	nop      
	jmp rtnCallTitleScreen



;--------------------------------------------------------------------------
; callDrawScore
;--------------------------------------------------------------------------
; Call to bank 4
;--------------------------------------------------------------------------

	org $1FD0

callDrawScore
	ldx BANK4
	nop      
	nop      
	nop      
	nop      
	nop      
	nop      
	jmp rtnCallDrawScore



;--------------------------------------------------------------------------
; callVBlank2
;--------------------------------------------------------------------------
; Call to bank 2
;--------------------------------------------------------------------------

	org $1FE0

callVBlank2
	ldx BANK2
	nop      
	nop      
	nop      
	nop      
	nop      
	nop      
	jmp VBlank2Return


;---------------------------------------------------------------------------
; Program Startup Vector
;---------------------------------------------------------------------------
	org $1FF3  	; The cart may start in bank 2, then a bankswitch
				; will occur and land here...

	jmp Start   ; Start program

	org $1FFC	; Program startup vector
	.word Start
	.word Start

	include marbank2.asm
	include marbank3.asm
	include marbank4.asm
Current Thread