------------------------------------------------------------------------------------
--    Схема: прячемся в кавере
------------------------------------------------------------------------------------
class "evaluator_need_cover" (property_evaluator)
function evaluator_need_cover:__init(storage, name) super(nil, name)
  	self.st = storage
end
function evaluator_need_cover:evaluate()
  	return xr_logic.is_active(self.object, self.st)
end

----------------------------------------------------------------------------------------------------------------------
class "action_cover" (action_base)
function action_cover:__init (npc_name, action_name, storage) super(nil, action_name)
	self.st = storage
end
function action_cover:initialize()
	action_base.initialize(self)
	self.board = sim_board.get_sim_board()
end
function action_cover:activate_scheme()
    self.st.signals = {}
    self.board = sim_board.get_sim_board()
    --' Высчитываем кавер.
    local base_point
    if self.st.smart ~= nil then
		base_point = sim_board.get_sim_board():get_smart_by_name(self.st.smart).m_level_vertex_id
    elseif self.st.path ~= nil then    
		base_point = patrol(self.st.path):level_vertex_id(0)
    end
       
    local direction_vector = vector():set(math.random(-100,100), 0, math.random(-100,100))
    local base_vertex_id = level.vertex_in_direction(base_point, direction_vector, math.random(self.st.radius_min,self.st.radius_max))
    local self_random_position = level.vertex_position(base_vertex_id)

	--' Получаем врага, относительно которого надо искать кавер
	self.enemy_random_position = self_random_position --' дефолтовая позиция
	if self.st.use_attack_direction then
		printf("use_attack_direction [true]")
		local squad = db.storage[self.object:id()].squad_obj
		if squad ~= nil then
			printf("squad ~= [nil]")
			local combat = self.board.smarts[squad.sim_combat_id].smrt.combat_manager
			for k,data in pairs(combat.squads) do
				local squad = self.board.squads[k]
				if squad.smart == nil or squad.smart.id ~= combat.smart.id then
					printf("squad.smart == [nil] or squad.smart.id ~= combat.smart.id")				
					for kk,vv in pairs(squad.squad_npc) do
						local obj = alife():object(kk)
						self.enemy_random_position = obj.position
						break
					end
					printf("enemy_random_position is [default]")
					break
				end
			end	
			printf("enemy_random_position is [default] combat.squads is empty")			
		end		
	end

	local cover = nil
	local tcover = nil
	if self.st.use_precalc_cover then
		tcover = cover_manager.get_cover(self.object, sim_board.get_sim_board():get_smart_by_name(self.st.smart))
		if tcover ~= nil then
			self.enemy_random_position = tcover.look_pos
		end
	else
		local cover_dist = 2
	    while cover == nil and cover_dist <= 4 do
			cover = self.object:best_cover(self_random_position, self.enemy_random_position, cover_dist, 1, 150)		
			cover_dist = cover_dist + 1		
		end	
	end

	if cover == nil then
		printf("cover is [nil]")
		self.cover_vertex_id = base_vertex_id
		self.cover_position = self_random_position
		printf("cover doesn't exists -- cover_vertex [%s] cover_position [%s]", tostring(self.cover_vertex_id), vec_to_str(self.cover_position))
	else
		if tcover ~= nil then
			self.cover_vertex_id = tcover.cover_vertex_id
			self.cover_position = tcover.cover_position
		else
			self.cover_vertex_id = cover:level_vertex_id()
			self.cover_position = cover:position()
		end
		printf("cover exists -- cover_vertex [%s] cover_position [%s]", tostring(self.cover_vertex_id), vec_to_str(self.cover_position))
	end
			
	if not self.object:accessible(self.cover_position) then
		local ttp = vector():set(0,0,0)
		self.cover_vertex_id = self.object:accessible_nearest(self.cover_position, ttp)
		self.cover_position = level.vertex_position(self.cover_vertex_id)
		printf("cover exists but not accesible -- cover_vertex [%s] cover_position [%s]", tostring(self.cover_vertex_id), vec_to_str(self.cover_position))
	end	

	self.object:set_dest_level_vertex_id(self.cover_vertex_id)
	printf("cover position is %s enemy position is %s",  vec_to_str(self.cover_position), vec_to_str(self.enemy_random_position))
	local desired_direction = vector():sub(self.cover_position,self.enemy_random_position)
	printf("desired_direction = %s", vec_to_str(desired_direction))
	if desired_direction ~= nil and not utils.vector_cmp(desired_direction, vector():set(0,0,0)) then
		desired_direction:normalize()
		self.object:set_desired_direction(desired_direction)
	end
	self.object:set_path_type(game_object.level_path)
	state_mgr.set_state(self.object, "assault")
	printf("[%s]Setting cover %s", self.object:name(), self.cover_vertex_id)
