//-------------------------------
// Snakes of Atari Island
//
// Author: Jakub "JKR" Krzak
// Katowice, April 2012
//-------------------------------


	OPT L+
    OPT R+
	
    ICL 'Macros.asm'
    ICL 'Consts.asm'

;--------------------------------------------------------
; Zero page variables
    
    ORG $80
    
_arr 			.ds 2 ;used for accessing arrays

SnW_Hx 			.ds 1
SnW_Hy			.ds 1
SnW_Tx			.ds 1
SnW_Ty			.ds 1
SnW_Dir			.ds 1
SnW_tmpDir		.ds 1
SnW_State		.ds 1
SnW_Score		.ds 2

SnB_Hx			.ds 1
SnB_Hy			.ds 1
SnB_Tx			.ds 1
SnB_Ty			.ds 1
SnB_Dir			.ds 1
SnB_tmpDir		.ds 1
SnB_State		.ds 1
SnB_Score		.ds 2

cSSt_Grow equ 1
cSSt_Dead equ 2
cSSt_Fast equ 4

GameCntrFast	.ds 1
GameCntr		.ds 1

_selectedMode 	.ds 1
_selectedArea 	.ds 1
Level			.ds 1
LevDelay		.ds 1
LevelTmp 		.ds 1
HiScore 		.ds 2

fruitExtraCntr	.ds 1
fruitExtra_X 	.ds 1
fruitExtra_Y 	.ds 1
fruit_Y 		.ds 1

_mute 			.ds 1

_bgrndColorPtr 	.ds 1
_bgrndClr 		.ds 1

; multi purpose variables
__x 	.ds 1
__y 	.ds 1
__z 	.ds 1
__a 	.ds 1
__b 	.ds 1
__c 	.ds 1

_tmpState 		.ds 1

tmrBase 		.ds 1
clckSeconds		.ds 1
clckMinutes		.ds 1

_msgNum 		.ds 1
_msgNum2 		.ds 1
tmrDisplMsgs 	.ds 2

_msgFlags 		.ds 1

cMsgUp_Change 		equ 1
cMsgDown_Change 	equ 2
cMsgUp_Blink 		equ 4
cMsgDown_Blink 		equ 8
cMsgUp_SH 			equ 16
cMsgDown_SH 		equ 32

_msgBrLower 	.ds 1
_msgBrUpper 	.ds 1
_tmrMsg 		.ds 1

vcnt 	.ds 1

_sfx_ptr 		.ds 1
_sfx_tmr 		.ds 1


	; Splash screen 
	ICL 'Splash.asm'
    ICL 'CMC.asm'
	INI Splash

	
    ORG $2e0
    dta a(Main)

    ORG $2000

    ICL 'Screen.asm'
    ICL 'Misc.asm'
    ICL 'include\STDLib.asm'
    ICL 'VBI.asm'
   
Main
   
    mva #0 _scrL25

    mva #0 _selectedMode

    mwa #$FFFF HiScore

	mvza fruitExtraCntr
	mvza fruitExtra_X
	mvza fruitExtra_Y
	mvza fruit_Y

	mvza _mute
	mvza _bgrndColorPtr
	getColor #0 _bgrndColorPtr
	sta _bgrndClr

    mvza _selectedArea
    mvza tmrBase
    mwa #0 tmrDisplMsgs

    mvza _msgNum
    mvza _msgNum2
    mvza _msgFlags
    mva #cMaxMsgBrtnss _msgBrLower
    mva #cMaxMsgBrtnss _msgBrUpper
    mvza _tmrMsg

    mvza vcnt

    mvza _sfx_ptr
    mvza _sfx_tmr

    mwa #DList SDLSTL ; set DL

   	mvza COLOR0+2
   	mvza COLOR0+5
   	mva #$F0 COL_BK_S
   	mva #$F0 COL_PF2_S
	mva #14 HSCROL
   
    ; select characters set
    lda #>fontFile
    sta CHBAS        

    ; set VBI vector
    mva #0 NMIEN
    mwa #VBI_Proc VVBLKD
    mva #64 NMIEN
   
    jsr CMC_Init
   
   
loopMain:

	#if .byte _mute = #0
		ldx #0
		jsr CMC_PlaySong
	#end
	
loopTP:
    
    jsr TitlePage
    
    jsr SelectionPage
     jcc loopTP
    
	jsr CMC_Stop
    
    jsr GameProcedure

     jmp loopMain


   .align 1024
fontFile:
   ins 'include\snake.fnt'
   
      
 .array arrPosHLL .byte
    54
    90
    130
    166
    .enda
    
 .array arrPosHLR .byte
    58
    98
    134
    170
    .enda
   
   ICL 'fields'

arrSnakeFldW		.ds 40*24
arrSnakeFldW_End
 
arrSnakeFldB		.ds 40*24 
arrSnakeFldB_End

