-- offline жизнь АМК
off_npcs = {}
items = {}
local relation_matrix = {}
local sell_table = {}
local item_dependence = {}
local always_keep_item = {}

local wpn_fp = {}
local bFlag = false	-- Пора апдейт делать
local iCounter = 1	-- Номер последнего отработанного обьекта
local iTime = game.minutes()	-- Время последнего глобального апдейта
local iFreq = 60	-- Как часто делать апдейты, игровые минуты
local initialized = false

local monster_params = {}

local maps = {		-- Уровни, где есть оффлайн жизнь
	"l01_escape",
	"l02_garbage",
	"l03_agroprom",
	"l04_darkvalley",
	"l05_bar",
	"l06_rostok",
	"l07_military",
	"l08_yantar",
	"l41_darkscape_ogse",
	"l10_radar",
	"l11_pripyat",
	"limansk",
	"red_forest",
	"lost_village",
	"marsh",
	"dead_city",
	"zaton",
	"jupiter",
	"pripyat",
	"l40_dshor",
	"l46_science_station",
	"l37_kurchatov"
}

protected = {
	names = {},		-- имена объектов (стоит добавлять только уникальные имена!)
	ids = {},		-- ID объектов
	story_ids = {	-- story ID объектов
	5008,
	5013,
	5014,
	5041,
	5065,
	5084,
	5104,
	5205,
	5222,
	5226,
	5237,
	5238,
	5243,
	5244,
	5245,
	5246,
	5247,
	5248,
	5249,
	5250,
	5254,
	5255,
	5408,
	5413,
	5428,
	5433,
	5434,
	5444,
	5446,
	5470,
	5471,
	5472,
	5473,
	5474,
	573
	},
	sections = {	-- секции объектов
		"dyak_mines_box",
		"raritet_box",
		"taynik_virus",
		"taynik_podarok"
	}
}

local smart_filters = {
	"esc_bridge", "esc_blokpost"
}

local rel_enemy,rel_friend

local look_radius = 50			-- радиус "обзора"
local look_radius_box = 0		-- Радиус поиска нычек
local search_intensivity = 60	-- интенсивность поиска (количество отрабатываемых неписей)
local max_rounds = 10			-- продолжительность боев
local health_wound = 0.20		-- При каком уровне здоровья НПС считается раненым
local health_wound_set = 0.02
local base_fp = 1400			-- Эталон firepower\distance при distance = 1 который снимет 100% health
local dist_coeff = 8			-- Коэффициент для расстояния
local sell_limit = 3000			-- Вещи дешевле продает торговцам

-- Рейтинг за убийство. При убийстве более слабого - 0.5 * rate_kill_base, более сильного - 2 * rate_kill_base
local rate_kill_base = 100
local rate_art_found = 100
local to_actor = 150

function init()
	if (initialized == false) then
		build_tables()
		iTime = (game.minutes() - iFreq) + 3
		initialized = true
	end
end

function update()
	if (bFlag == false and iTime ~= -1) then
		if (game.minutes() - iTime > iFreq) then
			bFlag = true			
			off_npcs={}	
			items={}
			iCounter = 1
		end
	end
	if (bFlag == true) then
		if (iCounter >= 65535) then
			bFlag = false
			iTime = game.minutes()
			iCounter = 1
		else
			local obj
			obj = server_object(iCounter)
			add_fresh_meat(obj)
			iCounter = iCounter + 1
		end
	end
end

--on_death - не убиваем!
--on_hit - не обрабатываем!
function add_fresh_meat(obj, o)
	if not obj or not graph:valid_vertex_id(obj.m_game_vertex_id) then return end
	if protected_items.actor_items_keep(obj:section_name()) or protected_items.is_no_offline_alife_npc(obj:section_name()) then return end
	
	if not o then
		-- для ускорения получаем все значения 1 раз
		o = {}
		o.id = obj.id
		o.parent_id = obj.parent_id
		o.clsid = obj:clsid()
		o.name = obj:name()
		o.section = obj:section_name()
		o.story_id = obj:story_id()
		o.level = object_level(obj)
		o.level_name = ai:level_name(o.level)
	end
	
	if not off_npcs[o.level_name] then off_npcs[o.level_name]={monsters={},stalkers={},weapons={},artefacts={},inv_boxes={},storages={}} end

	-- заполнение таблиц
	if iAmMonster[o.clsid] and obj:alive() and o.story_id == story_ids.INVALID_STORY_ID then
		local flags = get_flags(o.id)
		if flags == 0 or flags == 2 then --Уберем тех, у кого on_hit есть.
			table.insert(off_npcs[o.level_name].monsters, {id = o.id, name = o.name})
		end
	elseif iAmStalker[o.clsid] and obj:alive() and o.story_id == story_ids.INVALID_STORY_ID then
		local flags = get_flags(o.id)
		if flags == 0 or flags == 2 then --Уберем тех, у кого on_hit есть.
			if obj:community()~="zombied" then
				table.insert(off_npcs[o.level_name].stalkers, {id = o.id, name = o.name})
			else
				table.insert(off_npcs[o.level_name].monsters, {id = o.id, name = o.name})
			end
		end
	elseif iAmWeapon[o.clsid] then
		if o.story_id == story_ids.INVALID_STORY_ID then
			--if o.parent_id then
				local p_obj = server_object(o.parent_id)
				if p_obj then
					if p_obj:clsid() == clsid.inventory_box then
						-- НПС "не видят" этого
						o.level_name = ""
					--[[ как такое может быть что родитель на другом уровне???
					else
						local p_map = object_level_name(p_obj)
						if p_map ~= o.level_name then
							if not off_npcs[p_map] then off_npcs[p_map]={monsters={},stalkers={},weapons={},artefacts={}, inv_boxes={},storages={}} end
							o.level_name = p_map
						end	
					--]]
					end
				end
			--end
			if o.level_name ~= "" then table.insert(off_npcs[o.level_name].weapons, {id = o.id, name = o.name}) end
		end
	elseif string.find(o.section,"^af_") then
		--if o.parent_id then
			local p_obj = server_object(o.parent_id)
			if p_obj then
				if p_obj:clsid() == clsid.inventory_box then
					-- НПС "не видят" этого
					o.level_name = ""
				--[[ как такое может быть что родитель на другом уровне???
				else
					local p_map = object_level_name(p_obj)
					if p_map ~= o.level_name then
						if not off_npcs[p_map] then off_npcs[p_map]={monsters={},stalkers={},weapons={},artefacts={}, inv_boxes={},storages={}} end
						o.level_name = p_map
					end
				--]]
				end
			end
		--end
		if o.level_name ~= "" then table.insert(off_npcs[o.level_name].artefacts, {id = o.id, name = o.name}) end
	elseif o.clsid == clsid.inventory_box and not box_is_protected(obj) then
			table.insert(off_npcs[o.level_name].inv_boxes, {id = o.id, name = o.name})
	elseif o.section == "m_inventory_box" 
		and not safe_StealManager.GetStealManagerClass():IsStolen(o.id) 
		and safe_StealManager.GetStealManagerClass():AllowToSteal(o.id)
	then
		table.insert(off_npcs[o.level_name].storages, {id = o.id, name = o.name})
	end -- заполнение таблиц
		
	if o.story_id == story_ids.INVALID_STORY_ID and not iAmMonster[o.clsid] and not iAmStalker[o.clsid] then
		local zz = server_object(o.parent_id)
		if zz then
			if not items[o.parent_id] then items[o.parent_id] = {} end

			table.insert(items[o.parent_id], {id = o.id, name = o.name})
			gps_habar.insert_item(o.parent_id, obj) -- корректируем хабар в помеченных тайниках
		end
	end
end

--строим таблицу неписей, монстров и оружия
function build_tables()
	-- Почистим таблицу
