*         1850    030784
*
** UTILS.S *
** ASTEROIDS FOR THE ATARI 3600 **
** THIS FILE CONTAINS UTILITY PROGRAMS. **
*
** PRESENTLY CONTAINS - 
*
*         GAME PLAY LOOP                 *
*         DIFFICULTY LEVEL INC ROUTINE   *
*         RANDOM NUMBER ROUTINES         *
*         SAFETY BOX CHECK ROUTINE       *
*         FLIP PLAYER ROUTINE            *
*         STAR TWINKLER                  *
*         ICON SETUP ROUTINE             *
*         PAINT SHIP ROUTINE             *
*         WAIT FOR LOADER ROUTINE        *
*


** BASIC GAME PLAY LOOP. **

GAMELOOP:
	;SET DIFFICULTY LEVELS
	LDX	PLAYER
	LDA	LEVEL,X
	STA	MINYVEL		;SET MINYVEL AND MINXVEL
	LSR
	STA	MINXVEL

	LDA	ROCKTOT,X	;CONTINUE UNTIL ROCKTOT = 0
	BNE	GAMEPLAY
	LDA	STATUS+25	;WAIT FOR UFO TO LEAVE BEFORE NEW RACK
	CMP	#$FF		;FF = NON-EXISTANT
	BNE	GAMEPLAY	;IF HE EXISTS, JUST WAIT IN GAMEPLAY
	LDA	STATE		;IF EITHER PLAYER IS IN STATE 0 OR 1
	AND	STATE+1		; (THAT IS, OK OR BIRTH)
	CMP	#2		; THEN THIS 'AND' WILL BE LESS THAN 2
	BCS	GAMEPLAY	; IF IT ISN'T, THEN WAIT IN GAMEPLAY
	LDA	MODE
	BNE	ZDECRDLY	;IN TWO PLAYER, DON'T CREATE ROCKS
	LDY	OFFPLAY2	; IF CURRENT PLAYER IS DEAD, SO AS
	LDA	STATUS+24,Y	; NOT TO CREATE ROCKS AND IMMEDIATELY
	BMI	GAMEPLAY	; SWITCH THEM OUT.
ZDECRDLY:
	DEC	RACKDLY		;DON'T DO NEW RACK 'TILL DLY OVER
	BPL	GAMEPLAY	;LET THE SHOW GO ON !
	LDA	#RACKDLYC	;PRIME TIMER FOR NEXT RACK
	STA	RACKDLY
	INC	RACKNUM,X	;WHEN =0 NEW RACK

	LDA	RACKNUM,X	;SET NUM OF ROCKS TO BE RACKNUM
	CLC
	ADC	#2		;  PLUS TW0
	ADC	DIFF		;  PLUS DIFF (NOVICE=0,EXPERT=3)
	STA	ROCKTOT,X
	LDY	DIFF		;DETERMINE MAX NUMBER OF ROCKS
	LDA	MAXROCKS,Y
	CMP	ROCKTOT,X	; UP TO A MAXIMUM
	BCS	NEWRACK
	STA	ROCKTOT,X

NEWRACK:
	STA	STARTNUM,X
	JSR	LOADSTAR	;LOAD STARS INTO DISPLAY HEADERS.

	LDA	#1		;TYPE 1 INCREMENT FOR RACK
	JSR	INCLVL

	LDA	#$50		;5.2 SEC COUNTER FOR UFO
	STA	RTIMER
	LDX	DIFF
	LDA	UTIMES,X	;UFO
	LDX	PLAYER
	SEC
	SBC	RACKNUM,X
	SBC	RACKNUM,X
	SBC	RACKNUM,X
	STA	SDELAY
	STA	EDELAY

	LDA	#9
	STA	UFOACC		;SET ACCURACY DOWN TO MINIMUM
	LDA	#$28		;INITIALIZE UFO SHOT COUNTDOWN
	STA	USHOTCNT

	JSR	INITHUMP	;RESET THE HUMP RATE.
	JSR	INITROCK	;INITIALIZE THE ROCKS


