:NAME exit

:VAR boolean	open
:VAR c_object*	closed_object

:GLOBAL float32 win_time
:GLOBAL boolean won

:PARAM float32			win_distance
:PARAM s_ping_effect@	open_ping_effect



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

local vectorlib = require "scripts/vector_math"

k_primary_player= e_value("e_player", "_player_primary")
k_win_delay= 1.5


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

function global_initialize(g)
	g.won= false
	g.win_time= -1
end

function param_initialize(p)
	p.win_distance= 2 -- CB: was 1
end

function var_initialize(v)
	v.open= true
	v.closed_object= nil
end

-- ------------------- code ------------------- 

function exit_player(exit, player, player_control)

	if (player.physics_model) then
		player.physics_model.collisions_disable()
	end
	
	local path= player.path_get()
	if (path) then
		path.clear_path()
		
		local marker= exit.marker_get("path_target");
		local path_target= marker.world_position_get(exit);
		path.add_step_raw(path_target.x, path_target.y);
	end
	
	if (player_control) then
		player_control.disabled= true
		player_control.exited= true
	end
	
	local vitality= player._c.vitality
	if (vitality) then
		vitality.invincible= true
	end
	
	local mask_spawner= exit.spawn_get("mask")
	if (mask_spawner) then
		local mask_marker= player.marker_get("path_line")
		if (mask_marker) then
			local mask= mask_spawner.spawn()
			if (mask) then
				object_attach_no_inherit(player, mask_marker, mask)
				mask.set_as_mask(true)
			end
		end
	end
	
	local other_unexited_players= false
	local iterator= world_state_get().component_cache.component_player.iterator_get()
	while (true) do
		local player_component= iterator.next()
		if (player_component) then
			local player= player_component.object
			local player_control= player._c.player_control
			if (player_control) then
				if (not player_control.exited and not player._p.player_control.exit_is_optional) then
					other_unexited_players= true
					break
				end
			end
		else
			break
		end
	end
	
	local target_component= player.target_component_get()
	if (target_component) then
		local target= target_component.target_handle
		if (target) then
			if (other_unexited_players) then
				target.set_targetable(false)		-- only if there are other unexited players
			else
				target.lock_state(true)				-- only if there are NOT other unexited players
			end
		end
	end
	
	player.tween_animation_play("exiting")
end


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

function should_be_open(object)
	local game_hud= world_state_get().global_script("game_hud")
	if (game_hud and game_hud.required_loot_counter > 0) then
		-- I can't exit any players if there are still required loots left
		return false
	end
	
	return true
end

function door_open(object)
	if (not var.open) then
		if (var.closed_object) then
			object_delete(var.closed_object)
			var.closed_object= nil
			object.hide(false)
		end
		var.open= true
		
		-- ping effect?
		if (param.open_ping_effect) then
			local distance_map= object.distance_map_get()
			if (distance_map) then
				local dm= distance_map.distance_map
				if (dm.valid()) then
					dm.ping(param.open_ping_effect)
				end
			end
		end
	end
end

function door_close(object)
	if (var.open) then
		object.hide(true)
		if (not var.closed_object) then
			var.closed_object= object.spawn("exit_closed")
		end
		var.open= false
	end
end

function attach(object)
	if (should_be_open(object)) then
		door_open(object)
	else
		door_close(object)
	end
	
	-- compute the distance map
	local distance_map= object.distance_map_get()
	if (distance_map) then
		local ping_marker= object.marker_get("ping")
		if (ping_marker) then
			local pos= ping_marker.world_position_get(object);
			distance_map.compute_at_point(pos.x, pos.y)
		end
	end
	
end

function update(object)

	if (global.won) then
		-- finished
	elseif (global.win_time >= 0) then
		local ws= world_state_get()
		
		local dt= ws.time.time - global.win_time
		if (dt > k_win_delay) then
			local game_hud= world_state_get().global_script("game_hud")
			global.won= true
			if (game_hud) then
				game_hud.win_pending= true
			end
		end
	
	else
		if (not should_be_open(object)) then
			-- do nothing
			if (var.open) then
				door_close(object)
			end
		else
			local w= world_get()
			local ws= world_state_get()
			local found_unexited_player= false
			
			if (not var.open) then
				door_open(object)
			end

			-- exit position			
			local object_point= object.world_position_get()
			
			local iterator= ws.component_cache.component_player.iterator_get()
			while (true) do
				local player_component= iterator.next()
				if (player_component) then
					local player= player_component.object
					local player_control= player._c.player_control
					if (player_control) then
						if (not player_control.exited) then
							
							-- see if I exited here
							local player_point= player.world_position_get()
							
							if (vectorlib.distance2d(object_point, player_point) < param.win_distance) then
								exit_player(object, player, player_control)
							else
								if (not player._p.player_control.exit_is_optional) then
									found_unexited_player= true
								end
							end
						end
					end
				else
					break
				end
			end

			if (not found_unexited_player) then
				local game_hud= world_state_get().global_script("game_hud")
				global.win_time= ws.time.time
				if (game_hud) then
					game_hud.loss_disable= true
				end
			end
		end
	end
end

component_register(attach, update, nil, nil)