--	off_npcs={}	
--	local obj
--	for a=1,65534 do
--		obj = server_object(a)
--		add_fresh_meat(obj)
--	end

	rel_enemy,rel_friend = utils.cfg_get_number(config, "game_relations", "goodwill_enemy", nil, false, -1000), utils.cfg_get_number(config, "game_relations", "goodwill_friend", nil, false, 1000)
	local s_comm_list = utils.cfg_get_string(config, "game_relations", "communities", nil, false, "", "")
	local comm_list = {}
	local s_value = string.explode(s_comm_list, ",", true)
	for a=1, #s_value, 2 do
		local s_comm = s_value[a]
		table.insert(comm_list, s_comm)
	end
  
	local tmp={}
	config:iterate_lines("communities_relations", function(result, id, value)
		relation_matrix[id]={}
		table.insert(tmp, id)
	end)
	
	for a=1,#tmp do
		local value = utils.cfg_get_string(config, "communities_relations", tmp[a], nil, false, "", "")
		local idx = tmp[a]
		local m_value = string.explode(value, ",", true)
		for i=1, #m_value do
			local idx2 = comm_list[i]
			local v = m_value[i]
			if relation_matrix[idx] and idx2~=nil and v ~= nil then
				relation_matrix[idx][idx2]=tonumber(v)
			end
		end
	end
	
	sell_table = {}
	local sini = ini_file("trade\\generic.ltx")
	local cfg_sell = utils.cfg_get_string(sini, "trader", "sell_condition", nil, false, "", "")
	sell_table = sini:key_true(cfg_sell)

	sini = ini_file("misc\\death_manager\\generic.ltx")
    --' Заполняем таблицу зависимостей
	item_dependence = {}
	local vvv
	sini:iterate_lines("item_dependence", function(result, id, value)
		item_dependence[id] = {}
		vvv = value:parse_names()
		for k,v in pairs(vvv) do
			item_dependence[id][v] = true
		end
	end)
	
 	--' Квестовые предметы, которые нельзя продавать
	always_keep_item = sini:key_true("keep_items")
end

function update_trade()
	local obj
	for a=1,65534 do
		obj = server_object(a)
		if obj then
			process_trade(obj)
		end
	end
end

function update_tables(level)
	off_npcs[level]={monsters={},stalkers={},weapons={},artefacts={}, inv_boxes={},storages={}}
	local obj, p_obj
	for a=1,65534 do
		obj = server_object(a)
		if obj and graph:valid_vertex_id(obj.m_game_vertex_id) then
			if object_level_name(obj) == level then
				add_fresh_meat(obj)
			elseif obj.parent_id then
				p_obj = server_object(obj.parent_id)
				if p_obj and object_level_name(p_obj) == level then
					add_fresh_meat(obj)
				end
			end
		end
	end	
end

--генерируем оффлайн события
function generate(map_name)
	local lname 
	if map_name then
		lname=map_name
	else
		lname = table.random(maps)
	end
--	update_tables(lname)
	local st = 0
	amk.oau_reason="cn generate"
	if off_npcs[lname] then st = #off_npcs[lname].stalkers end
	if st>0 then
		--log("need run offline life")
		for search = 1,search_intensivity do
			local rnd = 3 --math.random(st)
			if off_npcs[lname].stalkers[rnd] then 
				local victim = server_object(off_npcs[lname].stalkers[rnd].id)
				if victim and not victim.online and victim.health and victim.can_switch_online and victim:health()>0 and victim:can_switch_online() and victim:name() == off_npcs[lname].stalkers[rnd].name then
					local vdata = collect_info(victim,lname)
					vdata.monsters={}
					if #vdata.enemies>0 then
						--есть вражина - воюем
						--log("%s on_enemies_found",victim:name())
						on_enemies_found(victim, vdata)
						break
					elseif #vdata.monsters>0 then
						--есть монстрятина - видели, слышали, убили, сдохли...
						--log("%s on_monsters_found",victim:name())
						on_monsters_found(victim, vdata)
						break
					elseif #vdata.storages>0 then
						--есть нычки
						--log("%s on_storages_found",victim:name())
						for i=1, #vdata.storages do
							safe_StealManager.GetStealManagerClass():StealStorage(victim,vdata.storages[i].id)
						end
						break
					elseif #vdata.corpses.stalkers>0 then
						--есть труп сталкера
						--log("%s on_npc_corpses_found",victim:name())
						on_npc_corpses_found(victim, vdata)
						break
					elseif #vdata.corpses.monsters>0 then
						--есть труп монстра
						--log("%s on_monster_corpses_found",victim:name())
						on_monster_corpses_found(victim, vdata)
						break
					elseif #vdata.weapons.seen>0 then
						--есть бесхозное оружие
						--log("%s on_weapons_found",victim:name())
						on_weapons_found(victim, vdata)
						break
					elseif #vdata.artefacts>0 then
						--есть арты
						--log("%s on_artifacts_found",victim:name())
						on_artifacts_found(victim, vdata)
						break
					elseif #vdata.inv_boxes>0 then
						--есть контейнеры. Надо обыскать.
						--log("%s on_inv_boxes_found",victim:name())
						on_inv_boxes_found(victim, vdata)
						break
					elseif items[victim.id] and #items[victim.id] > 0 then
						--попробуем продать всякого
						--log("%s process_trade",victim:name())
						process_trade(victim)
						break
					end
				end
			end
		end
	end
end

