----------------------------------
--' Подбор барахла и переодевание неписей 
--' на основе AI Pack by xStream 03.2008
--' Автор: Skunk
--' 15.10.2009
----------------------------------

local excluded_npcs={
"zat_b18_noah", -- Ной
"zat_b38_stalker_cop", -- Глухарь
"zat_b53_artefact_hunter", -- туториальные охотники за артами
"zat_a2_stalker_nimble", -- Шустрый
"mechanic",
"trader",
"medic",
"barmen",
"guide",
"zat_b7_bandit_boss_sultan",
"zat_b106_stalker_crab", -- раненый в Скадовске
"tech",
"jup_b10_stalker_drunk",
"leader",
"jup_b220_trapper",
"jup_b15_zulus",
"jup_b6_scientist_nuclear_physicist",
"jup_b6_scientist_biochemist",
--припять
"pri_a17_military_colonel_kovalski",
"pri_a17_military_captain_tarasov",
"pri_a17_military_prapor_valentyr",
"pri_a17_military_sergeant_morozov",
"pri_a17_military_lieutenant_podorojniy",
"pri_a15_military_recon_leader",
"pri_a15_sokolov",
"pri_a21_chasovoi_target",
"pri_a22_military_yarmoshuk",
"pri_a22_military_skelja",
"pri_a22_military_merkulov",
"pri_a15_vano",
"pri_a15_sokolov_scene",
"pri_a15_zulus",
"pri_a15_wanderer",
"pri_a15_military_tarasov",
"pri_a22_army_signaller",
"pri_b35_merc_leader",
"pri_b305_strelok",
"pri_b305_signal_man"
}

function excluded(npc_name)
	for i=1,#excluded_npcs do
		if string.find(npc_name, excluded_npcs[i]) then
			return true
		end
	end
	return false
end

local table_active_ruck={}

-------------------------
-- scheme part
-------------------------
evid_items=18690
actid_items=18690+2
exclusions={}
items={}
local tmp

----------------------------------------------------------------------------------------------------------------------
-- EVALUATORS
----------------------------------------------------------------------------------------------------------------------
class "evaluator_see_useful_items" (property_evaluator)
function evaluator_see_useful_items:__init(name, storage) super (nil, name)
	self.a = storage
end
function evaluator_see_useful_items:evaluate()
    if surge_manager.is_started() then
		return false
	end
	local npc=self.object
	if not npc:alive() then
		return false
	end
	if npc:best_enemy() ~= nil then
		return false
	end
	if npc:character_community() == "zombied" then
		return false
	end
	if xr_wounded.is_wounded(npc) then
		return false
	end
	if npc:section() == "actor_visual_stalker" then
		return false
	end
	local npc_id=npc:id()
	if excluded(npc:name()) then return false end
	if self.a.see_items and items[self.a.see_items] and items[self.a.see_items].npc_id==npc_id then
		local o = level.object_by_id(self.a.see_items)
		if o and o:position():distance_to_sqr(npc:position())<14400 and npc:accessible(o:level_vertex_id()) and level.vertex_position(o:level_vertex_id()):distance_to(o:position())<1 then
			return true
		else
			items[self.a.see_items]=nil
			self.a.see_items=nil
		end
	end
	if (self.next_check_time or 0) > time_global() then return false end
	self.next_check_time = time_global() + 5000
	local function check_item(obj)
		local obj_id
		if type(obj)=="number" then
			obj=level.object_by_id(obj)
			if obj==nil or check_active_ruck(obj,npc)~=true then return false end
			obj_id=obj:id()
		else
			obj=obj:object()
			if obj==nil or obj.clsid==nil or obj.id==nil then return false end
			if IsMonster(obj) and obj.alive and obj:alive() then return false end
			obj_id=obj:id()
			if ars_mutanter.monster_table[obj_id] and ars_mutanter.monster_table[obj_id].check_body then return false end
		end
		if exclusions[npc_id.."_"..obj_id]==true or items[obj_id] then return false end
		if obj:section()~="active_ruck" then
			if obj:parent()==nil and npc:see(obj) and obj_detect(npc, obj)==true and obj:position():distance_to_sqr(npc:position())<900 and npc:accessible(obj:level_vertex_id()) and level.vertex_position(obj:level_vertex_id()):distance_to(obj:position())<1 then
				return obj_id
			else
				exclusions[npc_id.."_"..obj_id]=true
				return false
			end
		else
			if  obj:position():distance_to_sqr(db.actor:position())>25 and obj:position():distance_to_sqr(npc:position())<14400 and npc:accessible(obj:level_vertex_id()) and level.vertex_position(obj:level_vertex_id()):distance_to(obj:position())<1 then
				return obj_id
			else
				exclusions[npc_id.."_"..obj_id]=true
				return false
			end
		end
	end
	local item = false
	local flag = false
	for o in npc:memory_visible_objects() do
		item = check_item(o)
		if item then 
			self.a.see_items = item
			items[item]={}
			items[item].npc_id=npc_id
			flag = true
		end
	end
	for o in npc:memory_sound_objects() do
		item = check_item(o)
		if item then 
			self.a.see_items = item
			items[item]={}
			items[item].npc_id=npc_id
			flag = true
		end
	end
	if table_active_ruck and #table_active_ruck>0 then
		for k,v in ipairs(table_active_ruck) do
			item = check_item(v)
			if item then 
				self.a.see_items = item
				items[item]={}
				items[item].npc_id=npc_id
				flag = true
			end
		end
	end
	return flag
