
-- Каждая функция в этом файле используется как условие xr_logic: {=функция !функция}
-- Если в функцию необходимо передавать параметры, то:  {=функция(парам1:парам2:...) !функция(парам1:парам2:...)}
-- Формат: function f(actor, npc). В случае передачи параметров: function f(actor, npc, p).
-- ----------------------------------------------------------------------------------------------------
-- Функции для работы с combat_ignore_cond
-- ----------------------------------------------------------------------------------------------------
function is_enemy_actor(enemy, object)
	return enemy:id() == db.actor:id()
end

-- текущий враг на расстоянии больше или равном заданному расстоянию
-- для combat_ignore
function fighting_dist_ge(enemy, npc, p)
	local d = p[1]
	return enemy:position():distance_to_sqr(npc:position()) >= d * d
end

-- расстояние до текущего реального врага меньше или равно заданного значения
function fighting_dist_le(enemy, npc, p)
	local d = p[1]
	return enemy:position():distance_to_sqr(npc:position()) <= d * d
end

function enemy_in_zone(enemy, npc, p)
	local zone = db.zone_by_name[p[1]]
	if zone == nil then
		abort("Wrong zone name %s in enemy_in_zone function. NPC [%s]", tostring(p[1]), npc:name())
	end
	return utils.npc_in_zone(enemy, zone)
end


-- ----------------------------------------------------------------------------------------------------
-- Общие функции
-- ----------------------------------------------------------------------------------------------------
-- видим ли мы еще "черный экран" или нет?
function black_screen(actor, npc)
	return device().precache_frame > 1
end
--Проверка, встречается ли в имени чувака одна из строк .
function check_npc_name (actor , npc , p)
	if npc:name() == nil then return false end
	local name_exist = false
	for k,v in pairs(p) do
		if string.find( npc:name(), v ) ~= nil then
			name_exist = true
		end
	end
	return name_exist
end

function check_enemy_name (actor , npc , p)
	local enemy_id = db.storage[npc:id()].enemy_id
	local enemy = db.storage[enemy_id] and db.storage[enemy_id].object
	local name
	if enemy and enemy:alive() then
		name = enemy:name()
		for i, v in pairs(p) do
			if string.find( name, v ) ~= nil then
				return true
			end
		end
	end
	return false
end

function is_playing_sound (actor, npc)
	return xr_sound.sound_table[npc:id()] ~= nil
end

-- проверка, что актер жив
function actor_alive(actor, npc)
	if db.actor and db.actor:alive() then
		return true
	end
	return false
end

function see_npc(actor, npc, p)
	local npc1 = get_story_object(p[1])
	if npc and npc1 then
		--printf("cond <see_npc>: [%s]->[%s]", npc:name(), npc1:name())
		return npc:see(npc1)
	else
		return false
	end
end

function actor_see_npc(actor, npc)
	return db.actor:see(npc)
end

function npc_in_actor_frustum(actor, npc)
	return npc_in_actor_frustrum(npc)
end

function is_wounded(actor, npc)
	return xr_wounded.is_wounded(npc)
end

function dist_to_actor_le(actor, npc, p)
	local d = p[1]
	if d == nil then
		abort("Wrong parameter in 'dist_to_actor_le' function!!!")
	end
	return d and npc:position():distance_to_sqr(actor:position()) <= d * d
end

function dist_to_actor_ge(actor, npc, p)
	local d = p[1]
	if d == nil then
		abort("Wrong parameter in 'dist_to_actor_ge' function!!!")
	end
	return d and npc:position():distance_to_sqr(actor:position()) >= d * d
end

-- Проверка выполняет ли кто указанную работу
function is_obj_on_job(actor, npc, p)
	local smart
	if p and p[2] then
		smart = sim_board.get_sim_board():get_smart_by_name(p[2])
	else
		smart = xr_gulag.get_npc_smart(npc)
	end
	if smart == nil then
		return false
	end
	for k,v in pairs(smart.npc_info) do
		local npc_job = smart.job_data[v.job_id]
		printf("section [%s]", tostring(npc_job.section))
		if npc_job.section == p[1] then
			return true
		end
	end
	return false
end

-- проверка того что дистанция до обьекта <= заданной
-- параметры: [sid,dist]
function distance_to_obj_on_job_le(actor, npc, p)
	local smart = xr_gulag.get_npc_smart(npc)
	for k,v in pairs(smart.npc_info) do
		local npc_job = smart.job_data[v.job_id]
		if npc_job.section == p[1] then
			return npc:position():distance_to_sqr(v.se_obj.position) <= p[2]*p[2]
		end
	end
	return false
end

-- проверка того что npc находится в заданной зоне
-- !!! ВЫЗЫВАТЬ ТОЛЬКО ИЗ SPACE RESTRICTOR !!!
-- параметры: [sid1:sid2:...]
-- !!! НЕКОРРЕКТНО РАБОТАЕТ ДЛЯ ОБЬЕКТОВ В offline'e !!!
-- !!! ДЛЯ ГАРАНТИИ ИСПОЛЬЗОВАТЬ one_obj_in_zone !!!
function obj_in_zone(actor, zone, p)
	local npc1, i, v = 0, 0, 0
	for i, v in pairs(p) do
		npc1 = get_story_object_id(v)
		if npc1 and zone:inside(alife():object(npc1).position) then
			return true
		end
	end
	return false
end

-- параметры: [sid:def*] def=true|false
-- * параметр не обязателен
function one_obj_in_zone(actor, zone, p)
	--local def_offline = (p[2] ~= "false") -- default (true) result if npc in offline
	local obj1 = get_story_object_id(p[1])

	if obj1 then -- npc is online
		return zone:inside(alife():object(obj1).position)
	else -- npc is offline
		return (p[2] ~= "false") -- default (true) result if npc in offline
	end
end

function story_obj_in_zone_by_name (actor, npc, p)
	local obj = get_story_object_id(p[1])
	local zone = db.zone_by_name[p[2]]
	if obj and zone then -- npc is online
		return zone:inside(alife():object(obj).position)
	end
	return false
end

function actor_in_zone(actor, npc, p)
	local zone = db.zone_by_name[p[1]]
	return utils.npc_in_zone(db.actor, zone)
end

function npc_in_zone(actor, npc, p)
	local zone = db.zone_by_name[p[1]]

	if type(npc.id) ~= "function" then
		npc_obj = db.storage[npc.id] and db.storage[npc.id].object
		if zone == nil then
			return true
		end

		if npc_obj == nil then
			return zone:inside(npc.position)
		end
	else
		npc_obj = npc
	end

	return utils.npc_in_zone(npc_obj, zone)
