#Johann Massyn, 23/06/2019
#Godot (3.1) 3D Player movement script

#Atatch script to 3d node with following structure
#Kinematic body: Player
#  - CollisionShape: CollisionShape
#  - Camera: Camera

extends KinematicBody

export (bool) var can_move = true #Alow player to input movment.
export (bool) var can_sprint = true #Alow player to toggle sprint movment.
export (float) var move_speed = 8 #Players movement speed
export (float) var move_speed_sprint = 16#16 #Players sprint movement speed
export (bool) var move_sprint = false #Player sprinting toggle
export (float) var move_speed_max = 200 #Player maximum velocity
export (float) var move_acceleration = 7 #Players acceleration to movment speed
export (float) var move_deacceleration = 10 #Players deacceleration from movment speed
export (bool) var mouse_captured = true #Toggles mouse captured mode
export (float) var mouse_sensitivity_x = 0.3 #Mouse sensitivity X axis
export (float) var mouse_sensitivity_y = 0.3 #Mouse sensitivity Y axis
export (float) var mouse_max_up = 45 #Mouse max look angle up
export (float) var mouse_max_down = -50 #Mouse max look angle down
export (float) var jump_speed = 6 #Players jumps speed
export (float) var jump_speed_sprint = 12 #Players jumps speed
export (bool) var allow_fall_input = true #Alow player to input movment when falling
export (bool) var stop_on_slope = false #Toggle sliding on slopes
export (float) var max_slides = 4 #Maximum of slides
export (float) var floor_max_angle = 60 #Maximum slop angle player can traverse
export (bool) var infinite_inertia = false #Toggle infinite inertia
export (float) var gravaty = 1.625 #9.81 #Gravaty acceleration
#export (Vector3) var gravaty_vector = Vector3(0, -1, 0) #Gravaty normal direction vector
#export (Vector3) var floor_normal = Vector3(0, 1, 0) #Floor normal direction vector
#export (Vector3) var jump_vector = Vector3(0, 1, 0) #Jump normal direction vector
export (Vector3) var velocity = Vector3(0, 0, 0) #Initial velocity

onready var up = global_transform.origin.normalized()
onready var forward = global_transform.basis.y
onready var right = forward.cross(up).normalized()

export (int) var move_mode = 0
enum moveMode {MODE_NORMAL, MODE_HOVER, MODE_FLY}

func _ready():
	if mouse_captured:
		Input.set_mouse_mode(Input.MOUSE_MODE_CAPTURED)
	pass
	
func moveTo(pos = Vector3()):
	if pos.z == 0:
		pos.z = 1737.4
	move_and_slide(Common.latLonToGlobal(Vector3(pos.x,pos.y,pos.z)), Vector3.UP)

func getSpos():
	var sPos = Common.globalToLatLon(self.global_transform.origin)
	sPos.y = Common.relativeToAbsolute(sPos.y)
	return sPos

func _process(delta):
	var pos = self.global_transform.origin
	.get_parent().get_node("UI/1").text="x:%s y:%s z:%s" %[pos.x, pos.y, pos.z]
	.get_parent().get_node("UI/2").text="latlonhight: "+str(getSpos())+","+str(pos.length())
	.get_parent().get_node("UI/3").text="vel: %s" % velocity
	.get_parent().get_node("UI/4").text="mode: %s" % move_mode

	#floor_normal = pos.normalized()
	#gravaty_vector = floor_normal * -1
	#self.transform.basis.y = floor_normal
	#rotation_degrees.x = 90
	
