*	    1830    040784
*
** FSM.S **
** ASTEROIDS FOR THE ATARI 3600 **
** THIS FILE CONTAINS THE FINITE STATE MACHINE FOR ASTEROIDS. **
** GAME SEQUENCER TO HANDLE INDIVIDUAL PLAYER'S EVENT TIMING. **


FSM:
	LDX	PLAYER		;PLAYER MUST CONTAIN CURRENT PLAYER
	LDA	STATE,X		;CURRENT STATE OF PLAYER
	BEQ	CKCOMPLY	;CHECK IF COMP PLAY
	BPL	DECTIMER	;IF IN ACTIVE STATE THEN TAKE ACTION
	RTS			;IF MINUS, RTS (I GUESS)

DECTIMER:
	DEC	TIMER,X		;DECREMENT EVENT TIMER
	CMP	#BIRTH		;BIRTH STATE?
	BEQ	BIRTHD
	CMP	#HYPER		;HYPERSPACE STATE?
	BNE	ZCKCOMP
	JMP	HYPERD
ZCKCOMP:
	CMP	#COMPOVER	;COMP PLAY OVER?
	BNE	ZCKDTH
	JMP	COVERD
ZCKDTH:
	CMP	#DEATH		;DEATH STATE?
	BNE	FSMRTS
	JMP	DEATHD
FSMRTS:
	RTS

CKCOMPLY:
	LDA	COMPFLAG	;CHECK IF ANYBODY DIED YET
	BEQ	FSMRTS
	JSR	CMPSCOR		;COMPARE SCORES
	BMI	FSMRTS
	CMP	PLAYER		;HISCORE = FIRST TO DIE?
	BNE	FSMRTS		;YES, CONTINUE PLAY
	TAX
	LDA	#COMPOVER
	STA	STATE,X		;STATE IS REZ OUT VICTOR
	LDA	#$FF
	STA	COMPFLAG
	LDA	#0
	STA	MENLEFT,X	;NO MORE LIVES
	LDA	#$0D
	STA	FLASH
	LDA	#$0
	JSR	DOTUNE		;VICTOR REZOUT SOUND
	RTS

CMPSCOR:
	LDX	#0		;COMPARE SCORES
CMPSLOOP:
	LDA	SCORE,X		;FIRST SCORE
	CMP	SCORE2,X	;SECOND SCORE
	BCC	P2BIGGR		;SCORE < SCORE2
	BEQ	BUMPX
	BCS	P1BIGGR		;SCORE > SCORE2
BUMPX:
	INX			;LOOK AT NEXT BYTE
	CPX	#5
	BNE	CMPSLOOP
	LDA	#$FF		;SCORE = SCORE2
	RTS
P2BIGGR:
	LDA	#1
	RTS
P1BIGGR:
	LDA	#0
	RTS

** BIRTH DISPACHER - HANDLES TIMING OF BIRTH EVENTS. **
BIRTHD:
	LDY	OFFPLAY2	;IF PLAYER IS NOT THERE, DON'T
	LDA	STATUS+24,Y	; DO REZ TWINKLE
	BMI	ZNOREZ

	;DO REZ TWINKLE
	LDA	#$05		;DEFAULT LUME FOR AUTOPLAY
	LDY	GAMSTATE
	CPY	#PLAYST
	BNE	ZREZGO		;IF NOT IN PLAY STATE, DO AUTO REZ
	LDA	FRMCNT		;USE FRAME COUNT LO BITS FOR LUME
	ASL
ZREZGO:
	JSR	PAINTSHP	;PAINT THE SHIP, BODY AND DEJAG COLORS
	LDX	PLAYER
ZNOREZ:
	LDA	TIMER,X		;CHECK TIMER TO DISPATCH
	CMP	#PMSGT		;TIME TO PUT UP PLAYER MESSAGE?
	BEQ	PMSG		; YES, PUT IT UP
	CMP	#PMSGOFFT	;TIME TO TAKE DOWN MESSAGE?
	BEQ	PMSGOFF		; YES, TAKE IT DOWN
	CMP	#RESINT		;TIME TO RES IN?
	BEQ	RESIN		; YES, RES IN.  IF LATER THAN RESINT,
	BCC	OPTENTER	; CHECK FOR OPTIONAL ENTER (JSTICK)
	RTS			;OTHERWISE, JUST RTS