end

-- true, если здоровье npc <= заданному значению
-- false в противном случае
function health_le(actor, npc, p)
	return p[1] and npc.health < p[1]
end

-- true, если здоровье актера  <= заданному значению
-- false в противном случае
function actor_health_le(actor, npc, p)
	return p[1] and actor.health < p[1]
end

--[[
-- true, если здоровье вертолёта <= заданному значению
-- false в противном случае
function heli_health_le(actor, obj, p)
	return p[1] and obj:get_helicopter():GetfHealth() < p[1]
end

-- видит ли вертолёт npc (по story id)
function heli_see_npc(actor, obj, p)
	if p[1] then
		local o = get_story_object( p[1] )
		return o ~= nil and obj:get_helicopter():isVisible( o )
	else
		return false
	end
end

function heli_see_actor(actor, obj)
	return actor ~= nil and obj:get_helicopter():isVisible( actor )
end

-- Проверка на принадлежность врага к одной из групп
-- (можно задавать несколько через двоеточие)
function enemy_group(actor, npc, p)
	local enemy_id = db.storage[npc:id()].enemy_id
	local enemy = db.storage[enemy_id] and db.storage[enemy_id].object
	local g = enemy:group()
	local i, v = 0, 0
	for i, v in pairs(p) do
		if v == g then
			--printf("_bp: [%s]'s enemy is from group [%d]", npc:name(), v)
			return true
		end
	end
	return false
end

function gulag_state(actor, npc, p)
	if xr_gulag.getGulagState(p[1]) == p[2] then
		return true
	end
	return false
end
]]--

function npc_community(actor, npc, p)
	local npc_obj

	if p[1] == nil then
		abort("Wrong number of params in npc_community")
	end

	if type(npc.id) ~= "function" then
		npc_obj = db.storage[npc.id] and db.storage[npc.id].object

		if npc_obj == nil then return npc:community() == p[1] end
	else
		npc_obj = npc
	end

	if character_community(npc_obj) == p[1] then
		return true
	end
	return false
end

--[[
function npc_rank(actor, npc, p)
	if p[1] == nil then
		abort("Wrong number of params in npc_rank")
	end

	if ranks.get_obj_rank_name(npc) == p[1] then
		return true
	end
	return false
end

function npc_profile(actor, npc, p)
	if p[1] == nil then
		abort("Wrong number of params in npc_profile")
	end
	if npc:profile_name() == p[1] then
		return true
	end
	return false
end
]]--

-- Проверка того что удар был нанесен кем-то из npc указанных в списке.
-- Параметры это story_id персонажей. Можно задавать несколько story_id.
function hitted_by(actor, npc, p)
	local npc1
	local t = db.storage[npc:id()].hit
	if t then
		for i, v in pairs(p) do
			npc1 = get_story_object(v)
			if npc1 and t.who == npc1:id() then
				return true
			end
		end
	end
	return false
end
-- Функция проверки попадания в кость по её индексу.(Проверка только для секции hit)
function hitted_on_bone(actor, npc, p)
	for k,v in pairs (p) do
		if db.storage[npc:id()].hit.bone_index == npc:get_bone_id(v) then
			return true
		end
	end
	return false
end

-- Проверка, что лучшее оружие персонажа - пистолет
function best_pistol(actor, npc)
	local pistol = npc:item_in_slot(1)
	if pistol ~= nil then
		return true
	else
		return false
	end
end

-- Проверка, что персонажу нанесли смертельный хит. Проверять ТОЛЬКО на on_hit
function deadly_hit(actor, npc)
	if db.storage[npc:id()] == nil or db.storage[npc:id()].hit == nil then
		--printf("deadly hit false")
		return false
	end

	--printf("deadly hit [%s]", tostring(db.storage[npc:id()].hit.deadly_hit == true))
	return db.storage[npc:id()].hit.deadly_hit == true
end



-- Проверка того что персонаж был убит кем-то из npc указанных в списке.
-- Параметры это story_id персонажей. Можно задавать несколько story_id.
function killed_by(actor, npc, p)
	local npc1
	local t = db.storage[npc:id()].death
	if t then
		for i, v in pairs(p) do
			npc1 = get_story_object(v)
			if npc1 and t.killer == npc1:id() then
				printf("_bp: killed_by(%d)", v)
				return true
			end
		end
	end
	return false
end

-- проверка (по story_id) все ли проверяемые сталкеры живы
-- TODO: исправить ситуацию, когда выдается неправильный результат для обьектов, которые
--       не успели проспавниться.
function is_alive_all(actor, npc, p)
	local npc1
	for i, v in pairs(p) do
		npc1 = get_story_object_id(v)
		if npc1 == nil then
			return false
		end
		npc1 = alife():object(npc1)
		if npc1 and (not IsStalker(npc1) or not npc1:alive()) then
			return false
		end
	end
	return true
end

-- проверка (по story_id) того, что чотя бы один из проверяемых сталкеров жив
-- TODO: исправить ситуацию, когда выдается неправильный результат для обьектов, которые
--       не успели проспавниться.
function is_alive_one(actor, npc, p)
	local npc1
	for i, v in pairs(p) do
		npc1 = get_story_object_id(v)
		if npc1 == nil then
			return false
		end
		npc1 = alife():object(npc1)
		if npc1 and IsStalker(npc1) and npc1:alive() then
			return true
		end
	end
	return false
end

-- проверка (по story_id) того, что проверяемыq npc жив
-- TODO: исправить ситуацию, когда выдается неправильный результат для обьектов, которые
--       не успели проспавниться.
function is_alive(actor, npc, p)
	local npc1

	if npc == nil or (p and p[1]) then
		npc1 = get_story_object_id(p[1])
	elseif (type(npc.id) == "number") then
		npc1 = npc.id
	else
		npc1 = npc:id()
	end

	if npc1 == nil then
		return false
	end

	npc1 = alife():object(npc1)

	if npc1 and IsStalker(npc1) and npc1:alive() then
		return true
	end

	return false
end

-- проверка (по story_id) все ли проверяемые сталкеры мертвы
-- TODO: исправить ситуацию, когда выдается неправильный результат для обьектов, которые
--       не успели проспавниться.
function is_dead_all(actor, npc, p)
	local npc1
	for i, v in pairs(p) do
		npc1 = get_story_object(v)
		if npc1 then
			if npc1:alive() then
				return false
			else
				printf("_bp: is_dead_all(%d) = true", v)
				return true
			end
		end
		return false
	end
	return true