--собираем инфу о неписе
function collect_info(victim,map)
	local vdata = {}
	vdata.rank = victim:rank() --ранг
	vdata.health = victim:health()  --здоровье
	vdata.community = victim:community()  --группировка
	
	--пытаемся определить пушку
	local wp = #off_npcs[map].weapons
	--условная огневая мощь
	vdata.fire_power = 0
	
	vdata.weapons={own={},seen={}}
	-- если есть пушки в карманах, выбираем лучшую (по условной мощности)
	if wp>0 then
		for w=1,wp do
			if off_npcs[map].weapons[w] then
				local www = server_object(off_npcs[map].weapons[w].id)
				if www and www:name()==off_npcs[map].weapons[w].name then
					if www.parent_id == victim.id then
						table.insert(vdata.weapons.own, {id = www.id, name = www:name()})
						local fp = get_weapon_firepower(www)
						if vdata.fire_power<fp then vdata.fire_power=fp end
					elseif www:can_switch_online() and victim.position:distance_to(www.position)<look_radius and sobj_is_far(www, to_actor) then
						--if www.parent_id==nil or www.parent_id==65535 or (server_object(www.parent_id) and server_object(www.parent_id):section_name()=="inventory_box") then
						-- ОП-2: Фикс пропадания стволов из нычки. Стволы в нычке больше не видимы для неписей.
						--if www.parent_id==nil or www.parent_id==65535 or (server_object(www.parent_id) and server_object(www.parent_id):clsid() == clsid.inventory_box) then
						if www.parent_id==nil or www.parent_id==65535 then
							table.insert(vdata.weapons.seen, {id = www.id, name = www:name()})
						end
					end
				end
			end
		end
	end
	
	--составляем списки друзей и врагов в зоне "видимости"
	-- Для тех, у кого смарт в фильтрах - не собираем врагов
	-- Для остальных - не учитываем врагов из смартов
	local npc_peaceful = npc_smart_is_peaceful(victim)
	
	vdata.friends={}
	vdata.enemies={}
	vdata.corpses={monsters={},stalkers={}}
	if #off_npcs[map].stalkers>0 then
		for a=1,#off_npcs[map].stalkers do
			if off_npcs[map].stalkers[a] then
				local opponent = server_object(off_npcs[map].stalkers[a].id)
				if opponent and opponent.id~=victim.id and opponent.health and opponent.can_switch_online and opponent:can_switch_online() and opponent:name() == off_npcs[map].stalkers[a].name  then
					if victim.position:distance_to(opponent.position)<look_radius then
						if opponent:health()>0 then
							local rel = relation_check(victim,opponent)
							if rel>=rel_friend then
								table.insert(vdata.friends, {id = opponent.id, name = opponent:name()})
							elseif rel<=rel_enemy then
								if npc_peaceful == false and npc_smart_is_peaceful(opponent) == false then
									table.insert(vdata.enemies, {id = opponent.id, name = opponent:name()})
								end
							end
						else
							if (sobj_is_far(opponent, to_actor)) then
								table.insert(vdata.corpses.stalkers, {id = opponent.id, name = opponent:name()})
							end
						end
					end
				end
			end
		end
	end
	
	--составляем список монстряков в зоне "видимости"
	vdata.monsters={}
	if off_npcs[map].monsters then
		if #off_npcs[map].monsters>0 then
			for a=1,#off_npcs[map].monsters do
				if off_npcs[map].monsters[a] then
					local monster = server_object(off_npcs[map].monsters[a].id)
					if monster and monster.health and monster.can_switch_online and monster:can_switch_online() and monster:name() == off_npcs[map].monsters[a].name and victim.position:distance_to(monster.position)<look_radius then
						if monster:health()>0 then
							table.insert(vdata.monsters, {id = monster.id, name = monster:name()})
						else
							if (sobj_is_far(monster, to_actor)) then
								table.insert(vdata.corpses.monsters, {id = monster.id, name = monster:name()})
							end
						end
					end
				end
			end
		end
	end
	
	--составляем список артов в зоне "видимости"
	vdata.artefacts={}
	if off_npcs[map].artefacts then
		if #off_npcs[map].artefacts>0 then
			for a=1,#off_npcs[map].artefacts do
				if off_npcs[map].artefacts[a] then
					local artefact = server_object(off_npcs[map].artefacts[a].id)
					if (artefact and artefact.can_switch_online and artefact:can_switch_online() and artefact:name() == off_npcs[map].artefacts[a].name and victim.position:distance_to(artefact.position)<look_radius and sobj_is_far(artefact, to_actor)) then
						--if artefact.parent_id==nil or artefact.parent_id==65535 or (server_object(artefact.parent_id) and (server_object(artefact.parent_id):section_name()=="inventory_box" or (server_object(artefact.parent_id):clsid()>172 and server_object(artefact.parent_id):clsid()<180))) then
						--if artefact.parent_id==nil or artefact.parent_id==65535 or (server_object(artefact.parent_id) and (server_object(artefact.parent_id):clsid() == clsid.inventory_box or (server_object(artefact.parent_id):clsid()>172 and server_object(artefact.parent_id):clsid()<180))) then
						if artefact.parent_id==nil or artefact.parent_id==65535 or (server_object(artefact.parent_id) and (server_object(artefact.parent_id):clsid() == clsid.inventory_box or amk_anoms.is_anomaly(server_object(artefact.parent_id):clsid()))) then
							table.insert(vdata.artefacts, {id = artefact.id, name = artefact:name()})
						end
					end
				end
			end
		end
	end
	--составляем список хранилищ в зоне "видимости"
	vdata.storages={}
	if off_npcs[map].storages then
		if #off_npcs[map].storages>0 then
			for a=1,#off_npcs[map].storages do
				local storageObj = server_object(off_npcs[map].storages[a].id)
				if (storageObj and storageObj:name() == off_npcs[map].storages[a].name) then
					local dist=victim.position:distance_to(storageObj.position)
					if dist<=look_radius_box and sobj_is_far(storageObj, to_actor) then
						local zdist=dist/100
						if math.random()>zdist then
							table.insert(vdata.storages, {id = storageObj.id, name = storageObj:name()})
						end
					end					
				end
			end
		end
	end
	--составляем список контейнеров в зоне "видимости"
	vdata.inv_boxes={}
	if off_npcs[map].inv_boxes then
		if #off_npcs[map].inv_boxes>0 then
			for a=1,#off_npcs[map].inv_boxes do
				if off_npcs[map].inv_boxes[a] then
					local inv_box = server_object(off_npcs[map].inv_boxes[a].id)
					if (inv_box and inv_box.can_switch_online and inv_box:can_switch_online() and inv_box:name() == off_npcs[map].inv_boxes[a].name and victim.position:distance_to(inv_box.position)<=look_radius_box and sobj_is_far(inv_box, to_actor)) then
						local zdist = victim.position:distance_to(inv_box.position)/100
						if math.random() > zdist then
							if inv_box.parent_id==nil or inv_box.parent_id==65535 then
								table.insert(vdata.inv_boxes, {id = inv_box.id, name = inv_box:name()})
							end
						end
					end
				end
			end
		end
	end
	return vdata
end

-- получаем отношение группировки к неписю, в оффлайне фактически равно личным отношениям неписей
function relation_check(victim,opponent)
	if relation_matrix[opponent:community()] and relation_matrix[opponent:community()][victim:community()] then
		return relation_matrix[opponent:community()][victim:community()]
	else
		return 0
	end
end