func _physics_process(delta):
	
	
	up = global_transform.origin.normalized()
	right = forward.cross(up).normalized()
	forward = up.cross(right).normalized()
	transform.basis = Basis(right, up, -forward)
	
	# we differentialte the y portion to apply a different speed (jump_speed)
	var horDir = Vector3()
	var vertDir = Vector3()
	match move_mode:
		moveMode.MODE_FLY:
			horDir = forward
		moveMode.MODE_HOVER:
			horDir = -velocity * 0.5
	
	if can_move and (is_on_floor() or allow_fall_input):
		
		#Left
		if Input.is_action_pressed("move_left"):
			horDir -= right
			
		#Right
		if Input.is_action_pressed("move_right"):
			horDir += right
			
		#Forward
		if Input.is_action_pressed("move_forward"):
			horDir += forward
		
		#Backwards	
		if Input.is_action_pressed("move_backward"):
			horDir -= forward
			
		# Jump
		#if is_on_floor():
		#if Input.is_action_pressed("move_up"):
		#	dir += up
		if Input.is_action_pressed("move_down"):
			vertDir -= up
			
		#Jump
		if Input.is_action_pressed("move_up"):# and is_on_floor():
			vertDir += up
	
		#Sprint toggle
		if can_sprint and Input.is_action_just_pressed("move_sprint"): #and is_on_floor():
			move_sprint = true
			move_speed_max = 600
			
		if can_sprint and not Input.is_action_pressed("move_sprint"): #and is_on_floor():
			move_sprint = false
			move_speed_max = 200
			
		#Hover toggle
		if Input.is_action_just_pressed("hover_mode"):
			if move_mode != moveMode.MODE_HOVER:
				move_mode = moveMode.MODE_HOVER
			else:
				move_mode = moveMode.MODE_NORMAL
				
		#Fly toggle
		if Input.is_action_just_pressed("fly_mode"):
			if move_mode != moveMode.MODE_FLY:
				move_mode = moveMode.MODE_FLY
			else:
				move_mode = moveMode.MODE_NORMAL	
	
	if move_mode == moveMode.MODE_NORMAL and horDir+vertDir == Vector3(0, 0, 0):
		# in NORMAL MODE velocity stays unchanged without input
		pass
	else:
		#velocity = velocity.linear_interpolate(horDir * (move_speed_sprint if move_sprint else move_speed)
		#								+ vertDir * (jump_speed_sprint if move_sprint else jump_speed), move_acceleration * delta)
		velocity += (horDir * (move_speed_sprint if move_sprint else move_speed)
				  + vertDir * (jump_speed_sprint if move_sprint else jump_speed)) * move_acceleration * delta
	
	#velocity = velocity.linear_interpolate(vertDir * (jump_speed_sprint if move_sprint else jump_speed), move_acceleration * delta)
	#if !is_on_floor():
		#velocity -= up * gravaty
		
	# limit Speed
	if velocity.length() > move_speed_max:
		velocity = velocity.normalized() * move_speed_max

	velocity = move_and_slide(velocity, up)
	
	
	
	
	#Smooth movement
	#dir = transform.basis.xform(dir.normalized()) * (move_speed_sprint if move_sprint else move_speed)
	#if is_on_floor() or dir != Vector3(0, 0, 0):
	#	var acceleration = move_acceleration if dir.dot(velocity) else move_deacceleration
	#	var vp = gravaty_vector.normalized() * velocity.dot(gravaty_vector)
	#	velocity = (velocity - vp).linear_interpolate(dir, acceleration * delta) + vp
	
	#Gravaty
	#if !is_on_floor():
	#	velocity += gravaty_vector * gravaty * delta
	
	#Player move
	#move_and_slide(velocity, floor_normal, stop_on_slope, max_slides, deg2rad(floor_max_angle), infinite_inertia)
	
	#Player orientation
	#var spos = Common.globalToLatLon(self.global_transform.origin)
	#global_rotate(Vector3(1,0,0), deg2rad(spos.x))
	#global_rotate(Vector3(0,1,0), deg2rad(spos.y))


func _input(event):
	#Mouse movement
	if event is InputEventMouseMotion and Input.get_mouse_mode() == Input.MOUSE_MODE_CAPTURED:
		#rotate_y(deg2rad(-event.relative.x * mouse_sensitivity_x))
		forward = forward.rotated(up, deg2rad(-event.relative.x * mouse_sensitivity_x))
		#rotate_y(deg2rad(-event.relative.x * mouse_sensitivity_x))
		#self.rotation_degrees.y += -event.relative.x * mouse_sensitivity_x
		$Camera.rotation_degrees.x = clamp($Camera.rotation_degrees.x + -event.relative.y * mouse_sensitivity_y, mouse_max_down, mouse_max_up)
	pass