end

-- проверка (по story_id) того, что хотя бы один из проверяемых сталкеров мертв
-- TODO: исправить ситуацию, когда выдается неправильный результат для обьектов, которые
--       не успели проспавниться.
function is_dead_one(actor, npc, p)
	local npc1
	for i, v in pairs(p) do
		npc1 = get_story_object(v)
		if not npc1 or not npc1:alive() then
			printf("_bp: is_dead_one(%d) = true", v)
			return true
		end
	end
	return false
end

-- проверка (по story_id) того, что хотя бы один из проверяемых сталкеров мертв
-- TODO: исправить ситуацию, когда выдается неправильный результат для обьектов, которые
--       не успели проспавниться.
function is_dead(actor, npc, p)
	local npc1
	npc1 = get_story_object(p[1])
	return not npc1 or not npc1:alive()
end

-- Проверяет , существует ли обьект с заданным стори айди.
function story_object_exist(actor, npc, p)
	local npc1 = get_story_object(p[1])
	return npc1 ~= nil
end

--[[
-- проверка (по story_id) того, что нашим врагом есть хотя бы кото-то один из списка
function check_fighting(actor, npc, p)
	local enemy_id = db.storage[npc:id()].enemy_id
	local enemy = db.storage[enemy_id] and db.storage[enemy_id].object
	local sid
	if enemy and enemy:alive() then
			sid = enemy:story_id()
			for i, v in pairs(p) do
					--printf("_bp: %s.check_fighting(%d)", npc:name(), v)
				if type(v) == 'number' and sid == v then
					--printf("TRUE")
					return true
				end
			end
	end
	--printf("_bp: check_fighting() = false")
	return false
end
]]--


-- true, если у актёра в инвентаре есть указанный предмет
-- false, если нету, либо не задана секция предмета
function actor_has_item(actor, npc, p)
	local story_actor  = get_story_object("actor")
	return p[1] ~= nil and story_actor and story_actor:object( p[1] ) ~= nil
end

function npc_has_item(actor, npc, p)
	return p[1] ~= nil and npc:object( p[1] ) ~= nil
end
-- проверяет наличие заданого количества предметов в инвентаре игрока.
function actor_has_item_count(actor, npc, p)
	local item_section 	= p[1]
	local need_count 	= tonumber(p[2])
	local has_count 	= 0
	local function calc(temp, item)
		--printf("item [%s]",tostring(item:section()))
		if item:section() == item_section then
			has_count = has_count + 1
		end
	end
	actor:iterate_inventory(calc, actor)
	return has_count >= need_count
end

-- возвращает true, если в текущей схеме персонажа взведён указанный сигнал.
function signal(actor, npc, p)
	if p[1] then
		local st   = db.storage[npc:id()]
		local sigs = st[st.active_scheme].signals
--		printf( "xr_conditions.signal: npc=%s, scheme=%s", npc:name(), tostring(st.active_scheme) )
		return sigs ~= nil and sigs[p[1]] == true
	else
		return false
	end
end

-- возвращает true, если значение указанного счётчика актёра больше указанного числа
function counter_greater(actor, npc, p)
	if p[1] and p[2] then
		local c = xr_logic.pstor_retrieve(actor, p[1], 0)
--		if  c > p[2] then printf("pl: counter [%s]  greater [%s]", p[1], p[2]) end
		return c > p[2]
	else
		return false
	end
end
function counter_equal(actor, npc, p)
	if p[1] and p[2] then
		local c = xr_logic.pstor_retrieve(actor, p[1], 0)
		return c == p[2]
	else
		return false
	end
end

--[[
-- определяет нечётность интервала игрового времени. интервал нужно передать в p[1]
function odd_time_interval(actor, npc, p)
	return odd( game.time() / p[1] )
end
]]--
-------------------------------------------------------------------------------------------------------
-- Функции поддержки kamp
function _kamp_talk(actor, npc)
	if xr_kamp.kamp_stalkers[npc:id()] then
		return xr_kamp.kamp_stalkers[npc:id()]
	end
	return false
end

function _used(actor, npc)
	return npc:is_talking()
end
-------------------------------------------------------------------------------------------------------

-------------------------------------------------------------------------------------------------------
local alarm_statuses = {
	normal = smart_terrain_control.NORMAL,
	danger = smart_terrain_control.DANGER,
	alarm = smart_terrain_control.ALARM
}

-- Функции поддержки безопасности баз
function check_smart_alarm_status(actor, npc, p)
	local smart_name = p[1]
	local status = alarm_statuses[p[2]]

	if status == nil then
		abort("Wrong status[%s] in 'check_smart_alarm_status'", tostring(p[2]))
	end

	local smart = sim_board.get_sim_board():get_smart_by_name(smart_name)

	local smart_control = smart.base_on_actor_control

	if smart_control == nil then
		abort("Cannot calculate 'check_smart_alarm_status' for smart %s", tostring(smart_name))
	end

	return smart_control:get_status() == status
end

-------------------------------------------------------------------------------------------------------
function has_enemy(actor, npc)
	return npc:best_enemy() ~= nil
end

function has_actor_enemy(actor, npc)
	local best_enemy = npc:best_enemy()
	return best_enemy ~= nil and best_enemy:id() == db.actor:id()
end

function see_enemy(actor, npc)
	local enemy = npc:best_enemy()

	if enemy ~= nil then
			return npc:see(enemy)
	end
	return false
end

function has_enemy_in_current_loopholes_fov(actor, npc)
	return npc:in_smart_cover() and npc:best_enemy() ~= nil and npc:in_current_loophole_fov( npc:best_enemy():position())
end

function talking(actor, npc)
	return actor:is_talking()
end

function npc_talking(actor, npc)
	return npc:is_talking()
end

function see_actor(actor, npc)
	return npc:alive() and npc:see(actor)
end

function actor_enemy(actor, npc)
	local t = db.storage[npc:id()].death
	return npc:relation(actor) == game_object.enemy or (t ~= nil and t.killer == actor:id())
end

function actor_friend(actor, npc)
	return npc:relation(actor) == game_object.friend
end

function actor_neutral(actor, npc)
	return npc:relation(actor) == game_object.neutral
end

function is_factions_enemies(actor, npc, p)
	if(p[1]~=nil) then
		return game_relations.is_factions_enemies(character_community(actor), p[1])
	else
		return false
	end