end

----------------------------------------------------------------------------------------------------------------------
-- Actions
----------------------------------------------------------------------------------------------------------------------
class "action_get_useful_items" (action_base)
function action_get_useful_items:__init (npc,action_name,storage) super (nil,action_name)
	self.a = storage
end
function action_get_useful_items:initialize()
	action_base.initialize(self)
	local npc=self.object
	npc:set_desired_position()
	npc:set_desired_direction()
	npc:set_dest_level_vertex_id(level.object_by_id(self.a.see_items):level_vertex_id())
	state_mgr.set_state(npc, "patrol")
end
function action_get_useful_items:execute()
	action_base.execute (self)
	local npc=self.object
	local npc_id=npc:id()
	local obj_id=self.a.see_items
	local o = level.object_by_id(obj_id)
	if o==nil then
		items[obj_id]=nil
		self.a.see_items = nil
		self.end_time=nil
		return
	end
	self.prefdir=npc:direction()
    if not IsMonster(o) and o:parent()~=nil and o:section()~="active_ruck" then 
		if o:parent():id()==db.actor:id() then
			if obj_cost_value(o)>999 and level.vertex_position(db.actor:level_vertex_id()):distance_to_sqr(npc:position())<4 then 
				punch_v_mordu(npc)
			end
		end
		items[obj_id]=nil
		self.a.see_items = nil
		self.end_time=nil
		return
	end	
	if not self.end_time then
		if o:position():distance_to_sqr(npc:position())<1.5 then 
			npc:set_desired_position()
			npc:set_desired_direction()
			npc:set_dest_level_vertex_id(npc:level_vertex_id())
			if not IsMonster(o) and o:section()~="active_ruck" then 
				state_mgr.set_state(npc,"search",nil,nil,{look_position = o:position()}, {animation = true})
				if npc:animation_count()>0 then 
					self.end_time = time_global() + 4500
				end
			else
				state_mgr.set_state(npc,"dynamite",nil,nil,{look_position = o:position()}, {animation = true})
				if npc:animation_count()>0 then 
					self.end_time = time_global() + 5800
				end
			end
			self.ends=nil
		else
			npc:set_desired_position()
			npc:set_desired_direction()
			npc:set_dest_level_vertex_id(o:level_vertex_id())
			state_mgr.set_state(npc, "patrol")
		end
	elseif self.end_time<time_global() then
		if not self.ends then
			if not IsMonster(o) and o:section()~="active_ruck" then
				if o:parent()==nil and o:position():distance_to_sqr(npc:position())<1.5 then
					o:transfer_item(o, npc)
				end
			elseif o:section()=="active_ruck" and o:position():distance_to_sqr(npc:position())<1.5 then
				o:iterate_inventory_box(function (dummy, item) 
				if obj_detect(npc, item, "steal") then
					o:transfer_item(item, npc)
				end
				end, nil)
			else
				if o:position():distance_to_sqr(npc:position())<1.5 and not (ars_mutanter.monster_table[obj_id] and ars_mutanter.monster_table[obj_id].check_body) then
					ars_mutanter.spawn_parts(obj_id,npc_id)
					ars_mutanter.add_monster(obj_id,npc_id)
				end
			end
			self.ends=time_global()+1500
			if not self.timer then
				self.timer=time_global()+15000
			end
		elseif self.ends<time_global() then
			self.ends=time_global()+1500
		    npc:set_item(object.activate, npc:best_weapon())	
		    local pos=level.vertex_in_direction(npc:level_vertex_id(),vector_rotate_y(self.prefdir,180),10)
		    if not npc:accessible(pos) then
			  local ttp = vector():set(0,0,0)
			  pos = level.vertex_position(npc:accessible_nearest(pos, ttp))
		    end
            npc:set_desired_position()
            npc:set_desired_direction()
            npc:set_dest_level_vertex_id(pos)
            state_mgr.set_state(npc, "patrol")
			items[obj_id]=nil
		end
	end
	if self.timer and self.timer<time_global() then
		exclusions[npc_id.."_"..obj_id]=true
	end