GAMEPLAY:
	JSR	FSM		;FINITE STATE MACHINE
	JSR	JOY		;EXECUTE JOYSTICK INPUTS
	LDA	MODE		;REPEAT FOR TEAM PLAY MODES
	CMP	#1
	BMI	NOTEAM
	JSR	FLIPPLAY	;FLIP PLAYER
	JSR	FSM		;REPEAT FOR OTHER PLAYER
	JSR	JOY
	JSR	FLIPPLAY
NOTEAM:
	JSR	ROCKMOVE	;UPDATE OBJECT MOVEMENT
	JSR	SHOTMOVE	;UPDATE SHOT MOVEMENT
	JSR	COLLIDE		;CHECK COLLISIONS
	JSR	EXPLODE		;CHECK EXPLOSIONS
	JSR	UFO		;UPDATE UFO
	JSR	BACKSNDS	;ADD BACKGROUND SOUNDS
	RTS

MAXROCKS:
	.DC.B	8,12,14,16	;MAX NUM ROCKS FOR EACH DIFF
UTIMES:
	.DC.B	0,$A7,$95,$8F

** DIFFICULTY LEVEL INCREMENT ROUTINE **
** CALLED WITH TYPE OF INCREMENT IN AC, TRASHES Y **
**	   TYPES: 0 = POINTS, 1 = RACKS, 2 = MR. BILL, 3 = SLUGGO **
INCLVL:
	TAY
	LDA	LVLINC,Y
	LDY	PLAYER
	CLC
	ADC	LEVEL,Y
	CMP	MAXLVL		;THERE IS ONLY ONE MAX FOR BOTH PLAYERS
	BCC	LVLOK
	LDA	MAXLVL
LVLOK:
	STA	LEVEL,Y
	RTS

** RANDOM NUMBER ROUTINES, >NOT< PREVIOUSLY IN RANDOM.S **
* NEWRAND: A WHOLESOME RANDOM NUMBER JENERATER FROM KNUTH (NOTABLE PEDIGREE)
NEWRAND:
	LDY	RANDPTR0	;LOAD Y WITH CONTENTS OF RANDPTR0
	LDA	RAND,Y		;LOAD AC WITH RAND INDEXED BY Y
	CLC			;CLEAR THE CARRY
	LDY	RANDPTR1	;LOAD Y WITH CONTENTS OF RANDPTR1
	ADC	RAND,Y		;ADD RAND INDEXED BY Y TO AC
	LDY	RANDPTR0	;GET THE DRIFT?
	STA	RAND,Y
	DEC	RANDPTR0
	BPL	ZR1
	LDY	#54
	STY	RANDPTR0
ZR1:
	DEC	RANDPTR1
	BPL	ZR2
	LDY	#54
	STY	RANDPTR1
ZR2:
	RTS


RANDPOS:
	JSR	NEWRAND
	LSR
	BCC	HBORDER

	LDA	#YPOSMAX
	STA	YPOSH,X
XRANDLOP:
	JSR	NEWRAND
	CMP	#XPOSMAX-6
	BCS	XRANDLOP
	STA	XPOSH,X
	RTS

HBORDER:
	LDA	#XPOSMAX
	STA	XPOSH,X
YRANDLOP:
	JSR	NEWRAND
	CMP	#YPOSMAX
	BCS	YRANDLOP
	STA	YPOSH,X
	RTS

RANDVEL:
	JSR	NEWRAND
	ROL			;USE SIGN BIT FOR DIRECTION (L OR R)
	BCC	RNDVXPOS	;X VELOCITY IS POSITIVE
	SBC	MINXVEL		;ADD IN MINIMUM VELOCITY
	STA	XVELL,X
	LDA	#$FF		;VELOCITY IS NEGATIVE
	SBC	#0		;TAKE AWAY THE BORROW, IF ANY
	STA	XVELH,X
	BCS	RANDVY		;UNCOND. BRANCH
