:NAME shield

:PARAM float32				duration	
:PARAM s_ping_effect@		ping
:PARAM float32				ping_delay
:PARAM s_function1d			distance_to_miss_radius_func
:PARAM s_function1d			distance_to_force_func

:ENEMY c_object*			object
:ENEMY boolean				shooter

:VAR float32		last_ping_time
:VAR enemy[]		enemies

-- ------------------- constants ------------------- 

k_bar_width= 1
k_bar_height= 0.25
k_y_offset= 0.4

k_bar_color= {}
k_bar_color.red= 0.85			-- 1
k_bar_color.blue= 0				-- 1
k_bar_color.green= 0.17			-- 0

k_empty_color={}
k_empty_color.red= 0.0			-- 0.2
k_empty_color.blue= 0.0			-- 0.2
k_empty_color.green= 0.0		-- 0.0

k_default_radius= 2

local vectorlib = require "scripts/vector_math"


-- ------------------- initialization ------------------- 

function param_initialize(p)
	p.duration = 2	
	p.ping_delay= 0.4
end

function var_initialize(v)
	v.last_ping_time= -100
end


-- ------------------- component ------------------- 


function draw_timer(object, dt)
	local base_point = object.world_position_get()

	base_point.x = base_point.x - k_bar_width/2
	base_point.y = base_point.y + k_y_offset
	
	local top_left= {}
	top_left.x= base_point.x
	top_left.y= base_point.y + k_bar_height
	
	local end_point= {}
	end_point.x = base_point.x + k_bar_width
	end_point.y = base_point.y
	
	render_rectangle(object.plate, top_left, end_point, k_empty_color, true)

	local fraction= 1 - dt/param.duration	
	end_point.x = base_point.x + fraction*k_bar_width
	
	render_rectangle(object.plate, top_left, end_point, k_bar_color, true)

end

function attach(object)
	local ws= world_state_get()
	
	-- collect a list of all enemies
	local iterator= ws.component_cache.component_perception.iterator_get()
	while (true) do
		local perception= iterator.next()
		if (perception) then
			local enemy = var.enemies.create()
			if (enemy) then
				enemy.object= perception.object
				enemy.shooter = (enemy.object._c.shoot_control ~= nil)
			end
		else
			break
		end
	end
	
end

k_shield_color= {}
k_shield_color.red= 0.8
k_shield_color.green= 0.8
k_shield_color.blue= 1

function debug(object)
	local position= object.world_position_get()
	local plate= object.plate
	local parent= object.attachment.parent
	if (parent) then
		plate= parent.plate
	end
	
	render_circle(plate, position, var.radius, k_shield_color, false)
end

function finish(object)

	-- reset the miss angle on all the shooters
	local iterator= var.enemies.iterator_get()
	while (true) do
		local enemy= iterator.next()
		if (enemy) then
			if (enemy.shooter) then
				local shoot_control= enemy.object._c.shoot_control
				shoot_control.miss_angle= 0
			end
		else
			break
		end
	end

	object_delete(object)
end

function update(object)
	
	local ws= world_state_get()
	local time= ws.time.time		

	-- grab the player object, but potentially use the player proxy
	local player= ws.primary_player_get()
	local gear_manager= ws.global_script("gear_manager")	
	if (gear_manager and gear_manager.player_proxy) then
		player= gear_manager.player_proxy
	end

	local player_pos= player.world_position_get()
	local miss_radius_func= nil
	local force_func= nil
	local make_noise= false
	
	if (param.distance_to_miss_radius_func.valid()) then
		miss_radius_func= param.distance_to_miss_radius_func
	end
	if (param.distance_to_force_func.valid()) then
		force_func= param.distance_to_force_func
	end
	
	-- update the miss radius for each enemy
	local iterator= var.enemies.iterator_get()
	while (true) do
		local enemy= iterator.next()
		if (enemy) then
			local enemy_object= enemy.object
			local enemy_pos= enemy_object.world_position_get()
			local v= vectorlib.vector_from_points(enemy_pos, player_pos)
			local d= vectorlib.normalize2d(v)
			
			if (miss_radius_func and enemy.shooter and (d > 0)) then
				local shoot_control= enemy_object._c.shoot_control
				local r= param.distance_to_miss_radius_func.evaluate(d)
				shoot_control.miss_angle= math.atan(r/d)
			end
			
			-- possible also force them away
			if (force_func) then
				local physics_model= enemy_object.physics_model
				if (physics_model) then
					local f= -force_func.evaluate(d)
					if (math.abs(f) > 0.001) then
						physics_model.impulse(f*v.x, f*v.y)
						
						-- if they don't know about us, they should!
						make_noise= true
					end
				end
			end
		else
			break
		end
	end
	
	if (make_noise and player) then
		local target= player.target_get()
		if (target) then
			target.make_sound(0.1, false)
		end
	end
	
	local dt= time-object.placement_time
	if (dt < param.duration) then
		draw_timer(player, dt)
	else
		finish(object)
	end
	
	if (param.ping and ((time - var.last_ping_time) > param.ping_delay)) then
	
		local dmap_component = object.distance_map_get()
		if (dmap_component) then
			local pos= player.world_position_get()
			dmap_component.compute_at_point(pos.x, pos.y)
			
			local dmap= dmap_component.distance_map
			if (dmap.valid()) then
				dmap.ping(param.ping)
			end
			
			var.last_ping_time= time
		end
	end
	
	--debug(object)
end

component_register(attach, update, nil, nil)
