extends KinematicBody2D

const BASE_SPEED := 300.0
const EPSILON := 0.1
const MAX_STAMINA := 3.0
const BOOST_COEFF := 50.0
const STAMINA_RECOVER_RATE := 0.3
const NET_KEY_TRANSFORM_DELAY := 0.2

var velocity := Vector2.ZERO
var grip := 1.0
var stamina := MAX_STAMINA
var speed_boost := 0
var transform_update_remaining := 0.0

puppet var pup_motion := Vector2.ZERO
puppet var pup_velocity := Vector2.ZERO
puppet var pup_transform := Transform()

onready var scene := $"/root/scene"
onready var world := $"/root/scene/world"
onready var camera := $Camera
onready var netgame := $"/root/Multiplayer"

export var is_controlled := false setget set_is_controlled

var object_name setget ,get_name

func _ready():
	$Camera.current = is_controlled

func _physics_process(delta):
	var motion := Vector2.ZERO
	if is_network_master():
		if not scene.writing:
			motion = Vector2(
				Input.get_action_strength("ui_right")-Input.get_action_strength("ui_left"),
				Input.get_action_strength("ui_down")-Input.get_action_strength("ui_up"))
	
		# Check sprinting
		var speed := BASE_SPEED
		if Input.is_action_pressed("sprint") and not scene.writing:
			if motion.length() > EPSILON and stamina > 0:
				speed_boost += BOOST_COEFF * delta * ease(stamina/MAX_STAMINA, 1.1)
				stamina -= delta
				update()
		else:
			if stamina < MAX_STAMINA:
				stamina += delta * STAMINA_RECOVER_RATE
				update()
	
		# Apply friction to speed boost and the boost itself, if any
		if speed_boost > 0:
			speed_boost /= 2
			speed *= 1.0 + speed_boost
			if speed_boost < EPSILON:
				speed_boost = 0
	
		# Set velocity
		velocity = velocity * (1.0-grip) + motion.clamped(1.0) * speed * grip
		rset("pup_motion", motion)
		rset("pup_velocity", velocity)
		rset("pup_transform", global_transform)
	else:
		velocity = pup_velocity
		motion = pup_motion
		if transform_update_remaining <= 0.0:
			transform_update_remaining = NET_KEY_TRANSFORM_DELAY
			global_transform = pup_transform
		else:
			transform_update_remaining -= delta
		
	if motion.length() > EPSILON:
		$Sprite/AnimationTree.set("parameters/direction/blend_position", motion)

	velocity = move_and_slide(velocity)
	
	# Check what tile I'm on
	if world.map != null:
		grip = 0.0
		for tilemap in world.map.tilemaps:
			var cell = tilemap.get_cellv(tilemap.world_to_map(transform.origin))
			if cell >= 0:
				grip = 1.0

func set_is_controlled(val):
	is_controlled = val
	$Camera.current = val

func _draw():
	if is_network_master():
		if stamina+EPSILON < MAX_STAMINA:
			draw_circle_arc_poly(Vector2(-10, -30), 6, 0, stamina/MAX_STAMINA * 360, Color.orange)

func draw_circle_arc_poly(center, radius, angle_from, angle_to, color):
	var nb_points := 32
	var points_arc := PoolVector2Array()
	points_arc.push_back(center)
	var colors := PoolColorArray([color])

	for i in range(nb_points + 1):
		var angle_point = deg2rad(angle_from + i * (angle_to - angle_from) / nb_points - 90)
		points_arc.push_back(center + Vector2(cos(angle_point), sin(angle_point)) * radius)
	draw_polygon(points_arc, colors)

func get_info():
	return netgame.player_info[get_network_master()]

func get_name():
	var id := get_network_master()
	return netgame.player_info[id].name

func inspect():
	if is_network_master():
		return {
			"type": "Crewmember",
			"description": "That's you!"
		}
	return {
		"type": "Crewmember",
		"description": "A fellow crewmember"
	}