RNDVXPOS:
	ADC	MINXVEL		;ADD IN MINIMUM VELOCITY
	STA	XVELL,X
	LDA	#0
	ROL			;ROL IN THE CARRY, IF ANY
	STA	XVELH,X

RANDVY:
	JSR	NEWRAND
	ROL
	BCC	RNDVYPOS
	SBC	MINYVEL
	STA	YVELL,X
	LDA	#$FF
	SBC	#0
	STA	YVELH,X
	BCS	RANDVRTS
RNDVYPOS:
	ADC	MINYVEL
	STA	YVELL,X
	LDA	#0
	ROL
	STA	YVELH,X

RANDVRTS:
	RTS


* CHECK IF ANY OBJECT IS IN SAFETY BOX.
* RETURNS WITH ZERO (Z) BIT SET IF ALL IS CLEAR.
* WE DON'T WORRY ABOUT CARRIES (LOW PRECISION).
* DESTROYS: X, Y, AND FIRST 7 BYTES OF TEMP
* TEMP LAYOUT:    TEMP		    X (OBJECT INDEX)
*		  TEMP+1		  BOXR (RIGHT HAND BOUNDARY)
*		  TEMP+2		  BOXL (LEFT HAND BOUNDARY)
*		  TEMP+3		  BOXTOP (TOP BOUNDARY)
*		  TEMP+4		  BOXBOT (BOTTOM BOUNDARY)
*		  TEMP+5		  X WRAP FLAG (1 = WRAP)
*		  TEMP+6		  Y WRAP FLAG (1 = WRAP)

ISSAFE:
	STX	TEMP		;SAVE X WHERE IT MAY BE COMPARED TO Y

	LDA	#0		;0 MEANS "NO WRAP OF BOX"
	STA	TEMP+5
	STA	TEMP+6

	LDA	XPOSH,X		;CHECK RIGHT HAND SIDE OF BOX.
	ADC	BOXWIDTH	; (SHOULD CLC HERE....)
	STA	TEMP+1		;BOXR
	SBC	#XPOSMAX	;CHECK FOR WRAPAROUND.
	BCC	BOXROK		; BOX'S RIGHT HAND SIDE: NO WRAP.
	INC	TEMP+5		; YES WRAP: SET FLAG
	STA	TEMP+1
BOXROK:

	LDA	XPOSH,X		;CHECK LEFT HAND SIDE OF BOX.
	SBC	BOXWIDTH
	BCS	BOXLOK		;CHECK FOR WRAPAROUND.
	INC	TEMP+5		; YES WRAP: SET FLAG
	ADC	#XPOSMAX	; MOD INTO RANGE
BOXLOK:
	STA	TEMP+2		;  AND SAVE IT (BOXL).


	LDA	YPOSH,X		;CHECK TOP OF BOX.
	ADC	BOXHIGHT
	STA	TEMP+3
	SBC	#YPOSMAX
	BCC	BOXTOK
	INC	TEMP+6
	STA	TEMP+3
BOXTOK:

	LDA	YPOSH,X		;CHECK BOTTOM OF BOX.
	SBC	BOXHIGHT
	BCS	BOXBOK
	INC	TEMP+6
	ADC	#YPOSMAX
BOXBOK:
	STA	TEMP+4


	LDX	#32		;START WITH LAST OBJECT (#32)
NEXTSAFE:
	LDA	STATUS,X	;CHECK ITS STATUS:
	BMI	SAFEOK		; IF OBJECT DOESN'T EXIST, IT IS SAFE.

	;FIRST CHECK X COORDS
	LDA	#0		;CLEAR OUT COMPARISON REGISTER "A"
	LDY	XPOSH,X		;GET OBJECT X'S HORIZ. POSITION
	CPY	TEMP+1		;COMPARE TO BOXR
	ROL			;ROL BIT INTO A
	CPY	TEMP+2		;COMPARE TO BOXL
	ADC	#0		;ADD BIT INTO A
	EOR	TEMP+5		;FLIP LOW BIT WITH X WRAP BIT
	ROR			;ROR BIT INTO CARRY
	BCC	SAFEOK		;NO BIT MEANS SAFE (OUTSIDE OF BOX).

	;THEN CHECK Y COORDS
	LDA	#0
	LDY	YPOSH,X
	CPY	TEMP+3
	ROL
	CPY	TEMP+4
	ADC	#0
	EOR	TEMP+6
	ROR
	BCC	SAFEOK

	;FINALLY, CHECK IF IT IS THE OBJECT SPECIFIED ITSELF.
	CPX	TEMP
	BEQ	SAFEOK

	;OBJECT IN BOX!  UNSAFE TO ENTER!