end

function action_get_useful_items:finalize()
	action_base.finalize (self)
	self.a.see_items=nil
	self.end_time=nil
	self.ends=nil
	self.timer=nil
end

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

	properties["items_exist"]				= evid_items
	properties["wounded"]					= xr_evaluators_id.sidor_wounded_base
	operators["search_items"]				= actid_items
	operators["state_mgr_to_idle_alife"]	= xr_actions_id.state_mgr + 2

	manager:add_evaluator (properties["items_exist"], evaluator_see_useful_items("items_exist", storage))
	
	local action = action_get_useful_items(object:name(),"action_get_useful_items", storage)
	action:add_precondition(world_property(stalker_ids.property_alive,true))
	action:add_precondition(world_property(stalker_ids.property_enemy,false))
	action:add_precondition(world_property(stalker_ids.property_danger,false))
	action:add_precondition(world_property(stalker_ids.property_anomaly,false))
	--if(level_anomaly)then
		--action:add_precondition(world_property(1099,false))
	--end
	--action:add_precondition(world_property(stalker_ids.property_items,false))
	action:add_precondition(world_property(properties["items_exist"],true))
	action:add_precondition(world_property(properties["wounded"],false))
	action:add_precondition(world_property(xr_evaluators_id.wounded_exist,false))

	action:add_effect(world_property(properties["items_exist"],false))
	manager:add_action(operators["search_items"],action)

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

	action = manager:action (operators["state_mgr_to_idle_alife"])
	action:add_precondition	(world_property(properties["items_exist"],false))
end

function set_scheme(npc, ini, scheme, section)
	local st = xr_logic.assign_storage_and_bind(npc, ini, scheme, section)
end

function disable_scheme(npc, scheme)
	local st = db.storage[npc:id()][scheme]
	if st then
		st.enabled = false
	end
end

function is_under_items_detection(npc)
	local mgr = npc:motivation_action_manager()
	if not mgr:initialized() then
		return false
	end
	local current_action_id = mgr:current_action_id() 
	return  current_action_id == xr_items_detection.evid_items
end

function obj_cost_value(obj)
	local sect=obj:section()
	local multiplier=1
	if string.find(sect,"ammo_") then
		multiplier=15
	elseif sect=="vodka" then
		multiplier=20
	elseif (get_clsid(obj)==clsid.wpn_grenade_rgd5_s or get_clsid(obj)==clsid.wpn_grenade_f1_s) then
		multiplier=3
	elseif string.find(sect,"medkit") or string.find(sect,"booster") or string.find(sect,"drug") or sect=="antirad" or sect=="bandage" then
		multiplier=10
	end
	if system_ini():section_exist(sect) and system_ini():line_exist(sect,"cost") then
		return system_ini():r_float(sect,"cost")*multiplier
	end
	return 0
end

function obj_detect(npc, obj, flag)
	if not IsMonster(obj) and obj:section()~="active_ruck" then
		local obj_cost = obj_cost_value(obj)
		if not flag then
			if obj_cost >= 5000 then
				return true
			elseif obj_cost >= 600 and obj:condition() >= 0.6 then
				return true
			end
		else
			if flag == "steal" then
				if (obj_cost >= 5000 and obj:condition() >= 0.75) or (npc:best_weapon() and obj_cost_value(npc:best_weapon()) < obj_cost) then
					return true
				end
			end
		end
	else
		return true
	end
	return false
end

function punch_v_mordu(npc)
	if math.random(1,1000) > 900 then
		npc:set_relation(game_object.enemy, db.actor)
	else
		xr_abuse.add_abuse(npc, 100)
	end		
end

local active_ruck_checked={}
function check_active_ruck(obj,npc)
--	if active_ruck_checked[obj:id()]~=nil then
--		return active_ruck_checked[obj:id()]
--	end
	local cnt=0
	local treasure
	obj:iterate_inventory_box(function (dummy, item) 
	local value = obj_cost_value(item)
	if obj_detect(npc,item,"steal")==true then
		treasure = true
	end
	cnt=cnt+value 
	end, nil)
	active_ruck_checked[obj:id()]=cnt>30000
	return active_ruck_checked[obj:id()]==true and treasure==true
end		

function add_active_ruck(obj)
	if obj:section()=="active_ruck" then
		table.insert(table_active_ruck, obj:id())
	end
end