; ==============================================================================
; Player

Global archer.Player

Function LoadPlayer()
	archer = New Player
	
	p.Player = archer
	p\state = AT_SPACE

	p\model = LoadAnimMesh("archerBow.b3d")
	ExtractAnimSeq(p\model,1,30)	; id 1 = breathing
	ExtractAnimSeq(p\model,31,40)	; id 2 = start walk
	ExtractAnimSeq(p\model,41,60)	; id 3 = walk
	ExtractAnimSeq(p\model,61,63)	; id 4 = start run
	ExtractAnimSeq(p\model,64,95)	; id 5 = run
	ExtractAnimSeq(p\model,96,100)	; id 6 = stop
	ExtractAnimSeq(p\model,101,115)	; id 7 = load bow
	ExtractAnimSeq(p\model,116,125)	; id 8 = lean back
	ExtractAnimSeq(p\model,126,130)	; id 9 = lower bow
	ExtractAnimSeq(p\model,131,140)	; id 10 = breathing with bow

	tex = LoadTexture("stars2.tga", 65)
	tex2 = LoadTexture("stars.tga", 65)
	EntityTexture p\model,tex2,1
	EntityTexture p\model,tex,0
	TextureBlend tex,3
	;TextureBlend tex2,3
	;TextureBlend tex,2	; add blending
	;EntityFX p\model,16
	;EntityType p\model,TYPE_PLAYER	; for collisions (using the pivot)
	
	p\bow   = LoadMesh("bow.x")
	p\arrow = LoadMesh("arrow.x")
	
	FitMesh p\model,-.5,0,-.5,1,1,1,True
	FitMesh p\bow,-0.5,-0.5,-0.5,1,1,1,True
	FitMesh p\arrow,-0.5,-0.5,0.0,1,1,1,True
	
	EntityParent p\bow, p\model
	EntityParent p\arrow, p\model
	EntityTexture p\bow,tex
	EntityTexture p\arrow,tex
	
	ShowAndHide(p)
	
	p\arrowflare=LoadSprite("starFlare.tga", 3, p\arrow)
	PositionEntity p\arrowflare,0,0,0
	PositionEntity p\arrowflare,0,0,1
	;HideEntity p\arrowflare
	
	;ShowAxes(p\arrow)

	;p\cam.ChaseCam = InitChaseCam(p\model, CAM_FIRST)
	microphone = CreateListener( p\model )
	
	p\timer% = MilliSecs()	; for the countdown
End Function

Function ScalePlayerToPlanet(p.Planet)
	scale# = p\radius# * plrscl#								; plrscl# defined in defs.bb
	ScaleEntity archer\model,scale#,scale#,scale#
End Function

Function ScaleBowToPlanet(p.Planet)
	scale# = 1	;p\radius# * plrscl#; the player's scale is already applied because the bow is a child
	bowscale# = scale# * bowscl#
	TFormPoint 0,0.5,0.5,archer\model,0
	;PositionEntity archer\bow, 0,0,0 : PositionEntity archer\arrow, 0,0,0
	PositionEntity archer\bow,   TFormedX(),TFormedY(),TFormedZ(),True
	PositionEntity archer\arrow, TFormedX(),TFormedY(),TFormedZ(),True
	ScaleEntity archer\bow,    bowscale#,bowscale#,bowscale#
	ScaleEntity archer\arrow,  bowscale#,bowscale#,bowscale#
End Function

Function ShowAndHide(me.Player)
	state = me\state
	
	EntityAlpha me\model,0
	HideEntity me\bow
	HideEntity me\arrow
	
	HideEntity g_corecurs
	
	If state = AT_SURFACE Then
		EntityAlpha me\model,1
	ElseIf state = AT_ARROW Then
		ShowEntity me\bow
	EndIf
End Function

; ==============================================================================

Global savedstate
Global beyondfixed = True
Global animspeed# = 1