;	LDY	#1		;CLEAR Z BIT TO SIGNIFY NOT CLEAR.
				;NOT NEEDED (BEQ ABOVE)
	RTS

SAFEOK:
	DEX			;GET NEXT OBJECT
	BPL	NEXTSAFE	;AND CONTINUE CHECKING

	LDY	#0		;SET Z BIT TO SIGNIFY ALL CLEAR.
	RTS

BOXWIDTH:
	.DC.B	$10
BOXHIGHT:
	.DC.B	$1A

* ROUTINE TO PUT UP SCORES.  WHATEVER IS IN PLAYER OR HIGH SCORES GOES. *
DOSCORE:
	JSR	CLSCORE		;ERASE ALL SCORES FIRST

	JSR	PUTHISCR	;HIGH SCORE UP

	LDA	MODE
	CMP	#1		;COMBINED SCORE
	BNE	ZPLRSCOR
	LDA	#2
	STA	SCORER
	JSR	PUTSCORE
	JSR	PUTMEN
	LDA	#0
	STA	SCORER
	JSR	PUTSCORE
	LDA	#1
	STA	SCORER
	JSR	PUTSCORE
	RTS

ZPLRSCOR:
	LDA	#0
	STA	SCORER
	JSR	PUTSCORE	;PLAYER 1 SCORE UP
	JSR	PUTMEN

	LDA	MODE
	BMI	NOP2SCOR
	LDA	#1
	STA	SCORER
	JSR	PUTSCORE	;PLAYER 2 SCORE UP
	JSR	PUTMEN

NOP2SCOR:
	RTS

* ROUTINE TO ERASE SCORES. *
CLSCORE:
	LDX	#56		;CLEAR MAPS
	LDA	#0
ZCLRLOOP:
	STA	CHARMAPS,X
	DEX
BPLOP:
	BPL	ZCLRLOOP	;LABLED TO ACCESS BPL OPCODE ($10)
	RTS

** ROUTINE USED IN GAME LOOP TO TOGGLE PLAYER BACK AND FORTH. **
FLIPPLAY:
	LDA	PLAYER		;CHANGE PLAYER
	EOR	#1
	STA	PLAYER
	BEQ	STOROFF		;ESTABLISH DATA OFFSET
	LDA	#8		;SECOND PLAYER POINTS TO END
STOROFF:
	STA	OFFPLAY2
	RTS

* ROTATE THROUGH THE COLORS TO TWINKLE THE STARS.
TWINKLE:
	JSR	NEWRAND		;DECIDE WHICH STARS TO TW'INC'LE
	LSR
	BCC	NOINC2
	LSR
	BCC	NOINC2
	INC	SOFTCOLR+14

NOINC2:
	LSR
	BCC	LOGODO
	LSR
	BCC	LOGODO
	INC	SOFTCOLR+15

LOGODO:
	LDA	GAMSTATE	;DON'T DO LOGOBARS WHILE PLAYING
	CMP	#PLAYST
	BEQ	LOGORTS
	CMP	#AUTOST
	BEQ	LOGORTS

LOGOBARS:
	LDA	FRMCNT		;DO IT ONLY ON EVEN FRAMES
	LSR
	BCS	LOGORTS
	INC	TEMP+11		;MOVE THIS!!
	LDA	TEMP+11
	BIT	BPLOP		;(BPLOP: OPCODE $10 IS BPL)
	BNE	LOGOGO
	EOR	#$1F