end
function action_cover:execute()
	--' Проверяем пришли ли в точку.
	if self.cover_position:distance_to_sqr(self.object:position()) <= 0.4 then
		local anim = xr_logic.pick_section_from_condlist(db.actor, self.object, self.st.anim)
		state_mgr.set_state(self.object, anim, nil, nil, {look_position = self.enemy_random_position}, nil, nil)
	else
		state_mgr.set_state(self.object, "assault")
	end
	if self.st.sound_idle ~= nil then
		xr_sound.set_sound_play(self.object:id(), self.st.sound_idle)
	end	
	action_base.execute(self)
end
function action_cover:finalize()
	action_base.finalize(self)
end
--' Возвращает достиг ли персонаж точки начала работы схемы
function action_cover:position_riched()
	return self.cover_position:distance_to_sqr(self.object:position()) <= 0.4
end

----------------------------------------------------------------------------------------------------------------------
-- binder
----------------------------------------------------------------------------------------------------------------------
function add_to_binder(npc, ini, scheme, section, storage)
  		local operators	= {}
	  	local properties  = {}
		
	   	local manager = npc:motivation_action_manager()

		properties["event"]			= xr_evaluators_id.reaction
	 	properties["need_cover"]	= xr_evaluators_id.stohe_cover_base + 1
		
	 	operators["action_cover"]	= xr_actions_id.stohe_cover_base + 1

	   	-- evaluators
		manager:add_evaluator(properties["need_cover"], this.evaluator_need_cover(storage, "need_cover"))

		local new_action = this.action_cover(npc, "action_cover", storage)
		new_action:add_precondition(world_property(stalker_ids.property_alive,true))
		new_action:add_precondition(world_property(stalker_ids.property_danger,false))
		new_action:add_precondition(world_property(stalker_ids.property_enemy,false))
		new_action:add_precondition(world_property(stalker_ids.property_anomaly,false))
		new_action:add_precondition(world_property(xr_evaluators_id.sidor_wounded_base + 0,false))
		new_action:add_precondition(world_property(xr_evaluators_id.smartcover_action + 3, false))
		new_action:add_precondition(world_property(properties["need_cover"],true))
	   	new_action:add_effect(world_property(properties["need_cover"],false))
		manager:add_action(operators["action_cover"], new_action)

		-- Зарегистрировать все actions, в которых должен быть вызван метод reset_scheme при изменении настроек схемы:
		xr_logic.subscribe_action_for_events(npc, storage, new_action)

	  	new_action = manager:action(xr_actions_id.alife)
	  	new_action:add_precondition(world_property(properties["need_cover"], false))
end

-- Включение схемы
function set_scheme(npc, ini, scheme, section, gulag_name)
	local st = xr_logic.assign_storage_and_bind(npc, ini, scheme, section)

	st.logic    = xr_logic.cfg_get_switch_conditions(ini, section, npc)

	st.path		= utils.cfg_get_string(ini, section, "path_walk", npc, false, gulag_name)
	st.smart	= utils.cfg_get_string(ini, section, "smart", npc, false, "")
	st.anim		= xr_logic.parse_condlist(npc, "anim", "anim", utils.cfg_get_string(ini, section, "anim", npc, false, "", "hide"))
	st.sound_idle= utils.cfg_get_string(ini, section, "sound_idle",npc, false, "")
		
	if st.path == nil and st.smart == nil then
		abort("There is no path_walk and smart in xr_cover.")
	end
	
	st.use_attack_direction = utils.cfg_get_bool(ini, section, "use_attack_direction", npc, false, true)
	st.use_precalc_cover = utils.cfg_get_bool(ini, section, "use_precalc_cover", npc, false, false)
	st.radius_min = utils.cfg_get_number(ini, section, "radius_min", npc, false, 3)
	st.radius_max = utils.cfg_get_number(ini, section, "radius_max", npc, false, 5)
end