Function UpdatePlayer(p.Player)
	loc.Planet = p\loc : If loc <> Null pivot = loc\campivot
	savedstate = p\state
	
	ShowAndHide(p)
	If savedstate <> AT_SPACE Then g_orbspd# = 3600

	Select savedstate
	  Case AT_CORE
	
			CoreFreeLook()
			
			If MouseHit(1) <> 0 Or MouseHit(2) <> 0 Then GoToSurface(loc)	; Left/Right Click

	  Case AT_SURFACE		; down is negative Y
		
			;If KeyDown(203) TurnEntity pivot,   0,    2.5,  0	; Left Arrow = Turn Left
			;If KeyDown(205) TurnEntity pivot,   0,   -2.5,  0	; Right Arrow = Turn Right
		
			HandleAnimation(p)		; handle archer animations
			
			If Animating(p\model) Then
				Select p\animode
						Case A_STARTWALK
							TurnEntity pivot,  animspeed * 0.2,   0,  0	; Move Forward
						Case A_WALK
							TurnEntity pivot,  animspeed * 0.3,   0,  0	; Move Forward
						Case A_STARTRUN
							TurnEntity pivot,  0.4,   0,  0				; Move Forward Faster
		  				Case A_RUN
							TurnEntity pivot,  0.5,   0,  0				; Move Forward Faster
				End Select
			EndIf
			
				
			target = archer\model
			;        cam, ent,           spd,   dist,   height,     pitch,     roll
			SuperCam(cam,target,  		 0.1,    2.2,      1.5,         0,       0)
				
				If loc\sprite <> 0 Then
					;For i = 0 To 5
					;	dust.Particle = MakeParticle(loc\sprite, "dust", 0.1, p\model, Rnd(-.1,.1), Rnd(.1,.2), -0.1, p\model)
					;	ScaleSprite dust\entity,0.5,0.5
					;Next
				EndIf

			;If MouseHit(1) Then MENUSTATE = MENU_HELP
			;If MouseHit(2) GoToOrbit(loc)		; Right Click
					
	  Case AT_ARROW

			HandleAnimation(p)		; handle archer animations
		
			seconds = 1 * c_gameRate
			compression# = Float(seconds - p\bowticks) / seconds		; varies from 1 to 0
			
			If MouseDown(1) Then		; draw back arrow until mouse released
			
				DeleteArrows()
				
				ShowEntity p\arrow		; do some kind of nifty particle effect here
				If p\bowticks < seconds p\bowticks = p\bowticks + 1
				
				bowscale# = bowscl# ;archer\loc\radius# * plrscl# * bowscl#
				ScaleEntity p\bow,bowscale#,bowscale#,bowscale# * (2.0 - 1.0 * compression#)
				
				MoveEntity p\arrow, 0, 0, -0.02*bowscale#*compression#	; pull it back
				
				flarescale# = loc\radius# * plrscl# * bowscl# * (1.0 - compression#)
				ScaleSprite p\arrowflare,flarescale * 0.4,flarescale * 0.4
				
			ElseIf p\bowticks > 0 Then	; release arrow
			
				p\bowticks = 0
				
				ScaleBowToPlanet(loc)
		
				a.Arrow = New Arrow
					a\speed# = (1.0 - compression#)	; zero to one
				UpdateArrow(a)
				HideEntity p\arrow
			EndIf
		
	  Case AT_ORBIT
			OrbitFreeLook()
			
			If MouseHit(1) <> 0 Or MouseHit(2) <> 0 Then GoToCore(loc)		; Left/Right Click			
			;If MouseHit(2) GoToBeyond()		; Right Click
		
	  Case AT_RINGS
	  Case AT_LINK
	  Case AT_SPACE
			g_orbspd# = 10
		
			If beyondfixed Then
				dx# = 2 : dy# = 2 : dz# = 2
				PointEntity cam,sol\model,0
				TurnEntity cam,20,20,0
				;RotateEntity cam, DeltaPitch(cam, sol\model) * 0.02, DeltaYaw(cam, sol\model) * 0.02, 0
				TranslateEntity cam, dx, dy, dz
			Else
				TurnEntity cam,(myspd * 0.03),(-mxspd * 0.03),0
			EndIf
		
			;PointEntity cam,sol\model,0
		
			If KeyDown(200) Then
				MoveEntity cam, 0,  0,  10	; Up Arrow = Forward
				beyondfixed = False
				
			ElseIf KeyDown(208)
				MoveEntity cam, 0,  0, -10	; Down Arrow = Back
				beyondfixed = False
				
			ElseIf MouseHit(1) <> 0 Or MouseHit(2) <> 0 Then
				GoToOrbit(RandomPlanet())
				
				;GAMESTATE = GAME_OVER
				;GoToCore(RandomPlanet()) : beyondfixed = True
				;g_orbspd# = 3600
				
			EndIf
		
			farthest.Planet = Last Planet	
			If Abs(EntityDistance(cam, sol\model)) > Abs(EntityDistance(sol\model, farthest\model))*2 Then
				GAMESTATE = GAME_OVER
			EndIf
		
	End Select
	
	If p\state <> savedstate Then
		FlushMouse : FlushKeys
		DeleteArrows()
		;cam_yaw = 0 : cam_pitch = 0 : target_yaw = 0 : target_pitch = 0
	EndIf