end

function is_factions_neutrals(actor, npc, p)
	return not(is_factions_enemies(actor, npc, p) or is_factions_friends(actor, npc, p))
end

function is_factions_friends(actor, npc, p)
	if(p[1]~=nil) then
		return game_relations.is_factions_friends(character_community(actor), p[1])
	else
		return false
	end
end

function is_faction_enemy_to_actor(actor, npc, p)
	if(p[1]~=nil) then
--        return db.actor:community_goodwill(p[1])<-1000
		return relation_registry.community_goodwill(p[1], db.actor:id())<=-1000
	else
		return false
	end
end

function is_faction_friend_to_actor(actor, npc, p)
	if(p[1]~=nil) then
--		return db.actor:community_goodwill(p[1])>1000
		return relation_registry.community_goodwill(p[1], db.actor:id())>=1000
	else
		return false
	end
end

function is_faction_neutral_to_actor(actor, npc, p)
	return not(is_faction_enemy_to_actor(actor, npc, p) or is_faction_friend_to_actor(actor, npc, p))
end

function is_squad_friend_to_actor(actor, npc, p)
	if(p[1]~=nil) then
--	   printf("squad check goodwill1 [%s]", p[1])
		return game_relations.check_all_squad_members(p[1], "friend")
	else
--	   printf("squad check goodwill5 [%s]", p[1])
		return false
	end
end

function is_squad_enemy_to_actor(actor, npc, p)
	if not p then
		abort("Not enough arguments in 'is_squad_enemy_to_actor' funciton!")
	end

	for k,v in pairs(p) do
--   	printf("squad check goodwill1 [%s]", v)
		if game_relations.check_all_squad_members(v, "enemy") then
			return true
		end
	end

	return false
end

function is_squad_neutral_to_actor(actor, npc, p)
	return not(is_squad_enemy_to_actor(actor, npc, p) or is_squad_friend_to_actor(actor, npc, p))
end

-- текущий враг актёр?
function fighting_actor(actor, npc)
	local enemy_id = db.storage[npc:id()].enemy_id
	local enemy = db.storage[enemy_id] and db.storage[enemy_id].object
	return enemy and enemy:id() == actor:id()
end


function hit_by_actor(actor, npc)
	local t = db.storage[npc:id()].hit
	local hit_by_actor = (t ~= nil and t.who == actor:id())
	printf("_bp: hit_by_actor: %s", if_then_else(hit_by_actor, "true", "false"))
	return hit_by_actor
end

function killed_by_actor(actor, npc)
	local t = db.storage[npc:id()].death
	local killed_by_actor = t ~= nil and t.killer == actor:id()
	printf("_bp: killed_by_actor: %s", if_then_else(killed_by_actor, "true", "false"))
	return killed_by_actor
end

function actor_has_weapon (actor, npc)
	local obj = actor:active_item ()
	if obj == nil or isWeapon (obj) == false then return false end
	return true
end

function actor_active_detector(actor, npc, p)
	local detector_section = p and p[1]
	if detector_section == nil then abort("Wrong parameters in function 'actor_active_detector'") end
	local actor_detector = db.actor:active_detector()
	return (actor_detector ~= nil) and actor_detector:section() == detector_section
end

function heavy_wounded(actor, npc)
	return xr_wounded.is_heavy_wounded_by_id( npc:id() )
end

--[[
Проверка на заданный период времени
Время задается в минутах
Параметры: (time_shift:period_min)
					 time_shift - периодичность срабатывания
					 period - период срабатывания на котором мы получаем true

Примеры:
time_period(60:10) - возвращает true каждый час на протяжении первых 10 минут
--]]
function time_period(actor, npc, p)
	local tshift, period = p[1], p[2]
	if tshift ~= nil and period ~= nil and db.actor ~= nil then
		return tshift > period and level.get_time_minutes() % tshift <= period
	end
	return false
end

function is_rain (actor, npc)
	return db.actor ~= nil and level.rain_factor() > 0
end

function is_heavy_rain (actor, npc)
	return db.actor ~= nil and level.rain_factor() >= 0.5
end

function is_day (actor, npc)
	return db.actor ~= nil and level.get_time_hours() >= 6 and level.get_time_hours() < 21
end

function is_dark_night (actor, npc)
	return db.actor ~= nil and (level.get_time_hours() < 3 or level.get_time_hours() > 22)
end

function is_jup_a12_mercs_time (actor, npc)
	return db.actor ~= nil and (level.get_time_hours() >= 1 and level.get_time_hours() < 5)
end

function zat_b7_is_night (actor, npc)
	return db.actor ~= nil and (level.get_time_hours() >= 23 or level.get_time_hours() < 5)
end

function zat_b7_is_late_attack_time (actor, npc)
	return db.actor ~= nil and (level.get_time_hours() >= 23 or level.get_time_hours() < 9)
end

function mob_has_enemy(actor, npc)
	-- return false
	if npc == nil then return false end
	--if npc:get_enemy () then printf ("ENEMY PRESENT") else printf ("ENEMY NOT PRESENT") end
	return npc:get_enemy() ~= nil
end

function mob_was_hit(actor, npc)
	local h = npc:get_monster_hit_info()
	if h.who and h.time ~= 0 then
		return true
	end
	return false
end