LOGOGO:
	STA	SOFTCOLR+10	;UPDATE HARDWARE REGISTER
LOGORTS:
	RTS


* SET UP AN ICON:
*	    ON ENTRY: Y SHOULD CONTAIN ICON NUMBER
*		    X SHOULD CONTAIN INDEX NUMBER OF NEW OBJECT
DOICON:
	LDA	ICONACYC,Y
	STA	ACYC,X
	LDA	ICONXPOS,Y
	STA	XPOSH,X
	LDA	ICONYPOS,Y
	STA	YPOSH,X
	LDA	ICONPALS,Y
	STA	PALS,X
	LDA	#ICON
	CPY	#22		;ICONS > 22 ARE SHIPS
	BCC	ZISICON
	LDA	#SHIP
ZISICON:
	STA	STATUS,X
	RTS

* PAINTSHP -- PAINT THE SHIP, BODY AND DEJAG AND FLAME COLORS
*	    ARGUMENTS: X CONTAINS THE PLAYER TO PAINT
*		A CONTAINS THE DESIRED LUME OF THE BODY
PAINTSHP:
	AND	#$0F		;KNOCK OFF EXTRANEOUS BITS
	ORA	BODYHUES,X	;OR IN THE CORRECT BODY HUE
	PHA			;PUSH BODY COLOR
	LSR			;LOWER INTENSITY FOR DEJAG LUME
	AND	#$07		;KNOCK OFF EXTRANEOUS BITS
	ORA	BODYHUES,X	;OR IN THE CORRECT BODY HUE
	CPX	#0		;WHICH PLAYER?
	BEQ	ZPAINTGO	;FOR 1ST PLAYER, USE 1ST PALETTE
	LDX	#4		;FOR 2ND PLAYER, USE 2ND PALETTE
ZPAINTGO:
	STA	SOFTCOLR+3,X	;STORE DEJAG COLOR
	PLA			;PULL BODY COLOR
	STA	SOFTCOLR+2,X	;STORE BODY COLOR
	LDA	#0		;TURN OFF SHIP'S THRUST FLAME
	STA	SOFTCOLR+1,X
	RTS

* REFRESH COLOR RAM, UPPER 4 PALETTES FROM ROM, LOWER 4 FROM RAM
REFRESH:
	LDX	#$1F
ZEFRESH:
	LDA	COLORS,X
	STA	BACKGRND,X
	DEX
	LDA	COLORS,X
	STA	BACKGRND,X
	DEX
	LDA	COLORS,X
	STA	BACKGRND,X
	DEX
	DEX			;SKIP OVER OTHER HARDWARE REGISTERS
	CPX	#$10		;$10 - $1F FROM ROM (COLORS)
	BCS	ZEFRESH
* NOW DO RAM PART:
Z2FRESH:
	LDA	SOFTCOLR,X
	STA	BACKGRND,X
	DEX
	LDA	SOFTCOLR,X
	STA	BACKGRND,X
	DEX
	LDA	SOFTCOLR,X
	STA	BACKGRND,X
	DEX
	DEX			;SKIP OVER OTHER HARDWARE REGISTERS
	BPL	Z2FRESH
	INX			;$FF + 1 = $00
	STX	BACKGRND	;FORCE BLACK BACKGROUND
	RTS

WAITLOAD:
	LDA	#1		;SET LOAD FLAG
	STA	LOADFLAG
ZWAIT:
	LDA	LOADFLAG	;WAIT FOR LOADER TO FINISH
	BEQ	ZWRTS		;IF LOADER FINISHED THEN RTS
	BIT	MSTAT		;IF OFF SCREEN FORCE LOAD
	BPL	ZWAIT
	BIT	MSTAT		;PROTECTION
	BPL	ZWAIT
	JSR	REFRESH		;MAKE SURE COLORS ARE RIGHT FIRST
	JSR	LOADER
ZWRTS:
	RTS