End Function

forward = False
backward = False
animspeed# = 1

Function HandleAnimation(p.Player)
		loc.Planet = p\loc : If loc <> Null pivot = loc\campivot
		start = Not Animating(p\model)	; are we restarting animation after this update?
		
		If		KeyDown(200)	Or myspd < -3	Then	; smaller Y is higher on screen
			forward = True : backward = False
		ElseIf	KeyDown(208)	Or myspd > 3	Then	; bigger Y is lower on screen
			backward = True : forward = False
		EndIf
		
		TurnEntity pivot, 0, ClampValue(-(mxspd * 0.08), -3, 3), 0		; Turn Left/Right

		Select p\animode
			Case A_NONE
				If archer\state <> AT_ARROW Then p\animode = A_BREATH
				start = False
				forward = False : backward = False
				animspeed = 1
				
	      	Case A_BREATH
				If forward Or backward Then
					p\animode = A_STARTWALK
					If backward Then animspeed = -1
					forward = False : backward = False
					start = True			; don't wait for current animation to end
				EndIf
				If MouseHit(1) Or MouseHit(2) Then
					p\animode = A_LOADBOW
					animspeed = 0.3	
					start = True			; don't wait for current animation to end
				EndIf
				
		  	Case A_STARTWALK
				If start = True Then p\animode = A_WALK
				forward = False : backward = False

		  	Case A_WALK
				If start = True Then
					If animspeed = 1 Then
						If forward  Then p\animode = A_STARTRUN	; Go Forward Faster
						If backward Then p\animode = A_STOP		; Halt
					Else
						If forward	Then p\animode = A_STOP		; Halt
					EndIf
				EndIf
				If MouseHit(2) Then
					p\animode = A_LOADBOW	
					start = True			; don't wait for current animation to end
				EndIf

			Case A_STARTRUN
				If start = True Then p\animode = A_RUN
				forward = False : backward = False
				
		  	Case A_RUN
				If start = True Then
					If backward Then p\animode = A_WALK
					forward = False : backward = False
				EndIf
				
		 	Case A_STOP
				If start = True Then p\animode = A_NONE : start = False
				
		  	Case A_LOADBOW
				If start = True Then
					bowandarrow()
					p\animode = A_TILTBOW
					start = False
				EndIf
				
		  	Case A_TILTBOW
				start = False
				alen# = AnimLength(p\model) : p\atime# = AnimTime(p\model)
				atime# = p\atime

				If myspd >  1	Then atime# = atime - 1
				If myspd < -1	Then atime# = atime + 1
				SetAnimTime p\model,clampvalue(atime, 115, 125)
				
				pitch# = 115 - AnimTime(p\model)	; 0 to 10
				RotateEntity p\arrow,2*(pitch-2),0,0
				
				If MouseHit(2) Then			; right click
					p\animode = A_BREATHBOW
					GoToSurface(loc)
					start = True			; force animation to begin immediately
				EndIf
				
		  	Case A_LOWERBOW
				If start = True Then p\animode = A_NONE : start = False
				
		  	Case A_BREATHBOW
				If start = True Then
					p\animode = A_LOWERBOW
					animspeed = animspeed / 2		; animate at half speed
				EndIf
		End Select
		
		If start = True Then Animate p\model,3,animspeed,p\animode	; one-shot animation