-- Вокруг враги! Что же делать..
function on_enemies_found(victim, vdata)
	if (victim == nil or vdata == nil) then return end
	local obj, v_obj
	local team_A = {}
	local team_B = {}
	-- Собираем weapons
	-- Учитываем rank, weapon, distance...
	local wpn = get_npc_weapon(victim)
	local rank = victim:rank()
	local health = victim:health()
	local firepower = get_weapon_firepower(wpn)
	local player = {player = victim, weapon = wpn, rank = rank, health = health, firepower = firepower, flags = get_flags(victim.id)}
	table.insert(team_A, player)
	if (vdata.friends and #vdata.friends > 0) then
		for i=1, #vdata.friends do
			v_obj = vdata.friends[i]
			if v_obj then
				obj = server_object(v_obj.id)
				if (obj and obj:name()==v_obj.name) then
					wpn = get_npc_weapon(obj)
					rank = obj:rank()
					health = obj:health()
					firepower = get_weapon_firepower(wpn)
					player = {player = obj, weapon = wpn, rank = rank, health = health, firepower = firepower, flags = get_flags(obj.id)}
					table.insert(team_A, player)
				end
			end
		end
	end
	for i=1, #vdata.enemies do
		v_obj = vdata.enemies[i]
		obj = server_object(v_obj.id)
		if (obj and obj:name() == v_obj.name) then
			wpn = get_npc_weapon(obj)
			if (wpn == nil) then
				list_npc_items(obj)
			end
			rank = obj:rank()
			health = obj:health()
			firepower = get_weapon_firepower(wpn)
			player = {player = obj, weapon = wpn, rank = rank, health = health, firepower = firepower, flags = get_flags(obj.id)}
			table.insert(team_B, player)
		end
	end
	local distances = {}
	for a=1, #team_A do
		local from = team_A[a].player
		distances[from.id] = {}
		for b=1, #team_B do
			local to = team_B[b].player
			distances[to.id] = {}
			if (from and to and from.id and to.id) then
				local dist = math.floor(from.position:distance_to(to.position))
				local fp_A = math.floor(team_A[a].firepower / (dist / dist_coeff))
				local fp_B = math.floor(team_B[b].firepower / (dist / dist_coeff))
				local item = {distance = dist, fpA = fp_A, fpB = fp_B}
				distances[from.id][to.id] = {distance = dist, fp = fp_A}
				distances[to.id][from.id] = {distance = dist, fp = fp_B}
			end
		end
	end
	-- Берем тех, у кого самый высокий rank и мин. distance
	table.sort(team_A, function(a,b) return a.rank > b.rank end)
	table.sort(team_B, function(a,b) return a.rank > b.rank end)
	-- 10 раундов
	local size_A = #team_A
	local size_B = #team_B
	local died_A = 0
	local died_B = 0
	for i=1, max_rounds do
		if (#team_A >0 and #team_B > 0) then
			local index = #team_A
			local attacker
			local defender 
			local attack_info 
			local rank_hit_chance
			local distance_hit_chance
			local hit_chance			
			if (#team_B > index) then index = #team_B end
			for j = 1, index do
				attacker = team_A[j]
				defender = table.random(team_B)
				if (attacker and defender and attacker.player and defender.player and attacker.health>0 and defender.health>0 and distances[attacker.player.id][defender.player.id]) then
					attack_info = distances[attacker.player.id][defender.player.id]
					-- Попал или нет? Зависит от: расстояния, рангов
					-- master to novice - 30% max
					-- 100 метров - 33% 10 метров - 100% 1 метр - 115% Каждый метр - минус 1.5% попасть.
					rank_hit_chance = math.floor((attacker.rank - defender.rank) / 50)
					distance_hit_chance = 100 - math.floor((attack_info.distance) / 1.5)					
					hit_chance = distance_hit_chance + rank_hit_chance
					if ((math.random() * 100) < hit_chance) then
						-- Попал таки, гад. Посмотрим, как сильно.
						if (attack_info.fp >= base_fp) then
							-- Все, убил.
							defender.health = 0
						else
							defender.health = defender.health - (attack_info.fp / base_fp)
							if (defender.health < 0 ) then defender.health = 0 end							
						end
						if (defender.health <= 0) then
							if (defender.flags >= 2) then
								defender.health = health_wound
							else
								-- Если сталкер - дадим опыт.
								if attacker.player and iAmStalker[attacker.player:clsid()] and attacker.player.community then
									local m_comm  = attacker.player:community()
									if (m_comm == "stalker" or m_comm == "dolg" or m_comm == "freedom") then
										-- Будет теперь опытным.
										local coeff = 1
										if (defender.rank < attacker.rank) then coeff = 0.5 end
										if (defender.rank > attacker.rank) then coeff = 2 end
										attacker.player:set_rank(attacker.player:rank() + math.floor(rate_kill_base * coeff))
									end
								end
								news_main.on_offline_death(defender.player, attacker.player, attacker.weapon)
								-- Заберем вещички с трупа
								local itA, v_itA
								local l_objA
								if (items[defender.player.id] and #items[defender.player.id] > 0) then
									for a=1,#items[defender.player.id] do
										v_itA = items[defender.player.id][a]
										if (v_itA) then
											itA = server_object(v_itA.id)
											if (itA and itA:name()==v_itA.name and itA.parent_id == defender.player.id) then
												l_objA = pick_item(attacker.player, itA)
											else
												if(itA) then
													local mm = itA.parent_id
													if mm == nil then mm = "nil" end
												end
											end	
										end
									end
								end
								process_trade(attacker.player)
							end
						end
					else
					end
				end
				-- team_B - защищается
				if (team_B[j] ~= nil) then
					attacker = team_B[j]
					defender = table.random(team_A)
					if (attacker and defender and attacker.player and defender.player and attacker.health>0 and defender.health>0 and distances[attacker.player.id][defender.player.id]) then
						attack_info = distances[attacker.player.id][defender.player.id]
						-- Попал или нет? Зависит от: расстояния, рангов
						-- master to novice - 30% max
						-- 100 метров - 33% 10 метров - 100% 1 метр - 115% Каждый метр - минус 1.5% попасть.
						rank_hit_chance = math.floor((attacker.rank - defender.rank) / 50)
						distance_hit_chance = 100 - math.floor((attack_info.distance) / 1.5)					
						hit_chance = distance_hit_chance + rank_hit_chance
						if math.random() * 100 < hit_chance then
							-- Попал таки, гад. Посмотрим, как сильно.
							if attack_info.fp >= base_fp then
								-- Все, убил.
								defender.health = 0
							else
								defender.health = defender.health - (attack_info.fp / base_fp)
								if (defender.health < 0 ) then defender.health = 0 end
							end
							if (defender.health <= 0) then
								if (defender.flags >= 2) then
									defender.health = health_wound
								else								
									-- Если сталкер - дадим опыт.
									if attacker.player and iAmStalker[attacker.player:clsid()] and attacker.player.community then
										local m_comm  = attacker.player:community()
										if (m_comm == "stalker" or m_comm == "dolg" or m_comm == "freedom") then
											-- Будет теперь опытным.
											local coeff = 1
											if (defender.rank < attacker.rank) then coeff = 0.5 end
											if (defender.rank > attacker.rank) then coeff = 2 end
											attacker.player:set_rank(attacker.player:rank() + math.floor(rate_kill_base * coeff))							
										end
									end
									news_main.on_offline_death(defender.player, attacker.player, attacker.weapon)
									-- Заберем вещички с трупа
									local itB, v_itB
									local l_objB
									if (items[defender.player.id] and #items[defender.player.id] > 0) then
										for a=1,#items[defender.player.id] do
											v_itB = items[defender.player.id][a]
											if (v_itB) then
												itB = server_object(v_itB.id)
												if (itB and itB:name() == v_itB.name and itB.parent_id == defender.player.id) then
													l_objB = pick_item(attacker.player, itB)
												else
													if(itB) then
														local mm = itB.parent_id
														if mm == nil then mm = "nil" end
													end
												end
											end
										end
									end
									process_trade(attacker.player)
								end
							end
						else
						end
					end
				end
			end
		else
			-- Теперь и событие можно сформировать для новостей
			break
		end
		-- Почистим таблицы от трупов
		for kk, vv in pairs(team_A) do
			if (vv.health <=0) then
				set_npc_health(vv.player, 0)
				table.remove(team_A, kk)
				died_A = died_A + 1
			elseif (vv.health <= health_wound and vv.health > 0) then
				set_npc_health(vv.player, health_wound_set)
				news_main.on_offline_wound(vv.player)
				table.remove(team_A, kk)
			end
		end
		for kk, vv in pairs(team_B) do
			if (vv.health <=0) then
				set_npc_health(vv.player, 0)
				table.remove(team_B, kk)
				died_B = died_B + 1
			elseif (vv.health <= health_wound and vv.health > 0) then
				set_npc_health(vv.player, health_wound_set)
				news_main.on_offline_wound(vv.player)
				table.remove(team_B, kk)
			end
		end		
	end
end

-- Вокруг монстры! Что же делать..
function on_monsters_found(victim, vdata)
	amk.oau_reason="on_monsters_found"
	if (victim == nil or vdata == nil) then return end
	-- Собираем комманды.
	local obj, v_obj
	local team_A = {}
	local team_B = {}
	local wpn = get_npc_weapon(victim)
	local rank = victim:rank()
	local health = victim:health()
	local firepower = get_weapon_firepower(wpn)
	local player = {player = victim, weapon = wpn, rank = rank, health = health, firepower = firepower, flags = get_flags(victim.id)}
	table.insert(team_A, player)
	if (vdata.friends and #vdata.friends > 0) then
		for i=1, #vdata.friends do
			v_obj = vdata.friends[i]
			obj = server_object(v_obj.id)
			if (obj and obj:name()==v_obj.name) then
				wpn = get_npc_weapon(obj)
				rank = obj:rank()
				health = obj:health()
				firepower = get_weapon_firepower(wpn)
				player = {player = obj, weapon = wpn, rank = rank, health = health, firepower = firepower, flags = get_flags(obj.id)}
				table.insert(team_A, player)
			end
		end
	end
	local params
	for i=1, #vdata.monsters do
		v_obj = vdata.monsters[i]
		obj = server_object(v_obj.id)
		if (obj and obj:name() == v_obj.name) then
			params = get_monster_params(obj)
			if (params) then
				rank = obj:rank()
				health = obj:health()
				firepower = params.attack * base_fp
				player = {player = obj, speed = params.speed, attack_dist = params.dist, immunity = params.immunity, rank = rank, health = health, firepower = firepower, flags = get_flags(obj.id) }
				table.insert(team_B, player)
			else
			end
		end
	end
	local distances = {}
	for a=1, #team_A do
		local from = team_A[a].player
		distances[from.id] = {}
		for b=1, #team_B do
			local to = team_B[b].player
			distances[to.id] = {}
			if (from and to and from.id and to.id) then
				local dist = math.floor(from.position:distance_to(to.position))
				local fp_A = math.floor(team_A[a].firepower / (dist / dist_coeff))
				local fp_B = math.floor(team_B[b].firepower)
				local item = {distance = dist, fpA = fp_A, fpB = fp_B}
				distances[from.id][to.id] = {distance = dist, fp = fp_A}
				distances[to.id][from.id] = {distance = dist, fp = fp_B}
			end
		end
	end
	-- Берем тех, у кого самый высокий rank и мин. distance
	table.sort(team_A, function(a,b) return a.rank > b.rank end)
	table.sort(team_B, function(a,b) return a.rank > b.rank end)
	-- 10 раундов
	local size_A = #team_A
	local size_B = #team_B
	local died_A = 0
	local died_B = 0
	for i=1, max_rounds do
		if (#team_A >0 and #team_B > 0) then
			local index = #team_A
			local attacker
			local defender
			local attack_info
			local rank_hit_chance
			local distance_hit_chance
			local hit_chance
			if (#team_B > index) then index = #team_B end
			for j = 1, index do
				attacker = team_A[j]
				defender = table.random(team_B)
				if (attacker and defender and attacker.player and defender.player and attacker.health>0 and defender.health>0 and distances[attacker.player.id][defender.player.id]) then
					attack_info = distances[attacker.player.id][defender.player.id]
					-- Попал или нет? Зависит от: расстояния, рангов
					rank_hit_chance = math.floor((attacker.rank - defender.rank) / 50)
					local dii = math.floor(attack_info.distance - defender.speed * i * 5)
					if (dii <=8) then dii = 45 end -- Вблизи еще и фиг попадешь...
					distance_hit_chance = 100 - math.floor(dii / 1.5)					
					hit_chance = distance_hit_chance + rank_hit_chance
					if ((math.random() * 100) < hit_chance) then
						-- Попал таки, гад. Посмотрим, как сильно.
						if ( math.floor(attack_info.fp * defender.immunity) >= base_fp) then
							-- Все, убил.
							defender.health = 0
						else
							defender.health = defender.health - (attack_info.fp / base_fp) * defender.immunity
							if (defender.health < 0 ) then defender.health = 0 end							
						end
						if (defender.health <= 0) then
							if defender.flags >= 2 then
								defender.health = health_wound
							else
								-- Если сталкер - дадим опыт.
								if attacker.player and iAmStalker[attacker.player:clsid()] and attacker.player.community then
									local m_comm  = attacker.player:community()
									if (m_comm == "stalker" or m_comm == "dolg" or m_comm == "freedom") then
										-- Будет теперь опытным.
										local coeff = 1
										if (defender.rank < attacker.rank) then coeff = 0.5 end
										if (defender.rank > attacker.rank) then coeff = 2 end
										attacker.player:set_rank(attacker.player:rank() + math.floor(rate_kill_base * coeff))
									end
								end
								news_main.on_offline_death(defender.player, attacker.player, attacker.weapon)
								-- Заберем вещички с трупа
								local itA, v_itA
								local l_objA
								if (items[defender.player.id] and #items[defender.player.id] > 0) then
									for a=1,#items[defender.player.id] do
										v_itA = items[defender.player.id][a]
										if (v_itA) then
											itA = server_object(v_itA.id)
											if (itA and itA:name()==v_itA.name and itA.parent_id == defender.player.id) then
												l_objA = pick_item(attacker.player, itA)
											else
												if(itA) then
													local mm = itA.parent_id
													if mm == nil then mm = "nil" end
												end											
											end			
										end
									end
								end
								process_trade(attacker.player)
							end
						end
					else
					end
				end
				-- team_B - защищается
				if (team_B[j] ~= nil) then
					attacker = team_B[j]
					defender = table.random(team_A)
					if (attacker and defender and attacker.player and defender.player and attacker.health>0 and defender.health>0 and distances[attacker.player.id][defender.player.id]) then
						attack_info = distances[attacker.player.id][defender.player.id]
						-- Для начала неплохо бы узнать, добежал ли монстрик до дистанции атаки.
						if (attack_info.distance - attacker.speed * i * 5 < attacker.attack_dist) then
							rank_hit_chance = math.floor((attacker.rank - defender.rank) / 50)
							distance_hit_chance = 100
							hit_chance = distance_hit_chance + rank_hit_chance
							if math.random() * 100 < hit_chance then
								-- Попал таки, гад. Посмотрим, как сильно.
								if attack_info.fp >= base_fp then
									-- Все, убил.
									defender.health = 0
								else
									defender.health = defender.health - (attack_info.fp / base_fp)
									if (defender.health < 0 ) then defender.health = 0 end
								end
								if (defender.health == 0) then
									if defender.flags >= 2 then
										defender.health = health_wound
									else
										local coeff = 1
										if (defender.rank < attacker.rank) then coeff = 0.5 end
										if (defender.rank > attacker.rank) then coeff = 2 end
										news_main.on_offline_death(defender.player, attacker.player, nil)
										-- Забирать вещички с трупа не будем.
									end
								end
							else
							end
						else
						end
					end
				end
			end
		else
			-- Теперь и событие можно сформировать для новостей
			break
		end
		-- Почистим таблицы от трупов
		for kk, vv in pairs(team_A) do
			if (vv.health <=0) then
				set_npc_health(vv.player, 0)
				table.remove(team_A, kk)
				died_A = died_A + 1
			elseif (vv.health <= health_wound and vv.health > 0) then
				set_npc_health(vv.player, health_wound_set)
				news_main.on_offline_wound(vv.player)
				table.remove(team_A, kk)
			end
		end
		for kk, vv in pairs(team_B) do
			if (vv.health <=0) then
				set_npc_health(vv.player, 0)
				table.remove(team_B, kk)
				died_B = died_B + 1
			elseif (vv.health <= health_wound and vv.health > 0) then
				set_npc_health(vv.player, health_wound_set)
				news_main.on_offline_wound(vv.player)
				table.remove(team_B, kk)
			end
		end		
	end	
end

-- О, трупик. Щас шмонать будем.
function on_npc_corpses_found(victim, vdata)
	if (victim == nil or vdata == nil) then return end
	if (vdata.corpses == nil) then return end
	if (vdata.corpses.stalkers == nil) then return end
	local obj, v_obj
	local id
	local v_id = victim.id
	for i=1, #vdata.corpses.stalkers do
		v_obj = vdata.corpses.stalkers[i]
		local corpse = server_object(v_obj.id)
		if (corpse and corpse:name() == v_obj.name) then
			news_main.on_offline_corpse_found(victim, corpse)
			id = corpse.id
			if (id and items[id]) then
				for a=1, #items[id] do
					local v_itA = items[id][a]
					if (v_itA) then
						local itA = server_object(v_itA.id)
						if (itA and itA:name() == v_itA.name and itA.parent_id == id) then
							local l_objA = pick_item(victim, itA)
						end			
					end
				end
			end
		end
	end
	process_trade(victim)
end

-- О, трупик монстра. Будем шмонать?
function on_monster_corpses_found(victim, vdata)
	if (victim == nil or vdata == nil) then return end
	if (vdata.corpses == nil) then return end
	if (vdata.corpses.monsters == nil) then return end
	local obj, v_obj
	local object
	local id
	local v_id = victim.id
	for i=1, #vdata.corpses.monsters do
		v_obj = vdata.corpses.monsters[i]
		local corpse = server_object(v_obj.id)
		if (corpse and corpse:name() == v_obj.name) then
			news_main.on_offline_corpse_found(victim, corpse)		
			id = corpse.id
			if (id and items[id]) then
				for a=1, #items[id] do
					local v_itA = items[id][a]
					if (v_itA) then
						local itA = server_object(v_itA.id)
						if (itA and itA:name() == v_itA.name and itA.parent_id == id) then
							local l_objA = pick_item(victim, itA)
						end			
					end
				end
			end
		end
	end
	process_trade(victim)
end

-- Хорошая пушка - не помешает.
function on_weapons_found(victim, vdata)
	if (victim == nil or vdata == nil) then return end
	local obj, v_obj
	local object
	local v_id = victim.id
	for i=1, #vdata.weapons.seen do
		v_obj = vdata.weapons.seen[i]
		if (v_obj) then
			object = server_object(v_obj.id)
			if (object and object:name() == v_obj.name) then
				obj = pick_item(victim, object)
			end
		end
	end
	process_trade(victim)
end

-- Артефакт
function on_artifacts_found(victim, vdata)
	if (victim == nil or vdata == nil) then return end
	local obj, v_obj
	local object
	local v_id = victim.id
	local b_stalker = false
	-- Если сталкер - дадим опыт.
	if victim and iAmStalker[victim:clsid()] and victim.community then
		local m_comm  = victim:community()
		if (m_comm == "stalker" or m_comm == "dolg" or m_comm == "freedom") then
			b_stalker = true
		end
	end
	for i=1, #vdata.artefacts do
		v_obj = vdata.artefacts[i]
		if (v_obj) then
			object = server_object(v_obj.id)
			if (object and object:name() == v_obj.name) then
				obj = pick_item(victim, object)
				if (obj) then
					if (b_stalker == true) then
						victim:set_rank(victim:rank() + rate_art_found)
					end
				end
			end
		end
	end
	process_trade(victim)
end

-- О, нычка.
-- проверим, а сможет ли непись долезть до  тайника.
-- если есть аномалии в радиусе 20м, меньше шансов или если тайник высоко, тоже не факт что долезет.
function inv_box_is_avail(victim, box)
	if (victim == nil or box == nil or box.id == 0) then return false end
	-- отсекаем сюжетные тайники
	if box:section_name() ~= "m_inventory_box" then return false end
	
	local n_rnd
	if victim.position and box.position then 
		n_rnd = math.random(0, 1)
		if math.abs(box.position.y - victim.position.y) > n_rnd then
			return false
		end 
	end

	local anom_list=amk_anoms.get_anomaly_list_for_pos(box.position,200) 
	local n_anoms = #anom_list
	n_rnd = math.random(1, 2)
	if n_rnd < n_anoms * 200 then -- смотрим вероятность. Чем больше аномалий, тем меньше шансов. При 5 - точно до ящика не доберется
		return false
	end
	
	return true
end

function on_inv_boxes_found(victim, vdata)
	if (victim == nil or vdata == nil) then return end
	local obj, v_obj
	local object
	local v_id = victim.id
	local b_stalker = false
	-- Если сталкер - дадим опыт.
	if victim and iAmStalker[victim:clsid()] and victim.community then
		local m_comm  = victim:community()
		if (m_comm == "stalker" or m_comm == "dolg" or m_comm == "freedom") then
			b_stalker = true
		end
	end
	for i=1, #vdata.inv_boxes do
		v_obj = vdata.inv_boxes[i]
		if (v_obj) then
			object = server_object(v_obj.id)
			if (object and object:name() == v_obj.name) then
				if inv_box_is_avail(victim, object) then  -- если нычка доступна - можно шмонать
					if items[v_obj.id] and #items[v_obj.id]>0 then
						for a=1,#items[v_obj.id] do
							local v_itA = items[v_obj.id][a]
							if (v_itA) then
								local itA = server_object(v_itA.id)
								if (itA and itA:name()==v_itA.name and itA.parent_id == v_obj.id) then
									-- Решим, подбираем или нет?
									local bTake = is_valuable(itA)
									if bTake then
										local l_objA = pick_item(victim, itA)
									end
								else
									if(itA) then
										local mm = itA.parent_id
										if mm == nil then mm = "nil" end
									end											
								end			
							end
						end					
					end
				end
			end
		end
		if (b_stalker == true) then
			victim:set_rank(victim:rank() + rate_art_found)
		end
	end
	process_trade(victim)
end

function pick_item(npc, obj)
	local new = nil
	if (npc and obj and db.actor and obj.id ~= db.actor:id()) then
		local section = obj:section_name()
		new = create(section, npc.position, npc.m_level_vertex_id, npc.m_game_vertex_id, npc.id)
		if (new) then
			if (new.parent_id) then
				if not items[new.parent_id] then items[new.parent_id] = {} end
				table.insert(items[new.parent_id], {id = new.id, name = new:name()})
				gps_habar.insert_item(new.parent_id, new) -- корректируем хабар в помеченных тайниках
			end
			if (obj.parent_id and items[obj.parent_id] and #items[obj.parent_id]>0) then
				for z=1, #items[obj.parent_id] do
					if (items[obj.parent_id][z] and items[obj.parent_id][z].id == obj.id) then
						gps_habar.remove_item(obj.parent_id, items[obj.parent_id][z]) -- корректируем хабар в помеченных тайниках
						table.remove(items[obj.parent_id], z)
						break
					end
				end
			end
			release(server_object(obj.id), true)
		end
	end
	return new
end

function get_npc_weapon(npc)
	local obj = nil
	local fp = 0
	if (npc) then
        if items[npc.id] ~= nil and items ~= nil and npc.id ~= nil then
            for k,v in pairs(items[npc.id]) do
				local wpn = server_object(v.id)
				if wpn and iAmWeapon[wpn:clsid()] and wpn:name() == v.name and wpn.parent_id == npc.id then
					local sect = wpn:section_name()
					local cur_fp = 0				
					local modes = rx_wmgr.read_wm_modes(npc:community(),ranks.get_obj_rank_name(npc),npc:section_name())
					local params = rx_wmgr.read_wpn_params(sect)
					if modes.mode1 == "1" then
						cur_fp = params.cst + modes.addcost
					elseif modes.mode1 == "2" then
						local kf = rx_wmgr.wm_modes.koeffs[modes.koeffs]
						cur_fp = (params.dmg*kf.dmg)+(params.rpm*kf.rpm)+(params.dst*kf.dst)+((100/params.dsp)*kf.dsp)
					elseif modes.mode1 == "3" then
						cur_fp = rx_wmgr.wm_modes.priors[modes.priors][sect] or 0
					end
					if cur_fp > fp then
						fp = cur_fp
						obj = wpn
					end			
				end
		     end
        end
	end
	return obj
end

function get_weapon_firepower(wpn)
	local result = 0
	if wpn and iAmWeapon[wpn:clsid()] then
		local sect = wpn:section_name()
		if wpn_fp[sect] then
			result = wpn_fp[sect]
		else
			if not (sect == "grenade_f1" or sect =="grenade_gd-05" or sect == "grenade_rgd5" or sect == "grenade_flash") then
				local priority = utils.cfg_get_number(config, sect, "ef_weapon_type", wpn, false, 1)
				local priority2 = utils.cfg_get_number(config, sect, "ef_main_weapon_type", wpn, false, 0)
				-- эти 4 параметра не сделаны
				local GetRPM = 0
				local GetDamage = 0
				local GetHandling = 0
				local GetAccuracy = 0
				--
				local fp = 1
			
				if priority>1 then
					if priority2>0 then
						priority = priority + priority2
					end
				end

				fp = math.ceil(priority * 1000 + GetAccuracy * 100 + GetRPM * 3 + GetDamage * 8) - 5000
				if GetHandling >= 99 then
					fp = fp + 1500
				end
				
				result = fp
				if wpn_fp[sect] == nil then
					wpn_fp[sect] = fp
				end
			end
		end
	end
	return result
end

function get_weapon_cost(weapon)
	local result = 0
	local sect = weapon:section_name()
	if (weapon and iAmWeapon[weapon:clsid()]) then
		result = utils.cfg_get_number(config, sect, "cost", weapon, false, 0)
	end
	return result
end

function get_item_cost(item)
	local result = 0
	if item and item.section_name then
		result = utils.cfg_get_number(config, item:section_name(), "cost", item, false, 0)
	end
	return result
end

function set_npc_health(obj, health)
	if (obj and health >=0 and health <=2) then
		if iAmMonster[obj:clsid()] or iAmStalker[obj:clsid()] then
			netpacket:modify(obj, "health", health, "upd.health", health)
		end
		if health == 0 then
			on_death(obj.id)
		end
	end
end

function list_npc_items(obj)
	if (obj) then
		--log("list_npc_items - "..obj:name()..":")
		local it
		local find = 0
		for a=1,65534 do
			it = server_object(a)
			if (it and it.parent_id == obj.id) then
				--log("list_npc_items - "..it:name().." "..it:section_name())
				if (iAmWeapon[it:clsid()]) then
					find = it.id
				end
			end			
		end
	end
end

--[[
	Уникальные предметы НЕ ПРОДАЕМ. Максимум - в новости.	
	Отсортировали оружие по firepower (можем еще ef_weapon_type добавить.)
	Оставили себе то, для которого есть патроны. (а) - wpn..ammo_class + item_dependence
	Оставили одно, которое лучше (а), но патронов нет (б) (%)
	Одно, которое лучше (а), но хуже (б) - в новости на продажу
	Остальное на продажу
	Патроны оставили только те, что подходят к (а), остальные на продажу
	Для вояк - только родной калаш надо бы... Не продавать вобще?
	Оставляем не более 2 аптечек и бинтов, антирада
	Оставляем 1-2 гранаты (%)
	Оставляем не более 1 шт: фонарик, рация, ПДА, бинокль, нож, детекторы
	Еда, водка - не более 1-2 шт (%)	
	Броники наверное продаем...
	Части монстров? Тоже продаем наверное, максимум 1-2 оставим.
]]
function process_trade(npc)
	local item_list = {}
	local sell_list = {}
	if npc and iAmStalker[npc:clsid()] and npc:alive() and npc.story_id~=nil and npc:story_id() == story_ids.INVALID_STORY_ID and items[npc.id] and #(items[npc.id])>0 and not protected_items.is_no_offline_alife_npc(npc:section_name()) then
		local m_comm = npc:community()
		local b_stalker = false		
		if (m_comm == "actor" or m_comm == "actor_dolg" or m_comm == "actor_freedom" or m_comm == "stalker" or m_comm == "dolg" or m_comm == "freedom") then
			if (npc.name and npc:name() ~= "agr_ratcatcher") then
				b_stalker = true
			end
		elseif m_comm == "zombied" then
			return
		end
			
		--Фильтруем квестовые items - always_keep_item, sell_table	
		-- В sell_table нихрена кроме партонов нет, незачем по ней проверять
		local obj, v_obj
		for ok,ov in pairs(items[npc.id]) do
			obj = server_object(ov.id)
			if obj and obj:name()==ov.name then
			--	if always_keep_item[obj:section_name()] or sell_table[obj:section_name()] == nil or protected_items.actor_items_keep(obj:section_name()) then
				if always_keep_item[obj:section_name()] or protected_items.actor_items_keep(obj:section_name()) then
					-- Это нам не надо.
				else
					table.insert(item_list, obj)
				end
			end
		end
		if item_list and #item_list > 0 then
			table.sort(item_list, function(a,b) return get_item_cost(a) > get_item_cost(b) end)		
			-- Выберем, что за оружие оставит себе NPC.
			local cnt_medkit = 0
			local cnt_antirad = 0
			local cnt_bandage = 0
			local cnt_grenade = 0
			local cnt_food = 0
			local cnt_drink = 0
			local cnt_torch = 0
			local cnt_pda = 0
			local cnt_radio = 0
			local cnt_guitar = 0
			local cnt_harmonica = 0
			local cnt_binocular = 0
			local cnt_knife = 0
			local cnt_arts = 0
			local cnt_detector = 0
			local cnt_addons = 0
			local cnt_mparts = 0
			
			local weapons = {}
			local ammo = {}
			for k,v in pairs(item_list) do			
				local sect = v:section_name()
				if iAmWeapon[v:clsid()] and not (sect == "grenade_f1" or sect =="grenade_gd-05" or sect == "grenade_rgd5" or sect == "grenade_flash" or sect == "wpn_knife") then
					local bOk = false
					if m_comm == "military" then
						if sect == "wpn_ak74" or sect =="wpn_ak74u" or sect =="wpn_abakan" or sect =="wpn_pm" or sect =="wpn_usp" or sect =="wpn_val" or sect =="wpn_walther" or sect =="wpn_svu" or sect =="wpn_sig550" or sect =="wpn_fn2000" or sect =="wpn_vintorez" or sect =="wpn_groza" then
							bOk = true
						end
					else
						bOk = true
					end
					if bOk == true then
						local ac = utils.cfg_get_string(config, sect, "ammo_class", v, false, "")
						if ac and ac ~= "" then
							local vvv = string.explode(ac, ",", true)
							local ammo_classes = {}
							for ak,av in pairs(vvv) do
								table.insert(ammo_classes, av)
							end
							table.insert(weapons, {obj = v, ammo = ammo_classes})
						else
							table.insert(weapons, {obj = v, ammo = nil})
						end
					end
				elseif string.find(sect, "^ammo_") then
					if ammo[sect] == nil then 
						ammo[sect] = 1
					else
						ammo[sect] = ammo[sect] + 1
--						if ammo[sect] > 2 then -- ОП-2: для стрельбы неписю хватает одной пачки
						if ammo[sect] > 1 then
							table.insert(sell_list, v)
						end
					end
				elseif string.find(sect, "^af_") then
					-- 3 самых хороших арта оставили себе (+здоровье), остальные на продажу (фильтруем булыжник)				
					if sect ~= "af_buliz" then
						cnt_arts = cnt_arts + 1
					end
					if cnt_arts > 3 then
						table.insert(sell_list, v)
					end
				elseif sect == "device_torch" then
					cnt_torch = cnt_torch + 1
					if cnt_torch > 1 then
						table.insert(sell_list, v)
					end
				elseif sect == "device_pda" then
					cnt_pda = cnt_pda + 1
					if cnt_pda > 1 then
						table.insert(sell_list, v)
					end
				elseif sect == "hand_radio" then
					cnt_radio = cnt_radio + 1
					if cnt_radio > 1 then
						table.insert(sell_list, v)
					end
				elseif sect == "harmonica_a" then
					cnt_harmonica = cnt_harmonica + 1
					if cnt_harmonica > 1 then
						table.insert(sell_list, v)
					end
				elseif sect == "guitar_a" then
					cnt_guitar = cnt_guitar + 1
					if cnt_guitar > 1 then
						table.insert(sell_list, v)
					end
				elseif sect == "wpn_binoc" or sect == "wpn_binoc_m1" or sect == "wpn_binoc_m2" then
					cnt_binocular = cnt_binocular + 1
					if cnt_binocular > 1 then
						table.insert(sell_list, v)
					end
				elseif sect == "wpn_knife" then
					cnt_knife = cnt_knife + 1
					if cnt_knife > 1 then
						table.insert(sell_list, v)
					end
				elseif sect == "medkit" or sect == "medkit_army" or sect == "medkit_scientic" then
					cnt_medkit = cnt_medkit + 1
					if cnt_medkit > 4 then
						table.insert(sell_list, v)
					end
				elseif sect == "antirad" then
					cnt_antirad = cnt_antirad + 1
					if cnt_antirad > 3 then
						table.insert(sell_list, v)
					end
				elseif sect == "bandage" then
					cnt_bandage = cnt_bandage + 1
					if cnt_bandage > 3 then
						table.insert(sell_list, v)
					end
				elseif sect == "grenade_f1" or sect =="grenade_gd-05" or sect == "grenade_rgd5" or sect == "grenade_flash" then
					cnt_grenade = cnt_grenade + 1
					if cnt_grenade > 2 then
						table.insert(sell_list, v)
					end
				elseif sect == "bread_a" or sect =="bread" or sect == "kolbasa" or sect == "kolbasa_a" or sect == "conserva" then
					cnt_food = cnt_food + 1
					if cnt_food > 4 then
						table.insert(sell_list, v)
					end
				elseif sect == "vodka_a" or sect =="vodka" or sect == "energy_drink" then
					cnt_drink = cnt_drink + 1
					if cnt_drink > 3 then
						table.insert(sell_list, v)
					end
				elseif sect == "detector_simple" or sect =="detector_advances" or sect == "detector_elite" then
					cnt_detector = cnt_detector + 1
					if cnt_detector > 1 then
						table.insert(sell_list, v)
					end
				elseif rx_addons.item_is_addon(v) then
					cnt_addons = cnt_addons + 1
					if cnt_addons > 2 then
						table.insert(sell_list, v)
					end
				elseif config:line_exist(sect, "monster_part") then
					cnt_mparts = cnt_mparts + 1
					if cnt_mparts > 2 then
						table.insert(sell_list, v)
					end
				end			
			end

			local modes = rx_wmgr.read_wm_modes(npc:community(),ranks.get_obj_rank_name(npc),npc:section_name())
			local weapons_types = {}
			for z,i in ipairs(modes.types) do
				weapons_types[i.t] = {}
			end
			for i,w in ipairs(weapons) do
				local sect = w.obj:section_name()				
				local params = rx_wmgr.read_wpn_params(sect)
				local prm = 0
				if modes.mode1 == "1" then
					prm = params.cst + modes.addcost
				elseif modes.mode1 == "2" then
					local kf = rx_wmgr.wm_modes.koeffs[modes.koeffs]
					prm = (params.dmg*kf.dmg)+(params.rpm*kf.rpm)+(params.dst*kf.dst)+((100/params.dsp)*kf.dsp)
				elseif modes.mode1 == "3" then
					prm = rx_wmgr.wm_modes.priors[modes.priors][sect] or 0
				end
				for k,v in ipairs(modes.types) do
					if v.t == params.typ then
						prm = prm + prm*v.p/100
						break
					end
				end
				if weapons_types[params.typ] then
					table.insert(weapons_types[params.typ],{obj = w.obj,ammo = w.ammo,prm = prm})
				end
			end
--			table.sort(weapons, function(a,b) return get_weapon_firepower(a.obj) > get_weapon_firepower(b.obj) end)
			-- Так, теперь у нас отсортированны все пушки НПС. Найдем ту, для которой есть патроны...
			for k,v in pairs(weapons_types) do
				table.sort(v,function(a,b) return a.prm > b.prm end)
				local cnt = 0
				local b_self = false
				local b_best = false
				local s_self = ""
				for i,w in ipairs(v) do
					cnt = cnt + 1
					local b_ammo = false
					local vac = w.ammo
					if vac and #vac>0 then
						for kk, vv in pairs(vac) do
							if ammo[vv] and ammo[vv] > 0 then -- Так, патроны есть.
								b_ammo = true
								break
							end
						end
					end
					if b_self == false and b_ammo == true then
						b_self = true
						s_self = w.obj:section_name()
					elseif b_best == false then
						if s_self ~= "" then
							if w.obj:section_name() ~= s_self then
								b_best = true
							else
								table.insert(sell_list, w.obj)
							end
						else
							b_best = true
						end
					else
						table.insert(sell_list, w.obj)
					end
				end
			end

			-- Так, с оружием закончили...
			-- Все, что осталось - надо продать.
			-- 1 самое дорогое можно попробовать через новости...
			item_list = nil
			local money = 0
			if sell_list and #sell_list>0 then
				table.sort(sell_list, function(a,b) return get_item_cost(a) > get_item_cost(b) end)		
				local zz = sell_list[1]
				if zz and b_stalker == true and (get_item_cost(zz) >= sell_limit) then
					-- Продадим через новости.
					news_main.on_offline_trade(npc, zz)
					table.remove(sell_list, 1)
				end
			end
			for kk,vv in pairs(sell_list) do
				local cost = get_item_cost(server_object(vv.id))
				if (cost > 0) then
					s_name = utils.cfg_get_string(config, vv:section_name(), "inv_name", vv, false, "", "")
					if (s_name == nil) then s_name = "" end
					s_name = translate(s_name)
					local coeff = math.random(30,50) / 100
					local price = math.floor(cost * coeff)
					money = money + price
					-- Почистим items
					if (items[npc.id] and #items[npc.id]>0) then
						for z=1, #items[npc.id] do
							if (items[npc.id][z] and items[npc.id][z].id == vv.id) then
								table.remove(items[npc.id], z)
								gps_habar.remove_item(npc.id, items[npc.id][z]) -- корректируем хабар в помеченных тайниках
								break
							end
						end
					end
					release(server_object(vv.id), true)
				end				
			end
			if (money > 0) then
				local tbl = netpacket:get(npc) 
				tbl.money = tbl.money+money
				netpacket:set(tbl, npc) 
			end
		end
	end
end

-- Строим таблицы, если надо.
-- В них - макс. скорость, сила атаки, дистанция атаки.
-- Не забываем про иммунитеты.
-- Поучаем immunities_sect
-- В immunities_sect читаем fire_wound_immunity. Все повреждения множим на него.
function get_monster_params(obj)
  amk.oau_reason="get_monster_params"
  local sect = obj:section_name()
	if (obj and iAmMonster[obj:clsid()]) or (obj and obj.community and obj:community()=="zombied") then
		if (monster_params and monster_params[sect]) then
			return monster_params[sect]
		else
			local speed 	= utils.cfg_get_number(config, sect, "MaxSpeed", obj, false, 5)
			local dist 		= utils.cfg_get_number(config, sect, "MaxAttackDist", obj, false, 3)
			local imm_sect	= utils.cfg_get_string(config, sect, "immunities_sect", obj, false, "", "")
			local immunity 	= utils.cfg_get_number(config, imm_sect, "fire_wound_immunity", obj, false, 1)
			local att_sect 	= utils.cfg_get_string(config, sect, "attack_params", obj, false, "", "")
			local attack	= 0
			if (config:section_exist(att_sect)) then
				local max_attack = 0
				local m_value, v
				config:iterate_lines(att_sect, function(result, id, value)
					m_value = string.explode(value, ",", true)
					if (m_value and #m_value>2) then
						v = tonumber(m_value[2])
						if (v and v > max_attack) then					
							max_attack = v
						end
					end
				end)
				attack = max_attack
			end
			monster_params[sect] = {speed = speed, dist = dist, immunity = immunity, attack = attack}
			return monster_params[sect]			
		end
	else
		return nil
	end
end

function sobj_is_far(obj, distance)
	local result = true
	if obj and distance then
		-- на одном ли уровне?
		local map = object_level_name(obj)
		if (map and level.name() == map) then
			-- Достаточно ли далеко?
			if (obj.position:distance_to(db.actor:position()) < distance) then
				result = false
			end
		end
   end
   return result
end

function box_is_protected(v)
	if v then
		local name = v:name()
		local id = v.id
		local sid = v:story_id()
		local sec = v:section_name()
		
		-- проверяем по имени объекта
		for k, o in pairs(protected.names) do
			if o == name then
				return true
			end
		end
		
		-- проверяем по ID объекта
		for k, o in pairs(protected.ids) do
			if o == id then
				return true
			end
		end
		
		-- проверяем по story ID объекта
		for k, o in pairs(protected.story_ids) do
			if o == sid then
				return true
			end
		end

		-- проверяем по секции объекта
		for k, o in pairs(protected.sections) do
			if o == sec then
				return true
			end
		end
	end
	return false
end

function npc_smart_is_peaceful(sobj)
	local result = false
	if (sobj and smart_filters and #smart_filters>0) then
		if (sobj.smart_terrain_id and sobj:smart_terrain_id() and sobj:smart_terrain_id()~=65535) then
			local sm = server_object(sobj:smart_terrain_id())
			if (sm and sm.name and sm:name()) then
				local sn = sm:name()
				for ks, vs in pairs(smart_filters) do
					if (vs == sn) then
						-- Ага, он у нас мирный.
						result = true
						break
					end
				end
			end
		end
	end
	return result
end

function on_death(npc_id)
	smart_terrain.on_death( npc_id )
end

function get_flags(npc_id)
	local flags = 0
	local obj = server_object(npc_id)
	if obj then
		if iAmMonster[obj:clsid()] or iAmStalker[obj:clsid()] then
			local char_ini = xr_logic.get_customdata_or_ini_file(obj, "<customdata>")
			if char_ini:section_exist("logic") then
				local from = ""
				local items = ""
				if char_ini:line_exist("logic", "on_hit") then
					flags = 1
				end
				if char_ini:line_exist("logic", "on_death") then
					flags = flags + 2
				end
			end
		end
	end
	return flags
end

function is_valuable(item)
	local result = false
	if item and not (iAmMonster[item:clsid()] or iAmStalker[item:clsid()]) and not protected_items.actor_items_keep(item:section_name()) then
		-- Уники не подбираем (пока?)
		if always_keep_item[item:section_name()] or sell_table[item:section_name()] == nil then
			return false
		end
		local cost = get_item_cost(item)
		if iAmWeapon[item:clsid()] and cost >= 1000 then
			result = true
		elseif cost >= 800 then
			result = true
		end
	end
	return result
end