_msg				.ds 41
_msg2				.ds 40

   
_scr_lo:  :25 dta l(_scr + #*40)
_scr_hi:  :25 dta h(_scr + #*40)

ColorSchemes_lo:  :6 dta l(ColorSchemes + #*4)
ColorSchemes_hi:  :6 dta h(ColorSchemes + #*4)

arrFields_lo:  :7 dta l(arrFields + #*36)
arrFields_hi:  :7 dta h(arrFields + #*36)

arrSnakeFldW_lo:  :24 dta l(arrSnakeFldW + #*40)
arrSnakeFldW_hi:  :24 dta h(arrSnakeFldW + #*40)

arrSnakeFldB_lo:  :24 dta l(arrSnakeFldB + #*40)
arrSnakeFldB_hi:  :24 dta h(arrSnakeFldB + #*40)
   
   
drawSnakeBeginW .proc
; __x, __y - head location
; __a - snake's length
	ldx __x
	ldy __y 
	stx SnW_Hx
	sty SnW_Hy
	sty SnW_Ty
	
	dec __a
	
	#if .byte SnW_Dir = #cRight
		txa
		sec
		sbc __a
		sta SnW_Tx
		sta __a
		inc __a
		#while .byte __a < SnW_Hx
			setScrAt __a SnW_Hy #chrBody_H
			setFldW __a SnW_Hy #chrBody_H
			inc __a
		#end
		setScrAt SnW_Hx SnW_Hy #chrHead_R
		setFldW SnW_Hx SnW_Hy #chrHead_R
		setScrAt SnW_Tx SnW_Ty #chrTail_R
		setFldW SnW_Tx SnW_Ty #chrTail_R
		
	#else
	
		txa
		clc
		adc __a
		sta SnW_Tx
		sta __a
		dec __a
		#while .byte __a > SnW_Hx
			setScrAt __a SnW_Hy #chrBody_H
			setFldW __a SnW_Hy #chrBody_H
			dec __a
		#end
		setScrAt SnW_Hx SnW_Hy #chrHead_L
		setFldW SnW_Hx SnW_Hy #chrHead_L
		setScrAt SnW_Tx SnW_Ty #chrTail_L
		setFldW SnW_Tx SnW_Ty #chrTail_L
	#end
	 
   rts
.endp

drawSnakeBeginB .proc
; __x, __y - head location
; __a - snake's length
	ldx __x
	ldy __y 
	stx SnB_Hx
	sty SnB_Hy
	sty SnB_Ty
	
	dec __a
	
	#if .byte SnB_Dir = #cRight
	
		txa
		sec
		sbc __a
		sta SnB_Tx
		sta __a
		inc __a
		#while .byte __a < SnB_Hx
			setScrAt __a SnB_Hy #chrBodyB_H
			setFldB __a SnB_Hy #chrBodyB_H
			inc __a
		#end
		setScrAt SnB_Hx SnB_Hy #chrHeadB_R
		setFldB SnB_Hx SnB_Hy #chrHeadB_R
		setScrAt SnB_Tx SnB_Ty #chrTailB_R
		setFldB SnB_Tx SnB_Ty #chrTailB_R
		
	#else
		txa
		clc
		adc __a
		sta SnB_Tx
		sta __a
		dec __a
		#while .byte __a > SnB_Hx
			setScrAt __a SnB_Hy #chrBodyB_H
			setFldB __a SnB_Hy #chrBodyB_H
			dec __a
		#end
		setScrAt SnB_Hx SnB_Hy #chrHeadB_L
		setFldB SnB_Hx SnB_Hy #chrHeadB_L
		setScrAt SnB_Tx SnB_Ty #chrTailB_L
		setFldB SnB_Tx SnB_Ty #chrTailB_L
	#end
	 
   rts
.endp

calculateNextHeadCoordW .proc

	mva SnW_Hx __x
	mva SnW_Hy __y
	
	// TODO: check teleport

	#if .byte SnW_Dir = #cRight
		#if .byte SnW_Hx = #39 ; Max. x on screen
			mva #0 __x ; Min. x on screen
		#else
			mva SnW_Hx __x
			inc __x
		#end
		rts
	#end
	#if .byte SnW_Dir = #cUp
		#if .byte SnW_Hy = #1 ; Min. y on screen
			mva #23 __y ; Max. y on screen
		#else
			mva SnW_Hy __y
			dec __y
		#end
		rts
	#end
	#if .byte SnW_Dir = #cLeft
		#if .byte SnW_Hx = #0 ; Min. x on screen
			mva #39 __x ; Max. x on screen
		#else
			mva SnW_Hx __x
			dec __x
		#end
		rts
	#end
	#if .byte SnW_Dir = #cDown
		#if .byte SnW_Hy = #23 ; Max. y on screen
			mva #1 __y ; Min. y on screen
		#else
			mva SnW_Hy __y
			inc __y
		#end
		rts
	#end
.endp

calculateNextHeadCoordB .proc

	mva SnB_Hx __x
	mva SnB_Hy __y

	// TODO: check teleport

	#if .byte SnB_Dir = #cRight
		#if .byte SnB_Hx = #39 ; Max. x on screen
			mva #0 __x ; Min. x on screen
		#else
			mva SnB_Hx __x
			inc __x
		#end
		rts
	#end
	#if .byte SnB_Dir = #cUp
		#if .byte SnB_Hy = #1 ; Min. y on screen
			mva #23 __y ; Max. y on screen
		#else
			mva SnB_Hy __y
			dec __y
		#end
		rts
	#end
	#if .byte SnB_Dir = #cLeft
		#if .byte SnB_Hx = #0 ; Min. x on screen
			mva #39 __x ; Max. x on screen
		#else
			mva SnB_Hx __x
			dec __x
		#end
		rts
	#end
	#if .byte SnB_Dir = #cDown
		#if .byte SnB_Hy = #23 ; Max. y on screen
			mva #1 __y ; Min. y on screen
		#else
			mva SnB_Hy __y
			inc __y
		#end
		rts
	#end
.endp


calculateNextTailCoordW .proc
	#if .byte __a = #chrTail_R
		ldx SnW_Tx
		cpx #39
		sne
		ldx #-1
		inx
		stx __x
		mva SnW_Ty __y
	#else
	#if .byte __a = #chrTail_U
		ldx SnW_Ty
		cpx #1
		sne
		ldx #24
		dex
		stx __y
		mva SnW_Tx __x
	#else
	#if .byte __a = #chrTail_L
		ldx SnW_Tx
		cpx #0
		sne
		ldx #40
		dex
		stx __x
		mva SnW_Ty __y
	#else
	#if .byte __a = #chrTail_D
		ldx SnW_Ty
		cpx #23
		sne
		ldx #0
		inx
		stx __y
		mva SnW_Tx __x
	#end 
	#end 
	#end 
	#end 
	rts
.endp


calculateNextTailCoordB .proc
	#if .byte __a = #chrTailB_R
		ldx SnB_Tx
		cpx #39
		sne
		ldx #-1
		inx
		stx __x
		mva SnB_Ty __y
	#else
	#if .byte __a = #chrTailB_U
		ldx SnB_Ty
		cpx #1
		sne
		ldx #24
		dex
		stx __y
		mva SnB_Tx __x
	#else
	#if .byte __a = #chrTailB_L
		ldx SnB_Tx
		cpx #0
		sne
		ldx #40
		dex
		stx __x
		mva SnB_Ty __y
	#else
	#if .byte __a = #chrTailB_D
		ldx SnB_Ty
		cpx #23
		sne
		ldx #0
		inx
		stx __y
		mva SnB_Tx __x
	#end 
	#end 
	#end 
	#end 
	rts
.endp


moveTailW .proc

	getFldW SnW_Tx SnW_Ty
	sta __a	; current __tail__ character
	jsr calculateNextTailCoordW
	getFldW __x __y
	sta __b ; snake's character next to the 'tail'

	; erase the tail
	setFldW SnW_Tx SnW_Ty #0
	getScrAt SnW_Tx SnW_Ty
	cmp __a
	jne l1
	getFldB SnW_Tx SnW_Ty
	sta __c
	setScrAt SnW_Tx SnW_Ty __c
l1

	#if .byte __b = #chrBody_UL
		#if .byte __a = #chrTail_R
			mva #chrTail_U __c
		#else
			mva #chrTail_L __c
		#end 
	#else
	#if .byte __b = #chrBody_DL
		#if .byte __a = #chrTail_R
			mva #chrTail_D __c
		#else
			mva #chrTail_L __c
		#end 
	#else
	#if .byte __b = #chrBody_DR
		#if .byte __a = #chrTail_U
			mva #chrTail_R __c
		#else
			mva #chrTail_D __c
		#end 
	#else
	#if .byte __b = #chrBody_UR
		#if .byte __a = #chrTail_L
			mva #chrTail_U __c
		#else
			mva #chrTail_R __c
		#end 
	#else
		mva __a __c
	#end 
	#end 
	#end 
	#end 
	
	; put the tail
	setFldW __x __y __c 
	getScrAt __x __y
	cmp __b
	jne l2
	setScrAt __x __y __c
l2

	mva __x SnW_Tx
	mva __y SnW_Ty
	rts
.endp


moveTailB .proc

	getFldB SnB_Tx SnB_Ty
	sta __a	; current __tail__ character
	jsr calculateNextTailCoordB
	getFldB __x __y
	sta __b ; snake's character next to the 'tail'

	; erase the tail
	setFldB SnB_Tx SnB_Ty #0
	getScrAt SnB_Tx SnB_Ty
	cmp __a
	jne l1
	getFldW SnB_Tx SnB_Ty
	sta __c
	setScrAt SnB_Tx SnB_Ty __c
l1

	#if .byte __b = #chrBodyB_UL
		#if .byte __a = #chrTailB_R
			mva #chrTailB_U __c
		#else
			mva #chrTailB_L __c
		#end 
	#else
	#if .byte __b = #chrBodyB_DL
		#if .byte __a = #chrTailB_R
			mva #chrTailB_D __c
		#else
			mva #chrTailB_L __c
		#end 
	#else
	#if .byte __b = #chrBodyB_DR
		#if .byte __a = #chrTailB_U
			mva #chrTailB_R __c
		#else
			mva #chrTailB_D __c
		#end 
	#else
	#if .byte __b = #chrBodyB_UR
		#if .byte __a = #chrTailB_L
			mva #chrTailB_U __c
		#else
			mva #chrTailB_R __c
		#end 
	#else
		mva __a __c
	#end 
	#end 
	#end 
	#end 
	
	; put the tail
	setFldB __x __y __c 
	getScrAt __x __y
	cmp __b
	jne l2
	setScrAt __x __y __c
l2

	mva __x SnB_Tx
	mva __y SnB_Ty
	rts
.endp


;-------------------------------------------------------------------------
.array snakeCharsW .byte
	chrHead_R
	chrHead_U
	chrHead_D
	chrHead_L
	chrBody_UL
	chrBody_UR
	chrBody_DL
	chrBody_DR
	chrBody_V
	chrBody_H
	chrTail_U
	chrTail_L
	chrTail_D
	chrTail_R
	10
	61
	62
.enda

.array snakeCharsB .byte
	chrHeadB_R
	chrHeadB_U
	chrHeadB_D
	chrHeadB_L
	chrBodyB_UL
	chrBodyB_UR
	chrBodyB_DL
	chrBodyB_DR
	chrBodyB_V
	chrBodyB_H
	chrTailB_U
	chrTailB_L
	chrTailB_D
	chrTailB_R
	10
	61
	62
.enda

checkIfSnakeCharW .proc
	ldx #.len(snakeCharsW)
l1:
	dex
	bmi l2
	cmp snakeCharsW,X
	bne l1
	sec
	rts
l2:
	clc
	rts
.endp

checkIfSnakeCharB .proc
	ldx #.len(snakeCharsB)
l1:
	dex
	bmi l2
	cmp snakeCharsB,X
	bne l1
	sec
	rts
l2:
	clc
	rts
.endp


changeSnakeChars .proc
	ldx #.len(snakeChars1)
l1:
	dex
	bmi l2
	cmp snakeChars1,X
	bne l1
	lda snakeChars2,X
	sec
	rts
l2:
	clc
	rts
.endp

.array snakeChars1 .byte
	chrHead_R
	chrHead_U
	chrHead_D
	chrHead_L
	chrBody_UL
	chrBody_UR
	chrBody_DL
	chrBody_DR
	chrBody_V
	chrBody_H
	chrTail_U
	chrTail_L
	chrTail_D
	chrTail_R

	chrHeadB_R
	chrHeadB_U
	chrHeadB_D
	chrHeadB_L
	chrBodyB_UL
	chrBodyB_UR
	chrBodyB_DL
	chrBodyB_DR
	chrBodyB_V
	chrBodyB_H
	chrTailB_U
	chrTailB_L
	chrTailB_D
	chrTailB_R

	0
.enda

.array snakeChars2 .byte
	chrHeadB_R
	chrHeadB_U
	chrHeadB_D
	chrHeadB_L
	chrBodyB_UL
	chrBodyB_UR
	chrBodyB_DL
	chrBodyB_DR
	chrBodyB_V
	chrBodyB_H
	chrTailB_U
	chrTailB_L
	chrTailB_D
	chrTailB_R

	chrHead_R
	chrHead_U
	chrHead_D
	chrHead_L
	chrBody_UL
	chrBody_UR
	chrBody_DL
	chrBody_DR
	chrBody_V
	chrBody_H
	chrTail_U
	chrTail_L
	chrTail_D
	chrTail_R

	0
.enda

clearSnakeBlack .proc
	cmp #chrHeadB_R
	jeq l1
	cmp #chrHeadB_U
	jeq l1
	cmp #chrHeadB_D
	jeq l1
	cmp #chrHeadB_L
	jeq l1
	cmp #62
	jeq l1
	clc
	rts
l1
	lda #0
	sec
	rts
.endp

clearSnakeWhite .proc
	cmp #chrHead_R
	jeq l1
	cmp #chrHead_U
	jeq l1
	cmp #chrHead_D
	jeq l1
	cmp #chrHead_L
	jeq l1
	cmp #62
	jeq l1
	clc
	rts
l1
	lda #0
	sec
	rts
.endp

showSnakeBlackDead .proc
	ldx #.len(snakeChars3)
l1:
	dex
	bmi l2
	cmp snakeChars3,X
	bne l1
	lda #62
	sec
	rts
l2:
	clc
	rts
.endp

showSnakeWhiteDead .proc
	ldx #.len(snakeChars4)
l1:
	dex
	bmi l2
	cmp snakeChars4,X
	bne l1
	lda #62
	sec
	rts
l2:
	clc
	rts
.endp

.array snakeChars3 .byte
	chrBodyB_UL
	chrBodyB_UR
	chrBodyB_DL
	chrBodyB_DR
	chrBodyB_V
	chrBodyB_H
	chrTailB_U
	chrTailB_L
	chrTailB_D
	chrTailB_R
.enda

.array snakeChars4 .byte
	chrBody_UL
	chrBody_UR
	chrBody_DL
	chrBody_DR
	chrBody_V
	chrBody_H
	chrTail_U
	chrTail_L
	chrTail_D
	chrTail_R
.enda

;-------------------------------------------------------------------------
MoveHeadW .proc
	
	mvza __z

	getFldW SnW_Hx SnW_Hy  ; current 'head' character
	sta __a
   
	jsr calculateNextHeadCoordW
	getScrAt __x __y
	sta __b ; character in front of the 'head'

	#if .byte SnW_Dir = #cRight
		ldx #chrHead_R
	#else
	#if .byte SnW_Dir = #cUp
		ldx #chrHead_U
	#else
	#if .byte SnW_Dir = #cLeft
		ldx #chrHead_L
	#else
	#if .byte SnW_Dir = #cDown
		ldx #chrHead_D
	#end 
	#end 
	#end 
	#end
	stx __c
	
	setFldW SnW_Hx SnW_Hy __c	; turn the head (no move yet)
	getScrAt SnW_Hx SnW_Hy
	cmp __a
	jne l1
	setScrAt SnW_Hx SnW_Hy __c
l1:

	; check character in front of the head
	#if .byte __b = #chrFruit

		ldy fruit_Y
		lda #0
		sta FHighlight,Y
		mvza fruit_Y
		setScrAt __x __y #0	
		mva #1 __z
	
	#else
	
	#if .byte __b = #chrFruitEx

		ldy fruitExtra_Y
		lda #0
		sta FHighlightEx,Y
		mvza fruitExtra_Y
		setScrAt __x __y #0
		mva #2 __z
		
	#else
	
	#if .byte __b <> #0

		jsr CheckMovePossibleW
		jcs l2
	
		mva #3 __z ; game over
		rts
l2:		
	#end
	#end
	#end
	
	
	; move the head
  	#if .byte __a = #chrHead_R
	  	#if .byte SnW_Dir = #cUp
	  		mva #chrBody_UL __b
	  	#else
	  	#if .byte SnW_Dir = #cDown
	  		mva #chrBody_DL __b
	  	#else
	  		mva #chrBody_H __b
	  	#end
	  	#end
  	#else
  	#if .byte __a = #chrHead_U
	  	#if .byte SnW_Dir = #cLeft
	  		mva #chrBody_DL __b
	  	#else
	  	#if .byte SnW_Dir = #cRight
	  		mva #chrBody_DR __b
	  	#else
	  		mva #chrBody_V __b
	  	#end
	  	#end
  	#else
  	#if .byte __a = #chrHead_L
	  	#if .byte SnW_Dir = #cUp
	  		mva #chrBody_UR __b
	  	#else
	  	#if .byte SnW_Dir = #cDown
	  		mva #chrBody_DR __b
	  	#else
	  		mva #chrBody_H __b
	  	#end
	  	#end
  	#else
  	#if .byte __a = #chrHead_D
	  	#if .byte SnW_Dir = #cLeft
	  		mva #chrBody_UL __b
	  	#else
	  	#if .byte SnW_Dir = #cRight
	  		mva #chrBody_UR __b
	  	#else
	  		mva #chrBody_V __b
	  	#end
	  	#end
  	#end
  	#end
  	#end
  	#end
  	
  	
  	setFldW SnW_Hx SnW_Hy __b
  	setFldW __x __y __c

	getScrAt SnW_Hx SnW_Hy
	cmp __c
	jne l3
	setScrAt SnW_Hx SnW_Hy __b
  	setScrAt __x __y __c
  	jmp l4
l3:
  	getScrAt __x __y 
	cmp #0
	jne l4
  	setScrAt __x __y __c
l4:

  	mva __x SnW_Hx
  	mva __y SnW_Hy
  	
	rts
.endp

;-------------------------------------------------------------------------
MoveHeadB .proc
	
	mvza __z

	getFldB SnB_Hx SnB_Hy  ; current 'head' character
	sta __a
   
	jsr calculateNextHeadCoordB
	getScrAt __x __y
	sta __b ; character in front of the 'head'

	#if .byte SnB_Dir = #cRight
		ldx #chrHeadB_R
	#else
	#if .byte SnB_Dir = #cUp
		ldx #chrHeadB_U
	#else
	#if .byte SnB_Dir = #cLeft
		ldx #chrHeadB_L
	#else
	#if .byte SnB_Dir = #cDown
		ldx #chrHeadB_D
	#end 
	#end 
	#end 
	#end
	stx __c
	
	setFldB SnB_Hx SnB_Hy __c	; turn the head (no move yet)
	getScrAt SnB_Hx SnB_Hy
	cmp __a
	jne l1
	setScrAt SnB_Hx SnB_Hy __c
l1:

	; check character in front of the head
	#if .byte __b = #chrFruit

		ldy fruit_Y
		lda #0
		sta FHighlight,Y
		mvza fruit_Y
		setScrAt __x __y #0	
		mva #1 __z
	
	#else
	
	#if .byte __b = #chrFruitEx

		ldy fruitExtra_Y
		lda #0
		sta FHighlightEx,Y
		mvza fruitExtra_Y
		setScrAt __x __y #0
		mva #2 __z
	
	#else
	
	#if .byte __b <> #0

		jsr CheckMovePossibleB
		jcs l2
	
		mva #3 __z ; game over
		rts
l2:		
	#end
	#end
	#end
	
	
	; move the head
  	#if .byte __a = #chrHeadB_R
	  	#if .byte SnB_Dir = #cUp
	  		mva #chrBodyB_UL __b
	  	#else
	  	#if .byte SnB_Dir = #cDown
	  		mva #chrBodyB_DL __b
	  	#else
	  		mva #chrBodyB_H __b
	  	#end
	  	#end
  	#else
  	#if .byte __a = #chrHeadB_U
	  	#if .byte SnB_Dir = #cLeft
	  		mva #chrBodyB_DL __b
	  	#else
	  	#if .byte SnB_Dir = #cRight
	  		mva #chrBodyB_DR __b
	  	#else
	  		mva #chrBodyB_V __b
	  	#end
	  	#end
  	#else
  	#if .byte __a = #chrHeadB_L
	  	#if .byte SnB_Dir = #cUp
	  		mva #chrBodyB_UR __b
	  	#else
	  	#if .byte SnB_Dir = #cDown
	  		mva #chrBodyB_DR __b
	  	#else
	  		mva #chrBodyB_H __b
	  	#end
	  	#end
  	#else
  	#if .byte __a = #chrHeadB_D
	  	#if .byte SnB_Dir = #cLeft
	  		mva #chrBodyB_UL __b
	  	#else
	  	#if .byte SnB_Dir = #cRight
	  		mva #chrBodyB_UR __b
	  	#else
	  		mva #chrBodyB_V __b
	  	#end
	  	#end
  	#end
  	#end
  	#end
  	#end
  	
  	
  	setFldB SnB_Hx SnB_Hy __b
  	setFldB __x __y __c

	getScrAt SnB_Hx SnB_Hy
	cmp __c
	jne l3
	setScrAt SnB_Hx SnB_Hy __b
  	setScrAt __x __y __c
  	jmp l4
l3:
  	getScrAt __x __y 
	cmp #0
	jne l4
  	setScrAt __x __y __c
l4:

  	mva __x SnB_Hx
  	mva __y SnB_Hy
  	
	rts
.endp


;-------------------------------------------------------------------------
DrawSnakeAtRandomPos .proc
; C flag - 0: white, 1: black
	php

l2	
    lda RANDOM
    and #15
    sta __y

    #if .byte __y > #(.len(Lines) -1)
        SBB __y #.len(Lines)
    #end

    ldy __y
    lda Lines,Y
    cmp fruit_Y
     jeq l2 
    cmp fruitExtra_Y
     jeq l2 
    sta __y

    lda RANDOM
    and #31
    sta __x

    #if .byte __x > #19
        SBB __x #20
    #end
    
    #if .byte __x < __a
        ADB __x __a
    #end
   
   	plp
   	jcs l1

    #if .byte SnW_Dir = #cLeft
        lda #39
        sec
        sbc __x
        sta __x
    #end
    jmp drawSnakeBeginW

l1
    #if .byte SnB_Dir = #cLeft
        lda #39
        sec
        sbc __x
        sta __x
    #end
    jmp drawSnakeBeginB

	
   .array Lines .byte
   2, 3, 5, 6, 17, 18, 19, 20, 21, 22
   .enda
   
.endp


;-------------------------------------------------------------------------
DrawSnakeRandomW .proc
    mva #cLeft SnW_Dir
    lda RANDOM
    and #1
    beq _l1
    mva #cRight SnW_Dir
_l1
    ; a = RND 10..19
    lda RANDOM
    and #15
    sta __a
    #if .byte __a > #9
        SBB __a #10
    #end
    ADB __a #10

	clc
    jmp DrawSnakeAtRandomPos
.endp

;-------------------------------------------------------------------------
DrawSnakeRandomB .proc
    mva #cLeft SnB_Dir
    lda RANDOM
    and #1
    beq _l1
    mva #cRight SnB_Dir
_l1

    ; a = RND 10..19
    lda RANDOM
    and #15
    sta __a
    #if .byte __a > #9
        SBB __a #10
    #end
    ADB __a #10

	sec
    jmp DrawSnakeAtRandomPos
.endp

;-------------------------------------------------------------------------
CheckMovePossibleW .proc
	getScrAt __x __y
	jeq l1
	checkIfSnakeCharB
	jcc l2
	getFldW __x __y
	jne l2
l1:	
	; yes
	sec
	rts
l2:
	; no
	clc
	rts
.endp

CheckMovePossibleB .proc
	getScrAt __x __y
	jeq l1
	checkIfSnakeCharW
	jcc l2
	getFldB __x __y
	jne l2
l1:	
	; yes
	sec
	rts
l2:
	; no
	clc
	rts
.endp

;-------------------------------------------------------------------------
ChangeDirectionW .proc

	; check if there's any move yet
	mva SnW_Hx __x
	mva SnW_Hy __y

	#if .byte __x = #39 \ mva #0 __x \ #else \ inc __x \ #end 
	jsr CheckMovePossibleW
	jcs l1
	
	mva SnW_Hx __x
	
	#if .byte __x = #0 \ mva #39 __x \ #else \ dec __x \ #end 
	jsr CheckMovePossibleW
	jcs l1
	
	mva SnW_Hx __x
	
	#if .byte __y = #23 \ mva #1 __y \ #else \ inc __y \ #end 
	jsr CheckMovePossibleW
	jcs l1

	mva SnW_Hy __y
	#if .byte __y = #1 \ mva #23 __y \ #else \ dec __y \ #end 
	jsr CheckMovePossibleW
	jcs l1
	
	; move is not possible
	mva #8 SnW_State
	clc
	rts

l1
	; turn
	#if .byte RANDOM >= #128
l2:
		;turn left
		#if .byte SnW_Dir = #cRight
			mva #cUp SnW_Dir
		#else
		#if .byte SnW_Dir = #cUp
			mva #cLeft SnW_Dir
		#else
		#if .byte SnW_Dir = #cLeft
			mva #cDown SnW_Dir
		#else
			mva #cRight SnW_Dir
		#end
		#end
		#end
		
		calculateNextHeadCoordW
		jsr CheckMovePossibleW
		jcs l4
		jmp l2
		
	#else
l3:
		;turn right
		#if .byte SnW_Dir = #cRight
			mva #cDown SnW_Dir
		#else
		#if .byte SnW_Dir = #cUp
			mva #cRight SnW_Dir
		#else
		#if .byte SnW_Dir = #cLeft
			mva #cUp SnW_Dir
		#else
			mva #cLeft SnW_Dir
		#end
		#end
		#end
		
		calculateNextHeadCoordW
		jsr CheckMovePossibleW
		jcs l4
		jmp l3
		
	#end

l4:
	sec
	rts

.endp

;-------------------------------------------------------------------------
ChangeDirectionB .proc

	; check if there's any move yet
	mva SnB_Hx __x
	mva SnB_Hy __y

	#if .byte __x = #39 \ mva #0 __x \ #else \ inc __x \ #end 
	jsr CheckMovePossibleB
	jcs l1
	
	mva SnB_Hx __x
	
	#if .byte __x = #0 \ mva #39 __x \ #else \ dec __x \ #end 
	jsr CheckMovePossibleB
	jcs l1
	
	mva SnB_Hx __x
	
	#if .byte __y = #23 \ mva #1 __y \ #else \ inc __y \ #end 
	jsr CheckMovePossibleB
	jcs l1

	mva SnB_Hy __y
	#if .byte __y = #1 \ mva #23 __y \ #else \ dec __y \ #end 
	jsr CheckMovePossibleB
	jcs l1
	
	; change is not possible
	mva #8 SnB_State
	clc
	rts

l1
	; turn
	#if .byte RANDOM >= #128
l2:
		;turn left
		#if .byte SnB_Dir = #cRight
			mva #cUp SnB_Dir
		#else
		#if .byte SnB_Dir = #cUp
			mva #cLeft SnB_Dir
		#else
		#if .byte SnB_Dir = #cLeft
			mva #cDown SnB_Dir
		#else
			mva #cRight SnB_Dir
		#end
		#end
		#end
		
		calculateNextHeadCoordB
		jsr CheckMovePossibleB
		jcs l4
		jmp l2
		
	#else
l3:
		;turn right
		#if .byte SnB_Dir = #cRight
			mva #cDown SnB_Dir
		#else
		#if .byte SnB_Dir = #cUp
			mva #cRight SnB_Dir
		#else
		#if .byte SnB_Dir = #cLeft
			mva #cUp SnB_Dir
		#else
			mva #cLeft SnB_Dir
		#end
		#end
		#end
		
		calculateNextHeadCoordB
		jsr CheckMovePossibleB
		jcs l4
		jmp l3
		
	#end

l4:
	sec
	rts

.endp


;-------------------------------------------------------------------------
AnimateSnakeW .proc

	#if .byte SnW_State <> #0
		jmp hideSnake
	#end

	jsr moveTailW
	jsr calculateNextHeadCoordW
	jsr CheckMovePossibleW
	jcs l1

	jsr ChangeDirectionW
	jcs l2
	rts

l1:
	lda RANDOM
	and #15
	cmp #3
	jcs l2
	jsr ChangeDirectionW

l2:	
	jsr moveHeadW
	rts

	
hideSnake:

	#if .byte SnW_Hx <> SnW_Tx .or .byte SnW_Hy <> SnW_Ty
		jsr moveTailW
		#if .byte SnW_Hx <> SnW_Tx .or .byte SnW_Hy <> SnW_Ty
			rts
		#end
	#end

	getScrAt SnW_Hx SnW_Hy
	checkIfSnakeCharW
	jcc l5
	
	#if .byte SnW_State = #8
		setScrAt SnW_Hx SnW_Hy #10
	#else
	#if .byte SnW_State = #7
		setScrAt SnW_Hx SnW_Hy #61
	#else
	#if .byte SnW_State = #6
		setScrAt SnW_Hx SnW_Hy #62
	#else
	#if .byte SnW_State = #5
		setScrAt SnW_Hx SnW_Hy #0
	#else
	#end
	#end
	#end
	#end
	
l5:
	#if .byte SnW_State = #8
		setFldW SnW_Hx SnW_Hy #10
	#else
	#if .byte SnW_State = #7
		setFldW SnW_Hx SnW_Hy #61
	#else
	#if .byte SnW_State = #6
		setFldW SnW_Hx SnW_Hy #62
	#else
	#if .byte SnW_State = #5
		setFldW SnW_Hx SnW_Hy #0
	#else
	#end
	#end
	#end
	#end

	dec SnW_State
	jne l6

	jsr DrawSnakeRandomW
l6:
	rts

.endp

;-------------------------------------------------------------------------
AnimateSnakeB .proc

	#if .byte SnB_State <> #0
		jmp hideSnake
	#end

	jsr moveTailB
	jsr calculateNextHeadCoordB
	jsr CheckMovePossibleB
	jcs l1

	jsr ChangeDirectionB
	jcs l2
	rts

l1:
	lda RANDOM
	and #15
	cmp #3
	jcs l2
	jsr ChangeDirectionB

l2:	
	jsr moveHeadB
	rts

	
hideSnake:
	#if .byte SnB_Hx <> SnB_Tx .or .byte SnB_Hy <> SnB_Ty
		jsr moveTailB
		#if .byte SnB_Hx <> SnB_Tx .or .byte SnB_Hy <> SnB_Ty
			rts
		#end
	#end

	getScrAt SnB_Hx SnB_Hy
	checkIfSnakeCharB
	jcc l5
	
	#if .byte SnB_State = #8
		setScrAt SnB_Hx SnB_Hy #10
	#else
	#if .byte SnB_State = #7
		setScrAt SnB_Hx SnB_Hy #61
	#else
	#if .byte SnB_State = #6
		setScrAt SnB_Hx SnB_Hy #62
	#else
	#if .byte SnB_State = #5
		setScrAt SnB_Hx SnB_Hy #0
	#else
	#end
	#end
	#end
	#end
	
l5:
	#if .byte SnB_State = #8
		setFldB SnB_Hx SnB_Hy #10
	#else
	#if .byte SnB_State = #7
		setFldB SnB_Hx SnB_Hy #61
	#else
	#if .byte SnB_State = #6
		setFldB SnB_Hx SnB_Hy #62
	#else
	#if .byte SnB_State = #5
		setFldB SnB_Hx SnB_Hy #0
	#else
	#end
	#end
	#end
	#end

	dec SnB_State
	jne l6

	jsr DrawSnakeRandomB
l6:
	rts

.endp


;-------------------------------------------------------------------------
ShowGameMode .proc

   	clearFldW
   	clearFldB
	mvza SnW_State
	mvza SnB_State
	
	#if .byte _selectedMode = #0 

		putArrOnScr 0 1 40 7 arrMode12
		mva #cLeft SnW_Dir
		mva #15 __x
		mva #6 __y
		mva #10 __a
		jsr drawSnakeBeginW

	#else
	#if .byte _selectedMode = #1 

		putArrOnScr 0 1 40 7 arrMode12
		mva #cLeft SnB_Dir
		mva #15 __x
		mva #6 __y
		mva #10 __a
		jsr drawSnakeBeginB

	#else
	#if .byte _selectedMode = #2 

		putArrOnScr 0 1 40 7 arrMode34
		mva #cLeft SnW_Dir
		mva #5 __x
		mva #6 __y
		mva #10 __a
		jsr drawSnakeBeginW
		mva #cRight SnB_Dir
		mva #34 __x
		mva #2 __y
		mva #10 __a
		jsr drawSnakeBeginB
		
	#else
	#if .byte _selectedMode = #3
	
		putArrOnScr 0 1 40 7 arrMode34
		mva #cLeft SnB_Dir
		mva #5 __x
		mva #6 __y
		mva #10 __a
		jsr drawSnakeBeginB
		mva #cRight SnW_Dir
		mva #34 __x
		mva #2 __y
		mva #10 __a
		jsr drawSnakeBeginW
	 
	#end
	#end
	#end
	#end
	
	rts
.endp


ChangeSnakes .proc

	exchangeMemory arrSnakeFldW \
				   arrSnakeFldW_End \
				   arrSnakeFldB \
				   changeSnakeChars
				   
	changeMemory (_scr + 40) \
				 (_scr + 40*8) \
				 changeSnakeChars
	lda SnW_Hx
	ldx SnB_Hx
	sta SnB_Hx
	stx SnW_Hx
	lda SnW_Hy
	ldx SnB_Hy
	sta SnB_Hy
	stx SnW_Hy
	lda SnW_Tx
	ldx SnB_Tx
	sta SnB_Tx
	stx SnW_Tx
	lda SnW_Ty
	ldx SnB_Ty
	sta SnB_Ty
	stx SnW_Ty
	lda SnW_Dir
	ldx SnB_Dir
	sta SnB_Dir
	stx SnW_Dir
					  
	rts
.endp


 .array arrMode12 .byte
    :40 $4A
    :10 $4A \ :21 $00 \ :9 $4A
    :10 $4A \ $00 \ :19 $4A \ $00 \ :9 $4A
    :10 $4A \ $00, $4A, "GET", $4A, "READY", $4A, "PLAYER!", $4A, $00 \ :9 $4A
    :10 $4A \ $00 \ :19 $4A \ $00 \ :9 $4A
    :10 $4A \ :21 $00 \ :9 $4A
    :40 $4A
    .enda

 .array arrMode34 .byte
    :40 $4A
    $4A \ :18 $00 \ :2 $4A \ :18 $00 \ $4A
    $4A, $00 \ :16 $4A \ $00 \ :2 $4A \ $00 \ :16 $4A \ $00, $4A
    $4A, $00, $4A, " PLAYER - 1 - ", $4A, $00 \ :2 $4A \ $00, $4A, " PLAYER - 2 - ", $4A, $00, $4A
    $4A, $00 \ :16 $4A \ $00 \ :2 $4A \ $00 \ :16 $4A \ $00, $4A
    $4A \ :18 $00 \ :2 $4A \ :18 $00 \ $4A
    :40 $4A
    .enda

arrMode12_lo:  :7 dta l(arrMode12 + #*40)
arrMode12_hi:  :7 dta h(arrMode12 + #*40)
arrMode34_lo:  :7 dta l(arrMode34 + #*40)
arrMode34_hi:  :7 dta h(arrMode34 + #*40)

;-------------------------------------------------------------------------
TitlePage .proc

	; Credits page

   	ClearScr
   	
   	getColor #3 _bgrndColorPtr	
	sta PM_COLS0
	sta PM_COLS1
	sta PM_COLS2
	
	mva #80 PM_XPOS
	mva #112 PM_XPOS+1
	mva #144 PM_XPOS+2
	mva #3 PM_WIDTH
	mva #3 PM_WIDTH+1
	mva #3 PM_WIDTH+2

	mwa #DList SDLSTL

	mva #0 NMIEN
	mwa #DLI_Proc2 VDSLST
	mva #192 NMIEN

	fillMemory FHighlight (FHighlight + .len(FHighlight)) 0
	fillMemory FHighlightEx (FHighlightEx + .len(FHighlightEx)) 0
	mvza fruit_Y
	mvza fruitExtra_Y
	
	mvza tmrBase
   
	jsr ClearMsg
	jsr WriteTitle
	
	mwza tmrDisplMsgs
	mvza _msgNum
	mvza _msgNum2

   	clearFldW
   	clearFldB

	lda RANDOM
	and #1
	jne l1
	jsr drawArea1
	jmp l2
l1 
	jsr drawArea2
l2

	jsr WriteCredits

	jsr ChangeMsg

	jsr DrawSnakeRandomW
	jsr DrawSnakeRandomB
	
	mvza CH
	mvza SnW_State
	mvza SnB_State

loop
	#if .byte tmrBase >= #9 
		jsr animateSnakeW
		jsr animateSnakeB
		mvza tmrBase
	#end
	#if .word tmrDisplMsgs >= #250 
		jsr ChangeMsg
	#end
	
	jsr CheckKeys
	
	jsr CheckTrigger
	jcc loop
	
   	rts
.endp


SelectionPage .proc
   
   ; Mode selection 

	jsr ClearMsg
	jsr clearScr

   	clearFldW
   	clearFldB
	
	mwa #DList2 SDLSTL

	mva #10 _msgNum
	mva #255 _msgNum2
	jsr changeMsg
   
	mva #0 NMIEN
	mwa #DLI_Proc2A VDSLST
	mva #192 NMIEN

	mvza PM_PATRN+2
   	getColor #3 _bgrndColorPtr
   	ora #$03	
	sta PM_COLS0
	sta PM_COLS1

	ldx _selectedArea
	mva arrPosHLL,x PM0_XPOS
	ldx _selectedArea
	mva arrPosHLR,x PM1_XPOS
	
	jsr writeTitle
   
	jsr ShowGameMode

	putArrOnScr 2 12 36 7 arrFields 	

	mvza CH
	mva #$F _tmpState

loop	
	jsr CheckKeys
	#if .byte CH = #28 ;ESC
        clc
        rts
    #end

	lda STICK0
	and #$F
	cmp #$F
	jne l3
	lda STICK1
	and #$F
	cmp #$F
	jne l3
	
	#if .byte _tmpState = #cUp 
		inc _selectedMode
		#if .byte _selectedMode = #4
			mvza _selectedMode
		#end
		#if .byte _selectedMode = #0 .or .byte _selectedMode = #2 
			jsr ShowGameMode
		#else
			jsr ChangeSnakes
		#end
	#else
	
	#if .byte _tmpState = #cDown 
		dec _selectedMode
		#if .byte _selectedMode = #-1
			mva #3 _selectedMode
		#end
		#if .byte _selectedMode = #1 .or .byte _selectedMode = #3 
			jsr ShowGameMode
		#else
			jsr ChangeSnakes
		#end
	#else
	
	#if .byte _tmpState = #cLeft .and .byte _selectedArea > #0
		dec _selectedArea
		ldx _selectedArea
		mva arrPosHLL,x __a
		mva __a PM0_XPOS
		ldx _selectedArea
		mva arrPosHLR,x __b
		mva __b PM1_XPOS
	#else
	
	#if .byte _tmpState = #cRight .and .byte _selectedArea < #3
		inc _selectedArea
		ldx _selectedArea
		mva arrPosHLL,x __a
		mva __a PM0_XPOS
		ldx _selectedArea
		mva arrPosHLR,x __b
		mva __b PM1_XPOS
	#end
	#end
	#end
	#end
				
	lda #$F
l3:
	sta _tmpState

	#if .byte tmrBase >= #9
		#if .byte _selectedMode <> #1 
			jsr animateSnakeW
		#end
		#if .byte _selectedMode <> #0 
			jsr animateSnakeB
		#end
		mvza tmrBase
	#end
	#if .word tmrDisplMsgs >= #250 
		jsr changeMsg
	#end

	jsr CheckTrigger
	jcc loop		

	sec   
	rts
.endp


	ICL 'GameProc.asm'
    