* ROUTINE TO PUT UP THE PLAYER X MESSAGE IF NEEDED. *
PMSG:
	LDA	MODE		;NO MESSAGES IN TEAM MODES
	CMP	#1
	BPL	ZPLRTS
	JSR	SETMSG
ZPLRTS:
	RTS

* ROUTINE TO TURN PLAYER X MESSAGE OFF. *
PMSGOFF:
	LDA	#$FF		;TURN OFF HIGH MESSAGE
	STA	STATUS+34
	RTS


* ROUTINE TO ENTER THE SHIP IF DESIRED OR NEEDED. *
OPTENTER:

	LDA	GAMSTATE	;DO ONLY IF GAMEPLAY STATE
	CMP	#PLAYST
	BNE	ZCKTIMM

	;FIRST CHECK TO SEE IF PLAYER IS FORCING SHIP IN
	LDA	FIREBUT1,X	;FIRE BUTTON
	AND	HYPBUT1,X	;HYPERSPACE BUTTON
	BPL	ENTSHIP		; IS PRESSED! ENTER HIM
	LDA	SWCHA		;JOYSTICK
	EOR	#$FF		; (INVERTED)
	AND	JOYTBL,X	; (LOOK AT ONLY CORRECT PLAYER'S BITS)
	BNE	ENTSHIP		; IS HIT! ENTER HIM

	;NOW CHECK IF IT IS TIME, AND IS SAFE.
ZCKTIMM:
	LDA	TIMER,X		;CHECK TIMER
	CMP	#ENTERT
	BCS	ENTRTS		;NOT TIME YET, DON'T BOTHER

	LDA	OFFPLAY2	;CHECK SAFTEY
	CLC
	ADC	#24
	TAX
	JSR	ISSAFE		;CHECK IF AREA SAFE TO ENTER
	BEQ	ENTSHIP		;YES, CONTINUE

	;NOT SAFE, HOLD TIMER HERE INDEFINITELY
	LDX	PLAYER
	INC	TIMER,X
ENTRTS:
	RTS

ENTSHIP:
	LDA	#2		;KILL TWINKLING
	JSR	KILLTUNE
	LDA	#$3		;ADD BUZZING IN
	JSR	DOTUNE

	LDA	PLAYER		;CHANGE BODY COLOR
	ASL
	ASL
	TAX
	LDA	COLORS+2,X
	STA	SOFTCOLR+2,X
	LDA	COLORS+3,X
	STA	SOFTCOLR+3,X

	LDX	PLAYER
	LDA	#1		;DEBOUNCE ENTER/FIRE BUTTON
	STA	FIRESTAT,X

	LDA	#OK		;SET STATE AS OK
	STA	STATE,X
	RTS

** ROUTINE TO RESIN AND TWINKLE SHIP AT ENTERING. **
RESIN:
	LDA	STATUS+25	;CHECK STATUS OF UFO
	BMI	ZGONOW		;DON'T BRING SHIP IN IF UFO
	INC	TIMER,X
	RTS

ZGONOW:
	LDA	GAMSTATE	;DON'T DECREMENT IF AUTOPLAY
	CMP	#AUTOST
	BEQ	ZNODECM
	LDA	MODE		;CHECK TO DEC FROM COMMON POOL
	CMP	#1
	BNE	ZNOPOOL
	LDA	MENLEFTC	;CHECK: IF NO MENLEFT, JUST HANG OUT
	CMP	#1		; AND WAIT; PERHAPS OTHER PLAYER WILL
	BCS	ZYESMEN		; BRING HIM IN A LIFE.
	INC	TIMER,X		; (HOLD TIMER AT THIS POINT IN TIME)
	RTS

ZYESMEN:
	LDX	#2		;2 = COMMON POOL
ZNOPOOL:
	DEC	MENLEFT,X	;DEC FROM PLAYERS LIVES
	JSR	UPDATMEN

ZNODECM:
	LDA	#2		;TWINKLING SOUND
	JSR	DOTUNE


ZINITPOS:
	LDX	OFFPLAY2	;INITIALIZE THE SHIP'S POSITION
	LDA	#0
	STA	XVELH+24,X
	STA	YVELH+24,X
	STA	XVELL+24,X
	STA	YVELL+24,X
	STA	GOATMILK	;??
	LDA	MODE
	CMP	#1
	BMI	ZCENTERS
	LDY	PLAYER
	LDA	INITSX,Y	;GET X POS VALUE FOR PLAYER
	BPL	ZSTORSX		;BPL = JMP HERE.
ZCENTERS:
	LDA	#$50
ZSTORSX:
	STA	XPOSH+24,X
	CLC
	ADC	DELTAX+3	;COULD SQUEEZE A BYTE HERE: USE IMMED.
	STA	COLXPOSH+24,X
	LDA	#$50
	STA	YPOSH+24,X
	CLC
	ADC	DELTAY+3	;COULD SQUEEZE HERE TOO.
	STA	COLYPOSH+24,X

	LDX	PLAYER		;STORE FIRST ANIMATION
	LDA	SHIPDIR,X
	LSR
	LSR
	LSR
	AND	#$FE
	CLC
	ADC	#SHIP1 & 255
	LDX	OFFPLAY2
	STA	ACYC+24,X

	LDA	#SHIP		;STORE STATUS AS SHIP
	STA	STATUS+24,X

	RTS


INITSX:
	.DC.B	$30,$70		;XPOS VALUES FOR INITIAL SHIP POS
JOYTBL:
	.DC.B	$F0,$0F		;JSTICK MASKS, INDEXED BY PLAYER.


** HYPER SPACE DISPACHER - HANDLES TIMING OF HYPER SPACE EVENTS. **
HYPERD:
	LDA	TIMER,X		;CURRENT PLAYERS EVENT TIMER
	CMP	#HYPERT		;TIME TO JUMP HYPERSPACE?
	BEQ	HYPERGO		; YES, DO IT.
	CMP	#HYPENDT	;TIME TO END HYPERSPACE
	BEQ	HYPEND		; YES, DO IT.
	RTS			;OTHERWISE, JUST RTS

* ROUTINE TO HANDLE THE JUMP TO HYPERSPACE. *
HYPERGO:
	LDA	#$01		;SOUND
	JSR	DOTUNE

	LDX	OFFPLAY2	;NULL OUT SHIP
	LDA	#$FF
	STA	STATUS+24,X

	LDA	#0		;NULL VELOCITY
	STA	XVELL+24,X
	STA	XVELH+24,X
	STA	YVELL+24,X
	STA	YVELH+24,X

	RTS


* ROUTINE TO HANDLE THE RETURN FROM HYPERSPACE. *
HYPEND:
	LDA	#24
	CLC
	ADC	OFFPLAY2
	TAX
	JSR	NEWRAND		;GET NEW SHIP POSITION
	LSR			; AVOID EXTREME SIDES
	ADC	#$D		; (BETWEEN $D AND $8C)
	STA	XPOSH,X
	JSR	NEWRAND		;GET Y POSITION; AVOID TOP AND BOTTOM
	LSR
	ADC	#$10		; (BETWEEN $10 AND $90)
	STA	YPOSH,X
	JSR	ISSAFE		;SAFE TO ENTER
	BEQ	GOBIGRED	;YOU BET
	LDX	PLAYER		;SORRY CHARLIE
	INC	TIMER,X
	RTS
GOBIGRED:
	JSR	NEWRAND		;GET RANDOM VALUE
	CMP	#50		;SOMETIMES LET THE SHIP EXPLODE
	BCS	NOBLOW		;OTHERWISE SET NEW POSITION

	;EXPLODE HIM!
	LDA	#24		;WITHOUT THIS X = 'FF' SOMETIMES
	CLC
	ADC	OFFPLAY2
	TAX
	LDA	#$A3		;BOOM !! SET HIGH BIT OF STATUS
	STA	STATUS,X
	LDA	ELBOUND+3	;SET ANIMATION STAMP
	STA	ACYC,X
	LDA	#5		;START SHIP EXPLOSION SOUND
	JSR	DOTUNE
	LDX	PLAYER
BLOW:
	LDA	#DEATH		;SET STATE
	LDX	PLAYER
	STA	STATE,X
	LDA	#DIET+$28	;ENTER TIMELINE AT TOP
	STA	TIMER,X
	RTS

NOBLOW:
	LDA	#3		;BUZZ SOUND
	JSR	DOTUNE
	LDA	#SHIP		;RESTORE SHIP
	LDX	TEMP
	STA	STATUS,X
	LDX	PLAYER
	LDA	#OK		;RETURN STATE TO OK.
	STA	STATE,X
	RTS


** COMP PLAY OVER DISPACHER - HANDLES TAKING SHIP OUT. **
COVERD:
*	LDX	PLAYER
	LDA	FLASH
	INC	FLASH
	CMP	#$20
	BEQ	ZTAB
	CMP	#$2E
	BNE	CCONTIN		;ALL DONE
	JMP	BLOW		;JUMP INTO HYPER CODE
CCONTIN:
	BIT	BPLOP
	BEQ	DOPAINT
	EOR	#$1F
DOPAINT:
	JSR	PAINTSHP
	RTS
ZTAB:
	LDX	OFFPLAY2	;NUKE SHIP
	LDA	#$FF
	STA	STATUS+24,X
	RTS

** DEATH DISPACHER - HANDLES TIMING OF DEATH SEQUENCE. **
DEATHD:
	LDA	TIMER,X		;CURRENT PLAYERS EVENT TIMER
	CMP	#DIET		;TOP OF DEATH TIMELINE?
	BEQ	DIE		; YES, GO TO DIE HANDLER
	CMP	#SWITCHT	;TIME TO SWITCH PLAYER?
	BNE	ZCKPOT
	JMP	SWITCH		; YES, SWITCH.
ZCKPOT:
	CMP	#POMSGT	;TIME TO DISPLAY PLAYERX OVER?
	BNE	ZCOKE
	JMP	POMSG		; YES, DO IT.
ZCOKE:
	CMP	#POMSGOFT	;TIME TO TURN OFF MESSAGE?
	BEQ	POMSGOFF	; YES, DO IT.
	CMP	#GOVERT		;TIME TO DISPLAY GAME OVER MESSAGE?
	BEQ	GOVER		; YES, DO IT.
	CMP	#NEWGAMET	;END OF DEATH TIMELINE?
	BNE	DEATHRTS
				;YES, SET UP FOR HIGH SCORE CART
	JSR	CLEARTUN	;GET RID OF ANY TUNES
	JSR	NULLOBJS	;GET RID OF ANY OBJECTS
	JSR	HSCDOENT
	JMP	DOTITLE
DEATHRTS:
	RTS


* ROUTINE TO TAKE DOWN THE ABOVE *
POMSGOFF:
	LDA	#$FF		;NULL OUT BOTH MESSAGES
	STA	STATUS+34
	STA	STATUS+35

	TXA			;CHECK OTHER PLAYER FOR GAME OVER COND.
	EOR	#$01		; HERE'S HOW IT WORKS: ONLY ONE PLAYER
	TAY			; ACTUALLY MAKES IT TO THE GAME OVER
	LDA	#DEAD		; MESSAGE TIME.  SO, THE FIRST PLAYER
	CMP	STATE,Y		; TO MAKE IT TO POMSGOFF BECOMES DEAD
	BEQ	DEATHRTS	; THE OTHER LIVES ON TO GET TO GOVER!
	STA	STATE,X		;MAKE PLAYER DEAD, SINCE OTHER IS LIVE.
	LDA	MODE		;IN TWO PLAYER MODE, SWITCH DATA NOW
	BNE	DEATHRTS	; SO WE DON'T GET STUCK PLAYING
	JMP	SWITCH		; A DEAD PLAYER (FSM WON'T RUN ON HIM)
	RTS

* ROUTINE TO PUT UP GAME OVER MESSAGE *
GOVER:
	LDX	#2		;GAME OVER MESSAGE
	JSR	SETMSG
	JSR	HIGHSCOR
	RTS

* ROUTINE TO HANDLE DEATH OF A SHIP. *
* ALL DEATHS GO HERE.  THIS ROUTINE FIGURES OUT WHERE WE SHOULD BE GOING. *
DIE:
	JSR	INITHUMP	;REINIT THUMP RATE

	LDA	#$11		;KILL THRUST SOUND
	JSR	KILLTUNE
	LDX	PLAYER		;RESTORE X, TRASHED BY KILLTUNE

	;HANDLE MODES DIFFERENTLY
	LDY	MODE
	LDA	MENLEFTC	;LOAD TEAMPLAY MENLEFT AS DEFAULT
	CPY	#1
	BEQ	ZDIEMN1		;IF NOT TEAMPLAY MODE
	LDA	MENLEFT,X	; USE CURRENT MENLEFT
ZDIEMN1:
	CMP	#1		;IF WE HAVE NO MEN LEFT
	BCC	NOMENLFT	; HANDLE THIS SITUATION
	CPY	#0		;ELSE IF NOT TWO PLAYER MODE
	BNE	GIVEBRTH	; SIMPLY TRY TO GIVE BIRTH.

	TXA			;ELSE TWO PLAYER MODE:
	EOR	#$01		; CHECK OTHER PLAYER'S MENLEFT.
	TAX
	LDA	MENLEFT,X
	CMP	#1		; IF HE HAS MEN LEFT THEN
	BCS	DEATHRTS	;  SIMPLY RTS. SWITCH WILL DO THE TRICK
	JMP	GIVBRTH2	; ELES SKIP THE SWITCH.  GIVE BIRTH NOW

NOMENLFT:
	CPY	#$FF		;ELSE, IF ONE PLAYER MODE
	BEQ	DIEGOVER	; DIE WITH SIMPLE GAMEOVER (NO PMSG)
	CPY	#$1		;ELSE, IF NOT IN TEAM PLAY MODE
	BNE	DIEPOVER	; DIE WITH PLAYER OVER MESSAGE
	TXA			;ELSE CHECK OTHER PLAYER'S STATE
	EOR	#$01		; TO SEE WHETHER TO END THE GAME
	TAX
	LDA	STATE,X
	CMP	#BIRTH		; IF OTHER PLAYER IS NOT IN BIRTH
	BNE	GIVEBRTH	;  THEN TRY TO GIVE BIRTH.
	LDA	OFFPLAY2	; OTHERWISE,
	EOR	#$08		;  (TOGGLE OFFPLAY2)
	TAY
	LDA	STATUS+24,Y	;  IF HE IS NOT YET BORN, THEN
	CMP	#SHIP		;  FORGET IT BUD.  AIN'T NO LIVES LEFT
	BEQ	GIVEBRTH	;  FOR EITHER OF THEM.
	LDA	#DEAD		;   NUKE OTHER PLAYER OUT OF BIRTHST
	STA	STATE,X		;   TO PREVENT A NEW RACK FROM STARTING
DIEGOVER:
	LDA	#GOVERT+3	;DIE WITH GAME OVER MESSAGE ONLY
	BNE	ZDIEOVER	; BNE = JMP

DIEPOVER:
	LDA	#POMSGT+3	;DIE WITH PLAYER N GAME OVER MESSAGE
ZDIEOVER:
	LDX	PLAYER
	STA	TIMER,X
	RTS

GIVEBRTH:
	LDX	PLAYER
	LDA	#BIRTH		;GIVE BIRTH
	STA	STATE,X
	LDA	#RESINT+3	;AT TIMER RESIN+3
	STA	TIMER,X
	RTS

* ROUTINE TO PUT UP PLAYERX GAME OVER MESSAGE *
POMSG:
	LDX	PLAYER		;PLAYERX MESSAGE
	LDA	COMPFLAG
	BMI	PVICTOR
	BEQ	PPLAYER
	JSR	CMPSCOR		;COMPARE SCORES
	TAX
	BPL	PVICTOR
;	    TIE SCORE
	LDA	GOATMILK	;CHECK FLAG
	BNE	PUNTTHIS	;SHIP TO SHIP
	LDX	PLAYER		;NO, PUT MESSAGE FOR THIS GUY
	BPL	PVICTOR		; = JMP
PUNTTHIS:
	LDA	#$FF		;RETURN W/OUT MSG IF EQUAL
	STA	STATUS+34	;TAKE MSG DOWN BEFORE SEEN
	STA	STATUS+35
	RTS

PPLAYER:
	JSR	SETMSG
	LDX	#2
DOMSG:
	JSR	SETMSG
	LDX	MODE
	CPX	#2
	BNE	ZPORTS
	STX	COMPFLAG
ZPORTS:
	RTS

PVICTOR:
	JSR	SETMSG		;X HAS PLAYER
	LDX	#3
	BPL	DOMSG		;BPL  =  JMP

* ROUTINE TO SWITCH THE TWO DATA SETS WHEN NEEDED. *
SWITCH:
	TXA			;TOGGLE CURRENT PLAYER # AND OFFSET
	EOR	#$01
	TAX
	STA	PLAYER
	BEQ	ZSTOFFP2
	LDA	#8
ZSTOFFP2:
	STA	OFFPLAY2

	LDA	#$FF		;NULL OUT SPACE OBJECTS
	LDX	#7		; (31-23=8 OBJECTS)
SWCHNULL:
	STA	STATUS+24,X
	DEX
	BPL	SWCHNULL

	LDA	#0
	STA	RACKDLY		;NO DELAY AFTER SWITCH
	LDA	#$50
	STA	RTIMER		;RESET UFO FREQUENCY AND TIMER
	LDA	#$92
	STA	SDELAY
	STA	EDELAY
	JSR	CLEARTUN	;KILL TUNES, ESP. UFO

	LDY	#23
SWCHLOOP:
	LDX	STATUS,Y
	LDA	STATUS2,Y
	STA	STATUS,Y
	TXA
	STA	STATUS2,Y
*
	LDX	ACYC,Y
	LDA	ACYC2,Y
	STA	ACYC,Y
	TXA
	STA	ACYC2,Y
*
	LDX	PALS,Y
	LDA	PALS2,Y
	STA	PALS,Y
	TXA
	STA	PALS2,Y
*
	LDX	XVELH,Y
	LDA	XVELH2,Y
	STA	XVELH,Y
	TXA
	STA	XVELH2,Y
*
	LDX	YVELH,Y
	LDA	YVELH2,Y
	STA	YVELH,Y
	TXA
	STA	YVELH2,Y
*
	LDX	XVELL,Y
	LDA	XVELL2,Y
	STA	XVELL,Y
	TXA
	STA	XVELL2,Y
*
	LDX	YVELL,Y
	LDA	YVELL2,Y
	STA	YVELL,Y
	TXA
	STA	YVELL2,Y
*
	LDX	XPOSH,Y
	LDA	XPOSH2,Y
	STA	XPOSH,Y
	TXA
	STA	XPOSH2,Y
*
	LDX	YPOSH,Y
	LDA	YPOSH2,Y
	STA	YPOSH,Y
	TXA
	STA	YPOSH2,Y

	DEY
	BPL	SWCHLOOP

GIVBRTH2:
	LDX	PLAYER		;GIVE BIRTH, TWO PLAYER STYLE (PMSG)
	LDA	#BIRTH		;GIVE BIRTH
	STA	STATE,X
	LDA	#PMSGT+$20	;AT TIMER PMSGT+20
	STA	TIMER,X

	RTS