function actor_on_level(actor, npc, p)
	for k,v in pairs (p) do
		--printf("level name: [%s], needed level name: [%s]", level.name(), v`)
		if v == level.name() then
			return true
		end
	end
	return false
end

function treasure_exist(actor, npc, p)
	--printf("%s %s", actor:name(), npc:name())
	return true
end

--[[
--'-----------------------------------------------------------------------------------
--' Cover support
--'-----------------------------------------------------------------------------------
--' Если возвращает true, то солдаты за каверами начинают стрелять.
function cover_attack(actor, npc)
	--' Берем сквад объекта
	local squad = get_object_squad(npc)

	if squad == nil then
		return false
	end

	return squad:cover_attack()
end
]]--

--'-----------------------------------------------------------------------------------
--' Squad support
--'-----------------------------------------------------------------------------------
function squad_in_zone(actor, npc, p)
	local story_id = p[1]
	local zone_name = p[2]
	if story_id == nil then
		abort("Insufficient params in squad_in_zone function. story_id[%s], zone_name[%s]", tostring(story_id), tostring(zone_name))
	end
	if zone_name == nil then
		zone_name = npc:name()
	end

	local sim_board = sim_board.get_sim_board()

	local squad = get_story_squad(story_id)
	if squad == nil then
		--abort("There is no squad with id[%s]", tostring(squad_id))
		return false
	end

	local zone = db.zone_by_name[zone_name]
	if zone == nil then
		--abort("There is no squad with id[%s]", tostring(zone_name))
		return false
	end

	for k in squad:squad_members() do
		local position = (db.storage[k.id] and db.storage[k.id].object and db.storage[k.id].object:position()) or k.object.position
		if zone:inside(position) then
			return true
		end
	end
	return false
end

function squad_has_enemy(actor, npc, p)
	local story_id = p[1]

	if story_id == nil then
		abort("Insufficient params in squad_has_enemy function. story_id [%s]", tostring(story_id))
	end

	local squad = get_story_squad(story_id)
	if squad == nil then
		--abort("There is no squad with id[%s]", tostring(story_id))
		return false
	end

	local al = alife()
	for k in squad:squad_members() do
		local npc_obj = level.object_by_id(k.object.id)
		if npc_obj == nil then
			return false
		end
		if npc_obj:best_enemy() ~= nil then
			return true
		end
	end

	return false
end

-- Functions for Yantar
function squad_in_zone_all(actor, npc, p)
	local story_id = p[1]
	local zone_name = p[2]
	if story_id == nil or zone_name == nil then
		abort("Insufficient params in squad_in_zone_all function. story_id[%s], zone_name[%s]", tostring(story_id), tostring(zone_name))
	end
	local squad = get_story_squad(story_id)
	if squad == nil then
		--abort("There is no squad with id[%s]", tostring(story_id))
		return false
	end
	local zone = db.zone_by_name[zone_name]
	if zone == nil then
		--abort("There is no squad with id[%s]", tostring(zone_name))
		return false
	end
	local al = alife()
	for k in squad:squad_members() do
		local position = (db.storage[k.id] and db.storage[k.id].object and db.storage[k.id].object:position()) or k.object.position
		if not zone:inside(position) then
			return false
		end
	end
	return true
end

function squads_in_zone_b41(actor, npc, p)
	local smart = sim_board.get_sim_board():get_smart_by_name("jup_b41")
	local zone = db.zone_by_name["jup_b41_sr_light"]
	local al = alife()

	if zone == nil then
		return false
	end
	if smart == nil then
		return false
	end

	for k,v in pairs(sim_board.get_sim_board().smarts[smart.id].squads) do
		if v ~= nil then
			for j in v:squad_members() do
				if not zone:inside(j.object.position) then
					return false
				end
			end
		end
	end

	return true
end


--' Проверка в таргет кондлисте задания, соответствует ли имя сквада переданному
function target_squad_name(actor, obj, p)
	if p[1] == nil then
		abort("Wrong parameters")
	end
	if not(obj) then
		return false
	end
	--callstack()
	if IsStalker(obj) or IsMonster(obj) then
		if alife():object(obj.group_id) == nil then
			return false
		end
		if string.find( alife():object(obj.group_id):section_name(), p[1] ) ~= nil then
			return true
		end
		--return alife():object(obj.group_id):section_name() == p[1]
	end
	return obj:section_name() == p[1]
end

--' Проверка в таргет кондлисте задания, соответствует ли имя смарта переданному
function target_smart_name(actor, smart, p)
	if p[1] == nil then
		abort("Wrong parameters")
	end
	--callstack()
	return smart:name() == p[1]
end

--' Проверяет жив ли отряд с указанным ID
function squad_exist(actor, npc, p)
	local story_id = p[1]
	if story_id == nil then
		abort("Wrong parameter story_id[%s] in squad_exist function", tostring(story_id))
	end
	local squad = get_story_squad(story_id)

--	if squad == nil then
--		return false
--	end
	return squad ~= nil
	--	return squad.squad_power > 0
end

function is_squad_commander(actor, npc)  -- Повелитель Зоны --
	if (type(npc.id) == "number") then
		npc_id = npc.id
	else
		npc_id = npc:id()
	end



      local squad = get_object_squad(npc)
 
      if squad==nil then return true end

      return squad ~= nil and squad:commander_id() == npc_id
end

function squad_npc_count_ge(actor, npc, p)
	local story_id = p[1]
	if story_id == nil then
		abort("Wrong parameter squad_id[%s] in 'squad_npc_count_ge' function", tostring(squad_id))
	end
	local squad = get_story_squad(story_id)

	if squad then
		return squad:npc_count() > tonumber(p[2])
	else
		return false
	end
end

function surge_complete()
	return surge_manager.is_finished()
end

function surge_started()
	return surge_manager.is_started()
end

function surge_kill_all()
	return surge_manager.is_killing_all()
end

function signal_rocket_flying(actor, npc, p)
	if p==nil then
		abort("Signal rocket name is not set!")
	end
	if db.signal_light[p[1]] then
		return db.signal_light[p[1]]:is_flying()
	else
		abort("No such signal rocket: [%s] on level", tostring(p[1]))
	end
	return false
end

function quest_npc_enemy_actor(actor, npc, p)
	if p[1] == nil then
		abort("wrong story id")
	else
		local obj = get_story_object(p[1])
		if obj and IsStalker(obj) then
			if db.actor and obj:general_goodwill(db.actor)<=-1000 then
				return true
			end
		end
	end
	return false
end

function animpoint_reached(actor, npc)
	local animpoint_storage = db.storage[npc:id()].animpoint

	if animpoint_storage == nil then
		return false
	end

	local animpoint_class = animpoint_storage.animpoint

	return animpoint_class:position_riched()
end

--[[
function npc_stay_offline(actor, npc, p)
	if p == nil then
		abort("Wrong parameter!!!")
	end
	if npc and db.actor then
		if is_smart_in_combat(actor, npc, p) then
			if npc.position:distance_to(db.actor:position())>=30 or game_relations.get_gulag_relation_actor(p[1], "enemy") then
				return true
			end
		end
	end
	return false
end
]]--

-- проверка того что дистанция до обьекта >= заданной
-- параметры: [sid,dist]
function distance_to_obj_ge(actor, npc, p)
	local npc_id = get_story_object_id(p[1])
	local npc1 = npc_id and alife():object(npc_id)
	if npc1 then
		return db.actor:position():distance_to_sqr(npc1.position) >= p[2]*p[2]
	end
	return false
end

function distance_to_obj_le(actor, npc, p)
	local npc_id = get_story_object_id(p[1])
	local npc1 = npc_id and alife():object(npc_id)
	if npc1 then
		return db.actor:position():distance_to_sqr(npc1.position) < p[2]*p[2]
	end
	return false
end

function in_dest_smart_cover(actor, npc, p)
	return npc:in_smart_cover()
end

function active_item(actor, npc, p)
	if p and p[1] then
		for k,v  in pairs(p) do
			if actor:item_in_slot(3) ~= nil and actor:item_in_slot(3):section() == v then return true end
		end
	end
	return false
end

function actor_nomove_nowpn()
	if (not isWeapon(db.actor:active_item())) or db.actor:is_talking() then
		return true
	end
	return false
end

function jup_b16_is_zone_active(actor, npc)
	return has_alife_info(npc:name())
end

--Функция проверки состояния видимости кровососа.
-- Возможный набор параметров --> story_id:visibility_state(можно вызывать откуда угодно) или visibility_state(если вызывается из кастомдаты кровососа)
--  visibility_state -->
--						0 - невидимый
--						1 - полувидимый
--						2 - полностью видимый

function check_bloodsucker_state(actor, npc, p)
	if (p and p[1]) == nil then abort("Wrong parameters in function 'check_bloodsucker_state'!!!") end
	local state = p[1]
	if p[2] ~= nil then
		state = p[2]
		npc = get_story_object(p[1])
	end
	if npc ~= nil then
		return npc:get_visibility_state () == tonumber(state)
	end
	return false
end

function dist_to_story_obj_ge(actor, npc, p)
	local story_id = p and p[1]
	local story_obj_id = get_story_object_id(story_id)
	if story_obj_id == nil then return true end
	local se_obj = alife():object(story_obj_id)
	return se_obj.position:distance_to(db.actor:position()) > p[2]
end

function actor_has_nimble_weapon(actor, npc)
	local need_item = {}
	need_item["wpn_groza_nimble"] = true
	need_item["wpn_desert_eagle_nimble"] = true
	need_item["wpn_fn2000_nimble"] = true
	need_item["wpn_g36_nimble"] = true
	need_item["wpn_protecta_nimble"] = true
	need_item["wpn_mp5_nimble"] = true
	need_item["wpn_sig220_nimble"] = true
	need_item["wpn_spas12_nimble"] = true
	need_item["wpn_usp_nimble"] = true
	need_item["wpn_vintorez_nimble"] = true
	need_item["wpn_svu_nimble"] = true
	need_item["wpn_svd_nimble"] = true
	for k,v in pairs(need_item) do
		if actor:object(k) ~= nil then
			return true
		end
	end
	return false
end

function actor_has_active_nimble_weapon(actor, npc)
	local need_item = {}
	need_item["wpn_groza_nimble"] = true
	need_item["wpn_desert_eagle_nimble"] = true
	need_item["wpn_fn2000_nimble"] = true
	need_item["wpn_g36_nimble"] = true
	need_item["wpn_protecta_nimble"] = true
	need_item["wpn_mp5_nimble"] = true
	need_item["wpn_sig220_nimble"] = true
	need_item["wpn_spas12_nimble"] = true
	need_item["wpn_usp_nimble"] = true
	need_item["wpn_vintorez_nimble"] = true
	need_item["wpn_svu_nimble"] = true
	need_item["wpn_svd_nimble"] = true

	if actor:item_in_slot(2) ~= nil and need_item[actor:item_in_slot(2):section()] == true then
		return true
	end
	if actor:item_in_slot(3) ~= nil and need_item[actor:item_in_slot(3):section()] == true then
		return true
	end
	return false
end

function jup_b202_inventory_box_empty(actor, npc)
	local inv_box = get_story_object("jup_b202_actor_treasure")
	return inv_box:is_inv_box_empty()
end
--[[
function jup_b46_actor_has_active_science_detector(actor, npc)
	if actor:item_in_slot(9) ~= nil and actor:item_in_slot(9):section() == "detector_scientific" then return true end
	return false
end
]]--
function is_in_danger(actor, npc, p)
	if p and p[1] then
		npc = get_story_object(p[1])
	end
	--printf("npc: [%s] is in danger [%s]", tostring(npc:id()), tostring(db.storage[npc:id()].danger_flag))
	return db.storage[npc:id()].danger_flag
end

function object_exist(actor , npc , p)
	return get_story_object(p[1]) ~= nil
end

function squad_curr_action(actor, npc, p)
	local squad = get_object_squad(npc)
	return squad.current_action and squad.current_action.name == p[1]
end

function is_monster_snork(actor, npc)
	return npc:clsid() == clsid.snork_s
end

function is_monster_dog(actor, npc)
	return npc:clsid() == clsid.dog_s
end

function is_monster_psy_dog(actor, npc)
	return npc:clsid() == clsid.psy_dog_s
end

function is_monster_polter(actor, npc)
	return npc:clsid() == clsid.poltergeist_s
end

function is_monster_tushkano(actor, npc)
	return npc:clsid() == clsid.tushkano_s
end

function is_monster_burer(actor, npc)
	return npc:clsid() == clsid.burer_s
end

function is_monster_controller(actor, npc)
	return npc:clsid() == clsid.controller_s
end

function is_monster_flesh(actor, npc)
	return npc:clsid() == clsid.flesh_s
end

function is_monster_boar(actor, npc)
	return npc:clsid() == clsid.boar_s
end


function dead_body_searching(actor, npc)
	return actor_menu.dead_body_searching
end

function jup_b47_npc_online(actor, npc, p)
--	printf("function jup_b47_npc_online: story_obj[%s]", tostring(p[1]))
	local story_obj = get_story_object(p[1])
	if story_obj == nil then
		return false
	end
	local obj = alife():object(story_obj:id())
	return obj ~= nil
end

function anomaly_has_artefact(actor, npc, p)
	local az_name = p and p[1]
	local af_name = p and p[2]

	local anomal_zone = db.anomaly_by_name[az_name]
	if anomal_zone == nil then
		return false
	end

	if anomal_zone.spawned_count < 1 then
		return false
	end

	if af_name == nil then
		local af_table = {}
		for k,v in pairs(anomal_zone.artefact_ways_by_id) do
			if alife():object(tonumber(k)) then
				table.insert(af_table, alife():object(tonumber(k)):section_name())
			end
		end
		return true, af_table
	end

	for k,v in pairs(anomal_zone.artefact_ways_by_id) do
		if alife():object(tonumber(k)) and af_name == alife():object(tonumber(k)):section_name() then
			return true
		end
	end

	return false
end

function zat_b29_anomaly_has_af(actor, npc, p)
	local az_name = p and p[1]
	local af_name

	local anomal_zone = db.anomaly_by_name[az_name]
	if anomal_zone == nil then
		return false
	end

	if anomal_zone.spawned_count < 1 then
		return false
	end

	for i = 16, 23 do
		if has_alife_info(dialogs_zaton.zat_b29_infop_bring_table[i]) then
			af_name = dialogs_zaton.zat_b29_af_table[i]
			break
		end
	end

	for k,v in pairs(anomal_zone.artefact_ways_by_id) do
		if alife():object(tonumber(k)) and af_name == alife():object(tonumber(k)):section_name() then
			db.actor:give_info_portion(az_name)
			return true
		end
	end

	return false
end

function jup_b221_who_will_start(actor, npc, p) -- доступные параметры: ability - проверить есть ли доступные темы, choose - выбрать групировку которая начнет перепалку
	local reachable_theme = {}
	local faction_table = {}
	local info_table = {
---------duty
		[1] = "jup_b25_freedom_flint_gone",
		[2] = "jup_b25_flint_blame_done_to_duty",
		[3] = "jup_b4_monolith_squad_in_duty",
		[4] = "jup_a6_duty_leader_bunker_guards_work",
		[5] = "jup_a6_duty_leader_employ_work",
		[6] = "jup_b207_duty_wins",
---------freedom
		[7] = "jup_b207_freedom_know_about_depot",
		[8] = "jup_b46_duty_founder_pda_to_freedom",
		[9] = "jup_b4_monolith_squad_in_freedom",
		[10] = "jup_a6_freedom_leader_bunker_guards_work",
		[11] = "jup_a6_freedom_leader_employ_work",
		[12] = "jup_b207_freedom_wins"
	}
--Составляем таблицу достыпных тем(тлько номера тем).
	for k,v in pairs(info_table) do
		if k <= 6 then
			faction_table[1] = "duty"
			faction_table[2] = "0"
		else
			faction_table[1] = "freedom"
			faction_table[2] = "6"
		end
		if (has_alife_info(v)) and (not has_alife_info("jup_b221_" .. faction_table[1] .. "_main_" .. tostring(k - tonumber(faction_table[2])) .. "_played")) then
			table.insert(reachable_theme,k)
			printf("jup_b221_who_will_start: table reachable_theme ------------------------------> [%s]", tostring(k))
		end
	end
	if (p and p[1]) == nil then
		abort("No such parameters in function 'jup_b221_who_will_start'")
	end
	if tostring(p[1]) == "ability" then
		return #reachable_theme ~= 0 -- если таблица пуста значит нет доступных тем и ненадо играть сцену
	elseif  tostring(p[1]) == "choose" then
---------Выберем рандомам елемент составленой таблицы и проверим к какой груперовки он пренадлежит :)
		return reachable_theme[math.random(1, #reachable_theme)] <= 6 -- если меньше 6-ти значит ДОЛГ если больше 6-ти значит СВОБОДА
	else
		abort("Wrong parameters in function 'jup_b221_who_will_start'")
	end
end

function pas_b400_actor_far_forward(actor, npc)
	local fwd_obj = get_story_object("pas_b400_fwd")

	if fwd_obj then
		if distance_between(fwd_obj, db.actor) > distance_between(fwd_obj, npc) then
			return false
		end
	else
		return false
	end

	local distance = 70 * 70
	local self_dist = npc:position():distance_to_sqr(actor:position())
	if self_dist < distance then
		return false
	end

	local squad = alife():object(alife():object(npc:id()).group_id)

	for k in squad:squad_members() do
		local other_dist = k.object.position:distance_to_sqr(actor:position())
		if other_dist < distance then
			return false
		end
	end

	--printf("npc: [%s], actor is far forward - self_dist [%s] distance [%s]", tostring(npc:name()), self_dist, distance)

	return true
end

function pas_b400_actor_far_backward(actor, npc)
	local bwd_obj = get_story_object("pas_b400_bwd")

	if bwd_obj then
		if distance_between(bwd_obj, db.actor) > distance_between(bwd_obj, npc) then
			return false
		end
	else
		return false
	end

	local distance = 70 * 70
	local self_dist = npc:position():distance_to_sqr(actor:position())
	if self_dist < distance then
		return false
	end

	local squad = alife():object(alife():object(npc:id()).group_id)

	for k in squad:squad_members() do
		local other_dist = k.object.position:distance_to_sqr(actor:position())
		if other_dist < distance then
			return false
		end
	end

	--printf("npc: [%s], actor is far backward - self_dist [%s] distance [%s]", tostring(npc:name()), self_dist, distance)

	return true
end

function pri_a28_actor_is_far(actor, npc)
	local distance = 150 * 150
	local squad = get_story_squad("pri_a16_military_squad")

	for k in squad:squad_members() do
		local npc_dist = k.object.position:distance_to_sqr(actor:position())
		if npc_dist < distance then
			return false
		end
	end

	return true
end

function check_enemy_smart(actor , npc , p)
	local enemy_id = db.storage[npc:id()].enemy_id
	local enemy = db.storage[enemy_id] and db.storage[enemy_id].object
	if enemy == nil or enemy_id == alife():actor().id then
		return false
	end
	local enemy_smart = xr_gulag.get_npc_smart(enemy)

	if (enemy_smart ~= nil) and (enemy_smart:name() == p[1]) then
		return true
	end
	return false
end

function zat_b103_actor_has_needed_food(actor, npc, p)
	return (dialogs_zaton.zat_b103_actor_has_needed_food(actor, npc)) or (has_alife_info("zat_b103_merc_task_done"))
end

function zat_b29_rivals_dialog_precond(actor, npc)
	local squads_table = {
						"zat_b29_stalker_rival_default_1_squad",
						"zat_b29_stalker_rival_default_2_squad",
						"zat_b29_stalker_rival_1_squad",
						"zat_b29_stalker_rival_2_squad"
						}

	local zones_table = {
						"zat_b29_sr_1",
						"zat_b29_sr_2",
						"zat_b29_sr_3",
						"zat_b29_sr_4",
						"zat_b29_sr_5",
						}

	local f_squad = false

	for k,v in pairs(squads_table) do
		if alife():object(alife():object(npc:id()).group_id):section_name() == v then
			f_squad = true
			break
		end
	end

	if not f_squad then
		return false
	end

	for k,v in pairs(zones_table) do
		if utils.npc_in_zone(npc, db.zone_by_name[v]) then
			return true
		end
	end

	return false
end

function polter_ignore_actor(actor, npc)
	return npc:poltergeist_get_actor_ignore()
end

function burer_gravi_attack(actor, npc)
	return npc:burer_get_force_gravi_attack()
end

function burer_anti_aim(actor, npc)
	return npc:burer_get_force_anti_aim()
end

function jup_b202_actor_treasure_not_in_steal(actor, npc)
	local before = ((not has_alife_info("jup_b52_actor_items_can_be_stolen")) and (not has_alife_info("jup_b202_actor_items_returned")))
	local after  = (has_alife_info("jup_b52_actor_items_can_be_stolen") and has_alife_info("jup_b202_actor_items_returned"))
	return (before or after)
end

function jup_b25_senya_spawn_condition(actor, npc)
	return (has_alife_info("jup_b16_oasis_found") or has_alife_info("zat_b57_bloodsucker_lair_clear") or has_alife_info("jup_b6_complete_end") or has_alife_info("zat_b215_gave_maps")) and has_alife_info("zat_b106_search_soroka")
end

function jup_b25_flint_gone_condition(actor, npc)
	return has_alife_info("jup_b25_flint_blame_done_to_duty") or has_alife_info("jup_b25_flint_blame_done_to_freedom") or has_alife_info("zat_b106_found_soroka_done")
end

-------------------------------------------------------------------------------------------------------------------------------------------
--	STALKER TRADE FUNCTIONS
-------------------------------------------------------------------------------------------------------------------------------------------
function has_tradable_stuff(actor, npc)


end


-------------------------------------------------------------------------------------------------------------------------------------------
--	end of STALKER TRADE FUNCTIONS
-------------------------------------------------------------------------------------------------------------------------------------------


pioneer_functor = xr_statistic.pioneer_functor

mutant_hunter_functor = xr_statistic.mutant_hunter_functor

detective_functor = xr_statistic.detective_functor

one_of_the_lads_functor = xr_statistic.one_of_the_lads_functor

kingpin_functor = xr_statistic.kingpin_functor

herald_of_justice_functor = xr_statistic.herald_of_justice_functor

seeker_functor = xr_statistic.seeker_functor

battle_systems_master_functor = xr_statistic.battle_systems_master_functor

high_tech_master_functor = xr_statistic.high_tech_master_functor

skilled_stalker_functor = xr_statistic.skilled_stalker_functor

leader_functor = xr_statistic.leader_functor

diplomat_functor = xr_statistic.diplomat_functor

research_man_functor = xr_statistic.research_man_functor

friend_of_duty_functor = xr_statistic.friend_of_duty_functor

friend_of_freedom_functor = xr_statistic.friend_of_freedom_functor

balance_advocate_functor = xr_statistic.balance_advocate_functor

wealthy_functor = xr_statistic.wealthy_functor

keeper_of_secrets_functor = xr_statistic.keeper_of_secrets_functor

marked_by_zone_functor = xr_statistic.marked_by_zone_functor

information_dealer_functor = xr_statistic.information_dealer_functor

friend_of_stalkers_functor = xr_statistic.friend_of_stalkers_functor


--------------------------------------------------------------------------------
function check_deimos_phase(actor, npc, p)
	if(p[1] and p[2]) then
		local obj = db.storage[npc:id()]
		local delta = sr_deimos.check_intensity_delta(obj)
				if(p[2]=="increasing" and delta) then
						return false
				elseif(p[2]=="decreasing" and not(delta)) then
						return false
				end
		if(p[1]=="disable_bound") then
			if(p[2]=="increasing") then
								if not(sr_deimos.check_disable_bound(obj)) then
					return true
				end
			elseif(p[2]=="decreasing") then
								return sr_deimos.check_disable_bound(obj)
			end
		elseif(p[1]=="lower_bound") then
			if(p[2]=="increasing") then
								if not(sr_deimos.check_lower_bound(obj)) then
					return true
				end
			elseif(p[2]=="decreasing") then
								return sr_deimos.check_lower_bound(obj)
			end
		elseif(p[1]=="upper_bound") then
			if(p[2]=="increasing") then
								if not(sr_deimos.check_upper_bound(obj)) then
					return true
				end
			elseif(p[2]=="decreasing") then
								return sr_deimos.check_upper_bound(obj)
			end
		end
	end
end

--------------------------------------------------------------------------------

function actor_in_surge_cover(actor, npc, p)
	return surge_manager.actor_in_cover()
end

function is_door_blocked_by_npc(actor, obj)
	return obj:is_door_blocked_by_npc()
end

function has_active_tutorial()
	return game.has_active_tutorial()
end

function upgrade_hint_kardan(actor, npc, p)
	local hint_table = {}
	local can_upgrade = 0
	local tools = (p and tonumber(p[1])) or 0

	if not has_alife_info("zat_b3_all_instruments_brought") then
		if not has_alife_info("zat_b3_tech_instrument_1_brought") and (tools == 0 or tools == 1) then
			table.insert(hint_table, "st_upgr_toolkit_1")
		elseif tools == 1 then
			can_upgrade = can_upgrade + 1
		end
		if not has_alife_info("zat_b3_tech_instrument_2_brought") and (tools == 0 or tools == 2) then
			table.insert(hint_table, "st_upgr_toolkit_2")
		elseif tools == 2 then
			can_upgrade = can_upgrade + 1
		end
		if not has_alife_info("zat_b3_tech_instrument_3_brought") and (tools == 0 or tools == 3) then
			table.insert(hint_table, "st_upgr_toolkit_3")
		elseif tools == 3 then
			can_upgrade = can_upgrade + 1
		end
	else
		can_upgrade = can_upgrade + 1
	end

	if not has_alife_info("zat_b3_tech_see_produce_62") then
		if (tools == 1) and not has_alife_info("zat_b3_tech_have_one_dose") then
			table.insert(hint_table, "st_upgr_vodka")
		elseif (tools ~= 1) and (not has_alife_info("zat_b3_tech_have_couple_dose")) then
			table.insert(hint_table, "st_upgr_vodka")
		else
			can_upgrade = can_upgrade + 1
		end
	else
		can_upgrade = can_upgrade + 1
	end

	inventory_upgrades.cur_hint = hint_table

	return can_upgrade >= 2
end