End Function

; ==============================================================================

; Logic:   Each planet has a core pivot. The camera/character tethers to this pivot.
; Core:    Pivot and camera aligned, Z is forward. Flip camera 90 degrees when leaving mode.
; Surface: Pivot and camera aligned, Z is forward.

Function GoToCore(pn.Planet)

	pn\visited = True
	
	If Not pn\flipped Then
		FlipMesh pn\model : pn\flipped = True
	EndIf
	EntityAlpha pn\model,0.4	; make it semi-transparent
	EntityFX pn\model, 1		; eliminate planet shading (because normals are wrong)
	
	EntityParent pn\campivot, pn\orbpivot			; don't rotate with planet
	;RotateEntity pn\campivot, 0,0,0, True			; restore neutral orientation of pivot

	EntityParent   cam,   pn\campivot				; tether camera to pivot
	PositionEntity cam,   0,0,0						; move camera to pivot
	RotateEntity   cam,	  0,0,0						; align camera to pivot
	
	DebugLog whereis(cam)+whereis(pn\model)
	
	archer\loc = pn : archer\state = AT_CORE : archer\animode = A_NONE
End Function

; ==============================================================================

Function GoToSurface(pn.Planet)
	ScalePlayerToPlanet(pn)
	ScaleBowToPlanet(pn)
	
	;EntityParent pn\campivot, pn\model							; start rotating with planet
	EntityParent archer\model, pn\campivot						; tether character to pivot
	
	If savedstate = AT_CORE TurnEntity pn\campivot,90,0,0		; rotate pivot so 'up' is where it was facing
	
	PositionEntity archer\model,   0,0,0						; move character to pivot
	RotateEntity   archer\model,   0,0,0						; align character with pivot
	MoveEntity     archer\model,   0,pn\radius,0				; move to surface along pivot's Y axis	

	EntityParent cam, pn\campivot								; tether camera to pivot
	RotateEntity cam, 0,0,0										; align camera with pivot
	EntityParent cam,0											; untether camera

	DebugLog whereis(cam)+whereis(pn\model)

	archer\loc = pn : archer\state = AT_SURFACE
End Function

; ==============================================================================

Function GoToOrbit(pn.Planet)

	EntityParent pn\campivot, pn\orbpivot						; don't rotate with planet
	RotateEntity pn\campivot, 0,0,0,True						; align pivot with solar system plane
	MoveToEntity (pn\campivot, pn\model)
	
	EntityParent cam, pn\campivot								; tether camera to pivot
	MoveToEntity (cam, pn\campivot, True)
	
	MoveEntity cam, 0,0,(pn\radius * 1.7)						; move into orbit along Z axis
	PointEntity cam, pn\campivot, 0								; look towards pivot (negative Z)

	DebugLog whereis(cam)+whereis(pn\model)+whereis(pn\campivot)

	archer\loc = pn : archer\state = AT_ORBIT : archer\animode = A_NONE
End Function

; ==============================================================================

Function GoToBeyond()
	EntityParent cam, 0											; untether camera
	
	If archer\state <> AT_SPACE Then
		MoveToEntity(cam, sol\model)
	EndIf
	
	beyondfixed = True
	
	;CameraRange SL_GetLeftCamera(),  1, 50000	; near clipping plane, far clipping plane
	;CameraRange SL_GetRightCamera(), 1, 50000	; near clipping plane, far clipping plane
	
	archer\loc = Null : archer\state = AT_SPACE : archer\animode = A_NONE
End Function

; ==============================================================================

Function BowAndArrow()
	pn.Planet = archer\loc

	EntityParent pn\campivot, pn\model							; start rotating with planet
	EntityParent cam, pn\campivot								; tether cam to planet
	
	TFormPoint -.1,0,-.75,archer\bow,pn\campivot
	PositionEntity cam,TFormedX(),TFormedY(),TFormedZ()			; move camera back
	RotateEntity cam,EntityPitch(archer\model,True),EntityYaw(archer\model,True),EntityRoll(archer\model,True),True	; point it at the bow
	
	archer\state = AT_ARROW : archer\animode = A_NONE
End Function