-- ----------------------------------------------------------------------------------------------------
-- Общие функции
-- ----------------------------------------------------------------------------------------------------

-- Принудительно апдейтит логику у объектов, переданных параметром. Пока работает только с НПС
function update_npc_logic(actor, object, p)
	--printf("UPDATE NPC LOGIC %s", device():time_global())
	for k,v in pairs(p) do
		local npc = get_story_object(v)
		if npc ~= nil then
			xr_motivator.update_logic(npc)

			local planner = npc:motivation_action_manager()
			planner:update()
			planner:update()
			planner:update()

			db.storage[npc:id()].state_mgr:update()
			db.storage[npc:id()].state_mgr:update()
			db.storage[npc:id()].state_mgr:update()
			db.storage[npc:id()].state_mgr:update()
			db.storage[npc:id()].state_mgr:update()
			db.storage[npc:id()].state_mgr:update()
			db.storage[npc:id()].state_mgr:update()
		end
	end
end

function update_obj_logic(actor, object, p)
	--printf("UPDATE OBJ LOGIC %s", device():time_global())
	for k,v in pairs(p) do
		local obj = get_story_object(v)
		if obj ~= nil then

			local st = db.storage[obj:id()]
			xr_logic.try_switch_to_another_section(obj, st[st.active_scheme], actor)

--			if st.active_scheme == "sr_cutscene" then
--				st[st.active_scheme].cutscene_action
--			end

		end
	end
end

local ui_active_slot = 0

function disable_ui(actor, npc, p)
	if db.actor:is_talking() then
		db.actor:stop_talk()
	end
	level.show_weapon(false)

	if not p or (p and p[1] ~= "true") then
		local slot = db.actor:active_slot()
		if(slot~=0) then
			ui_active_slot = slot
			db.actor:activate_slot(0)
		end
	end

	level.disable_input()
	level.hide_indicators_safe()
	local hud = get_hud()
	hud:HideActorMenu()
	hud:HidePdaMenu()
	disable_actor_nightvision(nil,nil)
	disable_actor_torch(nil,nil)
end

function disable_ui_only(actor, npc)
	if db.actor:is_talking() then
		db.actor:stop_talk()
	end
	level.show_weapon(false)

	if not p or (p and p[1] ~= "true") then
		local slot = db.actor:active_slot()
		if(slot~=0) then
			ui_active_slot = slot
			db.actor:activate_slot(0)
		end
	end

	level.disable_input()
	level.hide_indicators_safe()
	local hud = get_hud()
	hud:HideActorMenu()
	hud:HidePdaMenu()
end

function enable_ui(actor, npc, p)
	--db.actor:restore_weapon()

	if not p or (p and p[1] ~= "true") then
		if ui_active_slot ~= 0 and db.actor:item_in_slot(ui_active_slot) ~= nil then
			db.actor:activate_slot(ui_active_slot)
		end
	end

	ui_active_slot = 0
	level.show_weapon(true)
	level.enable_input()
	level.show_indicators()
	enable_actor_nightvision(nil,nil)
	enable_actor_torch(nil,nil)
end

local cam_effector_playing_object_id = nil

function run_cam_effector(actor, npc, p)
	if p[1] then
		local loop, num = false, (1000 + math.random(100))
		if p[2] and type(p[2]) == "number" and p[2] > 0 then
			num = p[2]
		end
		if p[3] and p[3] == "true" then
			loop = true
		end
		--level.add_pp_effector(p[1] .. ".ppe", num, loop)
		level.add_cam_effector("camera_effects\\" .. p[1] .. ".anm", num, loop, "xr_effects.cam_effector_callback")
		cam_effector_playing_object_id = npc:id()
	end
end

function stop_cam_effector(actor, npc, p)
	if p[1] and type(p[1]) == "number" and p[1] > 0 then
		level.remove_cam_effector(p[1])
	end
end

function run_cam_effector_global(actor, npc, p)
	local num = 1000 + math.random(100)
	if p[2] and type(p[2]) == "number" and p[2] > 0 then
		 num = p[2]
	end
	local fov = device().fov
	if p[3] ~= nil and type(p[3]) == "number" then
		fov = p[3]
	end
	level.add_cam_effector2("camera_effects\\" .. p[1] .. ".anm", num, false, "xr_effects.cam_effector_callback", fov)
	cam_effector_playing_object_id = npc:id()
end

function cam_effector_callback()
	if cam_effector_playing_object_id == nil then
		printf("cam_eff:callback1!")
		return
	end
	local st   = db.storage[cam_effector_playing_object_id]
	if st == nil or st.active_scheme == nil then
		printf("cam_eff:callback2!")
		return
	end

	if st[st.active_scheme].signals == nil then
		printf("cam_eff:callback3!")
		return
	end
	st[st.active_scheme].signals["cameff_end"] = true
end

function run_postprocess(actor, npc, p)
	if (p[1]) then
		if(system_ini():section_exist(p[1])) then
			local num = 2000 + math.random(100)
			if(p[2] and type(p[2]) == "number" and p[2]>0) then
				num = p[2]
			end
			printf("adding complex effector [%s], id [%s], from [%s]", p[1], tostring(p[2]), tostring(npc:name()))
			level.add_complex_effector(p[1], num)
		else
			abort("Complex effector section is no set! [%s]", tostring(p[1]))
		end
	end
end

function stop_postprocess(actor, npc, p)
	if(p[1] and type(p[1]) == "number" and p[1]>0) then
		printf("removing complex effector id [%s] from [%s]", tostring(p[1]), tostring(npc:name()))
		level.remove_complex_effector(p[1])
	end
end

function run_tutorial(actor, npc, p)
	printf("run tutorial called")
	game.start_tutorial(p[1])
end

--[[
function run_tutorial_if_newbie(actor, npc, p)
	if has_alife_info("esc_trader_newbie") then
		game.start_tutorial(p[1])
	end
end
]]--

function jup_b32_place_scanner(actor, npc)
	for i = 1, 5 do
		if xr_conditions.actor_in_zone(actor, npc, {"jup_b32_sr_scanner_place_"..i})
			and not has_alife_info("jup_b32_scanner_"..i.."_placed") then
			db.actor:give_info_portion("jup_b32_scanner_"..i.."_placed")
			db.actor:give_info_portion("jup_b32_tutorial_done")
			remove_item(actor, npc, {"jup_b32_scanner_device"})
			spawn_object(actor, nil, {"jup_b32_ph_scanner","jup_b32_scanner_place_"..i})
		end
	end
end

function jup_b32_pda_check(actor, npc)
	pda.change_anomalies_names()
end

function pri_b306_generator_start(actor, npc)
	if xr_conditions.actor_in_zone(actor, npc, {"pri_b306_sr_generator"}) then
		give_info("pri_b306_lift_generator_used")
	end
end

function jup_b206_get_plant(actor, npc)
	if xr_conditions.actor_in_zone(actor, npc, {"jup_b206_sr_quest_line"}) then
		give_info("jup_b206_anomalous_grove_has_plant")
		give_actor(actor, npc, {"jup_b206_plant"})
		destroy_object(actor, npc, {"story", "jup_b206_plant_ph"})
	end
end

function pas_b400_switcher(actor, npc)
	if xr_conditions.actor_in_zone(actor, npc, {"pas_b400_sr_switcher"}) then
		give_info("pas_b400_switcher_use")
	end
end


function jup_b209_place_scanner(actor, npc)
	if xr_conditions.actor_in_zone(actor, npc, {"jup_b209_hypotheses"})	then
		scenario_autosave(db.actor, nil, {"st_save_jup_b209_placed_mutant_scanner"})
		db.actor:give_info_portion("jup_b209_scanner_placed")
		remove_item(actor, npc, {"jup_b209_monster_scanner"})
		spawn_object(actor, nil, {"jup_b209_ph_scanner","jup_b209_scanner_place_point"})
	end
end

function jup_b9_heli_1_searching(actor, npc)
	if xr_conditions.actor_in_zone(actor, npc, {"jup_b9_heli_1"})
		then
		db.actor:give_info_portion("jup_b9_heli_1_searching")
	end
end

function pri_a18_use_idol(actor, npc)
	if xr_conditions.actor_in_zone(actor, npc, {"pri_a18_use_idol_restrictor"})
		then
		db.actor:give_info_portion("pri_a18_run_cam")
	end
end

function jup_b8_heli_4_searching(actor, npc)
	if xr_conditions.actor_in_zone(actor, npc, {"jup_b8_heli_4"})
		then
		db.actor:give_info_portion("jup_b8_heli_4_searching")
	end
end

function jup_b10_ufo_searching(actor, npc)
	if xr_conditions.actor_in_zone(actor, npc, {"jup_b10_ufo_restrictor"})
		then
		db.actor:give_info_portion("jup_b10_ufo_memory_started")
		give_actor(db.actor,nil,{"jup_b10_ufo_memory"})
	end
end


function zat_b101_heli_5_searching(actor, npc)
	if xr_conditions.actor_in_zone(actor, npc, {"zat_b101_heli_5"})
		then
		db.actor:give_info_portion("zat_b101_heli_5_searching")
	end
end

function zat_b28_heli_3_searching(actor, npc)
	if xr_conditions.actor_in_zone(actor, npc, {"zat_b28_heli_3"})
		then
		db.actor:give_info_portion("zat_b28_heli_3_searching")
	end
end

function zat_b100_heli_2_searching(actor, npc)
	if xr_conditions.actor_in_zone(actor, npc, {"zat_b100_heli_2"})	then
		db.actor:give_info_portion("zat_b100_heli_2_searching")
	end
end

function teleport_actor(actor, npc, p)
	local point = patrol(p[1])
	local dir
	if p[2] ~= nil then
		local look = patrol(p[2])
		dir = -look:point(0):sub(point:point(0)):getH()
		db.actor:set_actor_direction(dir)
	end

	for k,v in pairs(db.no_weap_zones) do
		local zone = db.zone_by_name[k]
		if utils.npc_in_zone(db.actor, zone) then
			db.no_weap_zones[k] = true
		end
	end

	if npc and npc:name() ~= nil then
		printf("teleporting actor from [%s]", tostring(npc:name()))
	end

	db.actor:set_actor_position(point:point(0))
end


local function reset_animation(npc)
	local state_mgr = db.storage[npc:id()].state_mgr
	if state_mgr == nil then
		return
	end
	local planner = npc:motivation_action_manager()

	state_mgr.animation:set_state(nil, true)
	state_mgr.animation:set_control()
	state_mgr.animstate:set_state(nil, true)
	state_mgr.animstate:set_control()

	state_mgr:set_state("idle", nil, nil, nil, {fast_set = true})

--	planner:update()
--	planner:update()
--	planner:update()

	state_mgr:update()
	state_mgr:update()
	state_mgr:update()
	state_mgr:update()
	state_mgr:update()
	state_mgr:update()
	state_mgr:update()

	npc:set_body_state(move.standing)
	npc:set_mental_state(anim.free)

end


function teleport_npc(actor, npc, p)
	local patrol_point = p[1]
	local patrol_point_index = p[2] or 0
	if patrol_point == nil then
		abort("Wrong parameters in 'teleport_npc' function!!!")
	end
	local position = patrol(patrol_point):point(patrol_point_index)
	reset_animation(npc)

	npc:set_npc_position(position)
end

function teleport_npc_by_story_id(actor, npc, p)
	local story_id = p[1]
	local patrol_point = p[2]
	local patrol_point_index = p[3] or 0
	if story_id == nil or patrol_point == nil then
		abort("Wrong parameters in 'teleport_npc_by_story_id' function!!!")
	end
	local position = patrol(tostring(patrol_point)):point(patrol_point_index)
	local npc_id = get_story_object_id(story_id)
	if npc_id == nil then
		abort("There is no story object with id [%s]", story_id)
	end
	local cl_object = level.object_by_id(npc_id)
	if cl_object then
		reset_animation(cl_object)
		cl_object:set_npc_position(position)
	else
		alife():object(npc_id).position = position
	end
end

function teleport_squad(actor, npc, p)
	local squad_story_id = p[1]
	local patrol_point = p[2]
	local patrol_point_index = p[3] or 0
	if squad_story_id == nil or patrol_point == nil then
		abort("Wrong parameters in 'teleport_squad' function!!!")
	end
	local position = patrol(patrol_point):point(patrol_point_index)
	local squad = get_story_squad(squad_story_id)
	if squad == nil then
		abort("There is no squad with story id [%s]", squad_story_id)
	end
	squad:set_squad_position(position)
end

function jup_teleport_actor(actor, npc)
	local point_in = patrol("jup_b16_teleport_in"):point(0)
	local point_out = patrol("jup_b16_teleport_out"):point(0)
	local actor_position = actor:position()
	local out_position = vector():set(actor_position.x - point_in.x + point_out.x, actor_position.y - point_in.y + point_out.y , actor_position.z - point_in.z + point_out.z)
	db.actor:set_actor_position(out_position)
end
-----------------------------------------------------------------------------
--[[
local drop_point, drop_object = 0, 0
local function drop_object_item(item)
	drop_object:drop_item_and_teleport(item, drop_point)
end

function drop_actor_inventory(actor, npc, p)
	if p[1] then
		drop_point  = patrol(p[1]):point(0)
		drop_object = actor
		actor:inventory_for_each(drop_object_item)
	end
end


-- FIXME: drop_npc_inventory doesn't work
function drop_npc_inventory(actor, npc, p)
	if p[1] then
		drop_point  = patrol(p[1]):point(0)
		drop_object = npc
		npc:inventory_for_each(drop_object_item)
	end
end

function drop_npc_item(actor, npc, p)
	if p[1] then
		local item = npc:object(p[1])
		if item then
			npc:drop_item(item)
		end
	end
end

function drop_npc_items(actor, npc, p)
	local item = 0
	for i, v in pairs(p) do
		item = npc:object(v)
		if item then
			npc:drop_item(item)
		end
	end
end
]]--

function give_items(actor, npc, p)
	local pos, lv_id, gv_id, npc_id = npc:position(), npc:level_vertex_id(), npc:game_vertex_id(), npc:id()
	for i, v in pairs(p) do
		alife():create(v, pos, lv_id, gv_id, npc_id)
	end
end

function give_item(actor, npc, p)
	if p[2] ~= nil then
		npc_id = get_story_object_id(p[2])
	else
		npc_id = npc:id()
	end
	npc = alife():object(npc_id)
	local pos, lv_id, gv_id, npc_id = npc.position, npc.m_level_vertex_id, npc.m_game_vertex_id, npc.id
	alife():create(p[1], pos, lv_id, gv_id, npc_id)
end

function play_particle_on_path(actor, npc, p)
	local name = p[1]
	local path = p[2]
	local point_prob = p[3]
	if name == nil or path == nil then
		return
	end
	if point_prob == nil then
		point_prob = 100
	end

	local path = patrol(path)
	local count = path:count()
	for a = 0,count-1,1 do
		local particle = particles_object(name)
		if math.random(100) <= point_prob then
			particle:play_at_pos(path:point(a))
		end
	end
end


-----------------------------------------------------------------------------
--[[
send_tip(news_id:sender:sender_id)
		1. news_id
		2. sender*
		3. sender_id*
		* - not necessary
--]]
function send_tip(actor, npc, p)
	news_manager.send_tip(actor, p[1], nil, p[2], nil, p[3])
end

--[[
Дать сталкеру небольшой пинок. Например чтоб скинуть его с возвышения.
параметры: actor, npc, p[direction,bone,power,impulse,reverse=false]
		1. direction - если строка, то считается, что это имя пути и в сторону
				первой точки производится толчек. Если же это число, то оно
				рассматривается как story_id персонажа от которого должен поступить хит.
		2. bone - строка. Имя кости, по которой наносится удар.
		3. power - сила удара
		4. impulse - импульс
		5. reverse (true/false) - изменение направления удара. по умолчанию false
--]]
function hit_npc(actor, npc, p)
	local h = hit()
	local rev = p[6] and p[6] == 'true'
	h.draftsman = npc
	h.type = hit.wound
	if p[1] ~= "self" then
		local hitter = get_story_object(p[1])
		if not hitter then return end
		if rev then
			h.draftsman = hitter
			h.direction = hitter:position():sub(npc:position())
		else
			h.direction = npc:position():sub(hitter:position())
		end
	else
		if rev then
			h.draftsman = nil
			h.direction = npc:position():sub(patrol(p[2]):point(0))
		else
			h.direction = patrol(p[2]):point(0):sub(npc:position())
		end
	end
	h:bone(p[3])
	h.power = p[4]
	h.impulse = p[5]
	printf("HIT EFFECT: (%s, %s,%d,%d) health(%s)", npc:name(), p[2], h.power, h.impulse, npc.health)
	npc:hit(h)
end

--[[
Дать обьекту, заданному story_id, хит.
параметры: actor, npc, p[sid,bone,power,impulse,hit_src=npc:position()]
		1. sid - story_id обьекта, по которому наносится хит.
		2. bone - строка. Имя кости, по которой наносится удар.
		3. power - сила удара
		4. impulse - импульс
		5. hit_src - если число, то рассматривается как story_id обьекта, со стороны
				которого наносится хит (он же является и инициатором хита), иначе это
				точка (waypoint), из которой по объекту наносится хит.
				Если не задано, то берется позиция обьекта, из которого была вызвана
				данная функция.
--]]
function hit_obj(actor, npc, p)
	local h = hit()
	local obj = get_story_object(p[1])
	local sid = nil

	if not obj then
--    abort("HIT_OBJ [%s]. Target object does not exist", npc:name())
		return
	end

	h:bone(p[2])
	h.power = p[3]
	h.impulse = p[4]

	if p[5] then
		sid = get_story_object(sid)
		if sid then
			h.direction = vector():sub(sid:position(), obj:position())
		end
		if not sid then
			h.direction = vector():sub(patrol(p[5]):point(0), obj:position())
		end
	else
		h.direction = vector():sub(npc:position(), obj:position())
	end
	h.draftsman = sid or npc
	h.type = hit.wound
	obj:hit(h)
end

--[[
function hit_obj_chemical(actor, npc, p)
	local h = hit()
	local obj = get_story_object(p[1])
	local sid = nil

	if not obj then
--    abort("HIT_OBJ [%s]. Target object does not exist", npc:name())
		return
	end

	h:bone(p[2])
	h.power = p[3]
	h.impulse = p[4]

	if p[5] then
		sid = get_story_object(sid)
		if sid then
			h.direction = vector():sub(sid:position(), obj:position())
		end
		if not sid then
			h.direction = vector():sub(patrol(p[5]):point(0), obj:position())
		end
	else
		h.direction = vector():sub(npc:position(), obj:position())
	end

	h.draftsman = sid or npc
	h.type = hit.chemical_burn
	obj:hit(h)
end

function hit_obj_fire_wound(actor, npc, p)
	local h = hit()
	local obj = get_story_object(p[1])
	local sid = nil

	if not obj then
--    abort("HIT_OBJ [%s]. Target object does not exist", npc:name())
		return
	end

	h:bone(p[2])
	h.power = p[3]
	h.impulse = p[4]

	if p[5] then
		sid = get_story_object(sid)
		if sid then
			h.direction = vector():sub(sid:position(), obj:position())
		end
		if not sid then
			h.direction = vector():sub(patrol(p[5]):point(0), obj:position())
		end
	else
		h.direction = vector():sub(npc:position(), obj:position())
	end

	h.draftsman = sid or npc
	h.type = hit.fire_wound
	obj:hit(h)
end
]]--
--[[
Дать сталкеру небольшой пинок после смерти. Аналогично предыдущему, только направление хита теперь
вычисляется через убийцу. Поэтому параметра direction нет.
параметры: actor, npc, p[bone,power,impulse]
FIXME: killer:position() isn't working
--]]
function hit_by_killer(actor, npc, p)
	if not npc then return end
	local t = db.storage[npc:id()].death
	if t == nil or t.killer == -1 then return end
	local killer = db.storage[t.killer]
	if killer == nil then return end
	local p1, p2
	p1 = npc:position()
	p2 = killer:position()
	local h = hit()
	h.draftsman = npc
	h.type = hit.wound
	h.direction = utils.vector_copy_by_val(p1):sub(p2)
	h.bone = p[1]
	h.power = p[2]
	h.impulse = p[3]
	npc:hit(h)
end


function hit_npc_from_actor(actor, npc, p)
	local h = hit()
	local sid = nil
	h.draftsman = actor
	h.type = hit.wound

	if p and p[1] then
		sid = get_story_object(p[1])
		if sid then
			h.direction = actor:position():sub(sid:position())
		end
		if not sid then
			h.direction = actor:position():sub(npc:position())
		end
	else
		h.direction = actor:position():sub(npc:position())
		sid = npc
	end

	h:bone("bip01_spine")
	h.power = 0.001
	h.impulse = 0.001
	sid:hit(h)
end

--[[
-- Хитует нпс от нпс, если задан один параметр (стори айди), то нпс с таким стори айди хитнет нпс у которого вызвали эту функцию.
-- если задано 2 стори айди , то нпс с 1-ым стори айди хитнет нпс со 2-ым стори айди.
function hit_npc_from_npc(actor, npc, p)
	if p == nil then abort("Invalid parameter in function 'hit_npc_from_npc'!!!!") end
	local h = hit()
	local hitted_npc = npc
	h.draftsman = get_story_object(p[1])
	if p[2] ~= nil then
		hitted_npc = get_story_object(p[2])
	end
	h.type = hit.wound
	h.direction = h.draftsman:position():sub(hitted_npc:position())
	h:bone("bip01_spine")
	h.power = 0.03
	h.impulse = 0.03
	hitted_npc:hit(h)
end

function hit_actor(actor, npc, p)
	local h = hit()
	h.direction = vector():set(0,0,0)
	h.draftsman = actor
	h.type = hit.shock
	h:bone("bip01_spine")
	h.power = (p and p[1] and tonumber(p[1])) or 0.001
	h.impulse = 0.001
	actor:hit(h)
end
]]--

function restore_health(actor, npc)
	--printf("HEALTH RESTORE")
	npc.health = 1
end

function make_enemy(actor, npc, p)
	if p == nil then abort("Invalid parameter in function 'hit_npc_from_npc'!!!!") end
	local h = hit()
	local hitted_npc = npc
	h.draftsman = get_story_object(p[1])
	if p[2] ~= nil then
		hitted_npc = get_story_object(p[2])
	end
	h.type = hit.wound
	h.direction = h.draftsman:position():sub(hitted_npc:position())
	h:bone("bip01_spine")
	h.power = 0.03
	h.impulse = 0.03
	hitted_npc:hit(h)
end

function sniper_fire_mode(actor, npc, p)
	if p[1] == "true" then
		--printf("SNIPER FIRE MODE ON")
		npc:sniper_fire_mode(true)
	else
		--printf("SNIPER FIRE MODE OFF")
		npc:sniper_fire_mode(false)
	end
end

function kill_npc(actor, npc, p)
	if p and p[1] then
		npc = get_story_object(p[1])
	end
	if npc ~= nil and npc:alive() then
		npc:kill(npc)
	end
end

function remove_npc(actor, npc, p)
	if p and p[1] then
		npc_id = get_story_object_id(p[1])
	end
	if npc_id ~= nil then
		alife():release(alife():object(npc_id), true)
	end
end

-- прибавить к указанному счётчику актёра 1
function inc_counter(actor, npc, p)
	if p and p[1] then
		local inc_value = p[2] or 1
		local new_value = xr_logic.pstor_retrieve(actor, p[1], 0) + inc_value
		if npc and npc:name() then
			printf("inc_counter '%s'  to value [%s], by [%s]", p[1], tostring(new_value), tostring(npc:name()))
		end
		xr_logic.pstor_store(actor, p[1], new_value)
	end
end

function dec_counter(actor, npc, p)
	if p and p[1] then
		local dec_value = p[2] or 1
		local new_value = xr_logic.pstor_retrieve(actor, p[1], 0) - dec_value
		if new_value < 0 then
			new_value = 0
		end
		xr_logic.pstor_store(actor, p[1], new_value)
		if npc and npc:name() then
			printf( "dec_counter [%s] value [%s] by [%s]", p[1], xr_logic.pstor_retrieve(actor, p[1], 0), tostring(npc:name()))
		end
	end
end

function set_counter(actor, npc, p)
	if p and p[1] then
		local count = p[2] or 0
--		printf( "set_counter '%s' %s", p[1], count)
		xr_logic.pstor_store(actor, p[1], count)
--		printf("counter [%s] value [%s]", p[1], xr_logic.pstor_retrieve(actor, p[1], 0))
	end
end


------------------------------------------------------------------------------------------------------------------------
-- постпроцесс и влияние удара в морду
function actor_punch(npc)
	if db.actor:position():distance_to_sqr(npc:position()) > 4 then
		return
	end

	set_inactivate_input_time(30)
	level.add_cam_effector("camera_effects\\fusker.anm", 999, false, "")

	local active_slot = db.actor:active_slot()
	if active_slot ~= 2 and
		 active_slot ~= 3
	then
		return
	end

	local active_item = db.actor:active_item()
	if active_item then
		db.actor:drop_item(active_item)
	end
end

-- забывание обиды
function clearAbuse(npc)
	printf("CLEAR_ABUSE")
	xr_abuse.clear_abuse(npc)
end

function turn_off_underpass_lamps(actor, npc)
	local lamps_table = {
							["pas_b400_lamp_start_flash"] = true,
							["pas_b400_lamp_start_red"] = true,
							["pas_b400_lamp_elevator_green"] = true,
							["pas_b400_lamp_elevator_flash"] = true,
							["pas_b400_lamp_elevator_green_1"] = true,
							["pas_b400_lamp_elevator_flash_1"] = true,
							["pas_b400_lamp_track_green"] = true,
							["pas_b400_lamp_track_flash"] = true,
							["pas_b400_lamp_downstairs_green"] = true,
							["pas_b400_lamp_downstairs_flash"] = true,
							["pas_b400_lamp_tunnel_green"] = true,
							["pas_b400_lamp_tunnel_flash"] = true,
							["pas_b400_lamp_tunnel_green_1"] = true,
							["pas_b400_lamp_tunnel_flash_1"] = true,
							["pas_b400_lamp_control_down_green"] = true,
							["pas_b400_lamp_control_down_flash"] = true,
							["pas_b400_lamp_control_up_green"] = true,
							["pas_b400_lamp_control_up_flash"] = true,
							["pas_b400_lamp_hall_green"] = true,
							["pas_b400_lamp_hall_flash"] = true,
							["pas_b400_lamp_way_green"] = true,
							["pas_b400_lamp_way_flash"] = true,
						}
	local obj
	for k,v in pairs(lamps_table) do
		obj = get_story_object(k)

		if obj then
			obj:get_hanging_lamp():turn_off()
		else
			printf("function 'turn_off_underpass_lamps' lamp [%s] does not exist", tostring(k))
			--abort("function 'turn_off_underpass_lamps' lamp [%s] does not exist", tostring(k))
		end
	end
end

---Выключение динамической лампочки (hanging_lamp)
function turn_off(actor, npc, p)
	local obj
	for k,v in pairs(p) do
		obj = get_story_object(v)

		if not obj then
			abort("TURN_OFF. Target object with story_id [%s] does not exist", v)
			return
		end
		obj:get_hanging_lamp():turn_off()
		--printf("TURN_OFF. Target object with story_id [%s] turned off.", v)
	end
end

function turn_off_object(actor, npc)
	npc:get_hanging_lamp():turn_off()
end

---Включение динамической лампочки (hanging_lamp)
function turn_on(actor, npc, p)
	local obj
	for k,v in pairs(p) do
		obj = get_story_object(v)

		if not obj then
			abort("TURN_ON [%s]. Target object does not exist", npc:name())
			return
		end
		obj:get_hanging_lamp():turn_on()
	end
end

---Включение и запуск динамической лампочки (hanging_lamp)
function turn_on_and_force(actor, npc, p)
	local obj = get_story_object(p[1])
	if not obj then
		abort("TURN_ON_AND_FORCE. Target object does not exist")
		return
	end
	if p[2] == nil then p[2] = 55 end
	if p[3] == nil then p[3] = 14000 end
	obj:set_const_force(vector():set(0,1,0), p[2], p[3])
	obj:start_particles("weapons\\light_signal", "link")
	obj:get_hanging_lamp():turn_on()
end

---Выключение динамической лампочки и партиклов (hanging_lamp)
function turn_off_and_force(actor, npc, p)
	local obj = get_story_object(p[1])
	if not obj then
		abort("TURN_OFF [%s]. Target object does not exist", npc:name())
		return
	end
	obj:stop_particles("weapons\\light_signal", "link")
	obj:get_hanging_lamp():turn_off()
end


function turn_on_object(actor, npc)
	npc:get_hanging_lamp():turn_on()
end

function turn_off_object(actor, npc)
	npc:get_hanging_lamp():turn_off()
end


-- Вызов этой функции отключит обработчик [combat] боя для персонажа.
-- Используется в случаях, когда все необходимые действия, такие как переключение на другую секцию,
-- уже выполнены, и повторно выполнять их во время боя нельзя (а условия секции [combat] проверяются на каждом
-- апдейте, когда персонаж в бою, если, конечно, не отключены вызовом этой функции).
function disable_combat_handler(actor, npc)
	if db.storage[npc:id()].combat then
		db.storage[npc:id()].combat.enabled = false
	end

	if db.storage[npc:id()].mob_combat then
		db.storage[npc:id()].mob_combat.enabled = false
	end
end

-- Вызов этой функции отключит обработчик [combat_ignore] перехвата боя для персонажа.
function disable_combat_ignore_handler(actor, npc)
	if db.storage[npc:id()].combat_ignore then
		db.storage[npc:id()].combat_ignore.enabled = false
	end
end

-------------------------------------------------------------------------------------
-- Функции для работы с вертолётами
-------------------------------------------------------------------------------------
--[[
function heli_set_enemy_actor(actor, npc)
	local st = db.storage[npc:id()]
	if not st.combat.enemy_id and actor:alive() then
		st.combat.enemy_id = actor:id()
		heli_snd.play_snd( st, heli_snd.snd_see_enemy, 1 )
	end
end

function heli_set_enemy(actor, npc, p)
	local st  = db.storage[npc:id()]
	local obj = get_story_object( p[1] )
	if not st.combat.enemy_id and obj:alive() then
		st.combat.enemy_id = obj:id()
		heli_snd.play_snd( st, heli_snd.snd_see_enemy, 1 )
	end
end

function heli_clear_enemy(actor, npc)
	db.storage[npc:id()].combat:forget_enemy()
end
]]--

function heli_start_flame(actor, npc)
	bind_heli.heli_start_flame( npc )
end

function heli_die(actor, npc)
	bind_heli.heli_die( npc )
end


--'-----------------------------------------------------------------------------------
--' Функции для работы с погодными эффектами
--'-----------------------------------------------------------------------------------

-- Принудительная установка погодных условий
-- =set_weather(<секция погоды>:true) - установка погоды сразу, false - через некоторое время
-- Будет использоваться на старте игры Зов Припяти и в сцене jup_b15 - утро после пьянки с Зулусом
function set_weather(actor, npc, p)
	if(p[1]) then
		if(p[2]=="true") then
			level.set_weather(p[1],true)
		else
			level.set_weather(p[1],false)
		end
	end
end
--[[
function update_weather(actor, npc, p)
	if p and p[1] then
		if p[1] == "true" then
			level_weathers.get_weather_manager():select_weather(true)
		elseif p[1] == "false" then
			level_weathers.get_weather_manager():select_weather(false)
		end
	end
end

function start_small_reject(actor, npc)
	level.set_weather_fx("fx_surge_day_3")
	level.add_pp_effector("vibros_p.ppe", 1974, false)
	this.aes_earthshake(npc)
end

function start_full_reject(actor, npc)
	level.set_weather_fx("fx_surge_day_3")
	level.remove_pp_effector(1974)
	level.remove_cam_effector(1975)
	level.add_cam_effector("camera_effects\\earthquake.anm", 1975, true, "")
end

function stop_full_reject(actor, npc)
	level.remove_pp_effector(1974)
	level.remove_cam_effector(1975)
end

function run_weather_pp(actor,npc, p)
	local weather_fx = p[1]
	if weather_fx == nil then
		weather_fx = "fx_surge_day_3"
	end
	level.set_weather_fx(weather_fx)
end
]]--

function game_disconnect(actor, npc)
	local c = get_console()
	c:execute("disconnect")
--	c:execute_deferred("main_menu off")
--	c:execute_deferred("hide")
end

function game_credits(actor, npc)
	db.gameover_credits_started = true
	game.start_tutorial("credits_seq")
end

function game_over(actor, npc)
	if db.gameover_credits_started ~= true then
		return
	end
	local c = get_console()
	printf("main_menu on console command is executed")
	c:execute("main_menu on")
end

function after_credits(actor, npc)
	get_console():execute	("main_menu on")
end

function before_credits(actor, npc)
	get_console():execute	("main_menu off")
end

function on_tutor_gameover_stop()
	local c = get_console()
	printf("main_menu on console command is executed")
	c:execute("main_menu on")
end

function on_tutor_gameover_quickload()
	local c = get_console()
	c:execute("load_last_save")
end


-- для смены работы
function get_stalker_for_new_job(actor, npc, p)
	xr_gulag.find_stalker_for_job(npc,p[1])
end
function switch_to_desired_job(actor, npc, p)
	xr_gulag.switch_to_desired_job(npc)
end

--[[
function death_hit(actor, npc, p)
	 local draftsman = get_story_object (p[1])
	 local hitted_obj = (p[2] ~= nil and get_story_object (p[2])) or npc
	 if draftsman == nil or hitted_obj == nil then
		return
	 end
	 local h = hit()
	 h.power = 1000
	 h.direction = hitted_obj:direction()
	 h.draftsman = draftsman
	 h.impulse = 1
	 h.type = hit.wound
	 hitted_obj:hit(h)
end
]]--

--'-----------------------------------------------------------------------------------
--' Функции для работы с подспауном
--'-----------------------------------------------------------------------------------
function spawn_object(actor, obj, p)
		--' p[1] - секция кого спаунить
		--' p[2] - имя патрульного пути где спа унить.
	local spawn_sect = p[1]
	if spawn_sect == nil then
		abort("Wrong spawn section for 'spawn_object' function %s. For object %s", tostring(spawn_sect), obj:name())
	end

	local path_name = p[2]
	if path_name == nil then
		abort("Wrong path_name for 'spawn_object' function %s. For object %s", tostring(path_name), obj:name())
	end

	if not level.patrol_path_exists(path_name) then
		abort("Path %s doesnt exist. Function 'spawn_object' for object %s ", tostring(path_name), obj:name())
	end
	local ptr = patrol(path_name)
	local index = p[3] or 0
	local yaw = p[4] or 0

	--' printf("Spawning %s at %s, %s", tostring(p[1]), tostring(p[2]), tostring(p[3]))
	local se_obj = alife():create(spawn_sect,
								ptr:point(index),
								ptr:level_vertex_id(0),
								ptr:game_vertex_id(0))
	if IsStalker( nil, se_obj:clsid()) then
		se_obj:o_torso().yaw = yaw * math.pi / 180
	elseif se_obj:clsid() == clsid.script_phys then
		se_obj:set_yaw(yaw * math.pi / 180)
	end
end

local jup_b219_position
local jup_b219_lvid
local jup_b219_gvid

function jup_b219_save_pos()
	local obj = get_story_object("jup_b219_gate_id")
	if obj and obj:position() then
		jup_b219_position = obj:position()
		jup_b219_lvid = obj:level_vertex_id()
		jup_b219_gvid = obj:game_vertex_id()
	else
		return
	end
	sobj = alife():object(obj:id())
	if sobj then
		alife():release(sobj, true)
	end
end

function jup_b219_restore_gate()
	local yaw = 0
	local spawn_sect = "jup_b219_gate"
	if jup_b219_position then
		local se_obj = alife():create(spawn_sect,
									vector():set(jup_b219_position),
									jup_b219_lvid,
									jup_b219_gvid)
		se_obj:set_yaw(yaw * math.pi / 180)
	end
end

function spawn_corpse(actor, obj, p)
		--' p[1] - секция кого спаунить
		--' p[2] - имя патрульного пути где спаунить.
	local spawn_sect = p[1]
	if spawn_sect == nil then
		abort("Wrong spawn section for 'spawn_corpse' function %s. For object %s", tostring(spawn_sect), obj:name())
	end

	local path_name = p[2]
	if path_name == nil then
		abort("Wrong path_name for 'spawn_corpse' function %s. For object %s", tostring(path_name), obj:name())
	end

	if not level.patrol_path_exists(path_name) then
		abort("Path %s doesnt exist. Function 'spawn_corpse' for object %s ", tostring(path_name), obj:name())
	end
	local ptr = patrol(path_name)
	local index = p[3] or 0

	local se_obj = alife():create(spawn_sect,
									ptr:point(index),
									ptr:level_vertex_id(0),
									ptr:game_vertex_id(0))
	se_obj:kill()
end


function spawn_object_in(actor, obj, p)
	--' p[1] - секция кого спаунить
	--' p[2] - стори айди обьекта в который спавнить
	local spawn_sect = p[1]
	if spawn_sect == nil then
		abort("Wrong spawn section for 'spawn_object' function %s. For object %s", tostring(spawn_sect), obj:name())
	end
	if p[2] == nil then
		abort("Wrong target_name for 'spawn_object_in' function %s. For object %s", tostring(target_name), obj:name())
	end
--	local box = alife():object(target_name)
--	if(box==nil) then

	printf("trying to find object %s", tostring(p[2]))

	local target_obj_id = get_story_object_id(p[2])
	if target_obj_id ~= nil then
		box = alife():object(target_obj_id)
		if box == nil then
			abort("There is no such object %s", p[2])
		end
		alife():create(spawn_sect,vector(),0,0,target_obj_id)
	else
		abort("object is nil %s", tostring(p[2]))
	end
end


function spawn_npc_in_zone(actor, obj, p)
	--' p[1] - секция кого спаунить
	--' p[2] - имя зоны в которой спаунить.
	local spawn_sect = p[1]
	if spawn_sect == nil then
		abort("Wrong spawn section for 'spawn_object' function %s. For object %s", tostring(spawn_sect), obj:name())
	end
	local zone_name = p[2]
	if zone_name == nil then
		abort("Wrong zone_name for 'spawn_object' function %s. For object %s", tostring(zone_name), obj:name())
	end
	if db.zone_by_name[zone_name] == nil then
		abort("Zone %s doesnt exist. Function 'spawn_object' for object %s ", tostring(zone_name), obj:name())
	end
	local zone = db.zone_by_name[zone_name]
--	printf("spawn_npc_in_zone: spawning %s at zone %s, squad %s", tostring(p[1]), tostring(p[2]), tostring(p[3]))
	local spawned_obj = alife():create( spawn_sect,
										zone:position(),
										zone:level_vertex_id(),
										zone:game_vertex_id())
	spawned_obj.sim_forced_online = true
	spawned_obj.squad = 1 or p[3]
	db.script_ids[spawned_obj.id] = zone_name
end

function destroy_object(actor, obj, p)
	local sobj
	if p == nil then
		sobj = alife():object(obj:id())
	else
		if p[1] == nil or p[2] == nil then
			abort("Wrong parameters in destroy_object function!!!")
		end
		local target_str = nil
		if p[3] ~= nil then
			target_str = p[1].."|"..p[2]..","..p[3]
		else
			target_str = p[1].."|"..p[2]
		end
		local target_position, target_id, target_init = xr_remark.init_target(obj, target_str)
		if target_id == nil then
            printf("You are trying to set non-existant target [%s] for object [%s] in section [%s]", tostring(target_str), tostring(obj:name()), tostring(db.storage[obj:id()].active_section))
		end
		sobj = alife():object(target_id)
	end
	if sobj == nil then
		return
	end
	printf("releasing object ["..sobj:name().."]")
	alife():release(sobj, true)
end

function give_actor(actor, npc, p)
	for k,v in pairs(p) do
		alife():create(v,
				db.actor:position(),
				db.actor:level_vertex_id(),
				db.actor:game_vertex_id(),
				db.actor:id())
		news_manager.relocate_item(db.actor, "in", v)
	end
end

function activate_weapon_slot(actor, npc, p)
	db.actor:activate_slot(p[1])
end

function anim_obj_forward(actor, npc, p)
	for k,v in pairs(p) do
		if v ~= nil then
			db.anim_obj_by_name[v]:anim_forward()
		end
	end
end
function anim_obj_backward(actor, npc, p)
	if p[1] ~= nil then
		db.anim_obj_by_name[p[1]]:anim_backward()
	end
end
function anim_obj_stop(actor, npc, p)
	if p[1] ~= nil then
		db.anim_obj_by_name[p[1]]:anim_stop()
	end
end

-- Функции для работы с огненными зонами.
--[[
function turn_on_fire_zone(actor, npc, p)
	bind_campfire.fire_zones_table[ p[1] ]:turn_on()
end

function turn_off_fire_zone(actor, npc, p)
	bind_campfire.fire_zones_table[ p[1] ]:turn_off()
end
]]--
--'-----------------------------------------------------------------------------------
--' Функции для отыгрывания звука
--'-----------------------------------------------------------------------------------
function play_sound(actor, obj, p)
	local theme = p[1]
	local faction = p[2]
	local point = sim_board.get_sim_board().smarts_by_names[p[3]]
	if point ~= nil then
		point = point.id
	elseif p[3]~=nil then
		point = p[3]
	end

	if obj and IsStalker(obj) then
		if not obj:alive() then
			abort("Stalker [%s][%s] is dead, but you wants to say something for you: [%s]!", tostring(obj:id()), tostring(obj:name()), p[1])
		end
	end

	xr_sound.set_sound_play(obj:id(), theme, faction, point)
end

function play_sound_by_story(actor, obj, p)
	local story_obj = get_story_object_id(p[1])
	local theme = p[2]
	local faction = p[3]
	local point = sim_board.get_sim_board().smarts_by_names[p[4]]
	if point ~= nil then
		point = point.id
	elseif p[4]~=nil then
		point = p[4]
	end
	xr_sound.set_sound_play(story_obj, theme, faction, point)
end

function stop_sound(actor, npc)
	xr_sound.stop_sounds_by_id(npc:id())
end

function play_sound_looped(actor, obj, p)
	local theme = p[1]
	xr_sound.play_sound_looped(obj:id(), theme)
end

function stop_sound_looped(actor, obj)
	xr_sound.stop_sound_looped(obj:id())
end

function barrel_explode (actor , npc , p)
	local expl_obj = get_story_object (p[1])
	if expl_obj ~= nil then
		expl_obj:explode(0)
	end
end

--'-----------------------------------------------------------------------------------
--' Alife support
--'-----------------------------------------------------------------------------------
--[[
function start_sim(actor, obj)
	sim_board.get_sim_board():start_sim()
end

function stop_sim(actor, obj)
	sim_board.get_sim_board():stop_sim()
end

function update_faction_brain(actor, obj, p)
	if p[1] == nil then
		abort("Wrong parameters update_faction_brain")
	end
	local board = sim_board.get_sim_board()
	local player = board.players[ p[1] ]
	if player == nil then
		abort("Can't find player %s", tostring(p[1]))
	end
	player:faction_brain_update()
end
]]--

function create_squad(actor, obj, p)
	if obj ~= nil then
		printf("pl:creating_squad from obj [%s] in section [%s]", tostring(obj:name()), tostring(db.storage[obj:id()].active_section))
	end
	local squad_id = p[1]
	if squad_id == nil then
		abort("Wrong squad identificator [NIL] in create_squad function")
	end
	local smart_name = p[2]
	if smart_name == nil then
		abort("Wrong smart name [NIL] in create_squad function")
	end

	local ltx = sim_board.squad_ltx

	if not ltx:section_exist(squad_id) then
		abort("Wrong squad identificator [%s]. Squad descr doesnt exist.", tostring(squad_id))
	end

	local board = sim_board.get_sim_board()
	local smart = board.smarts_by_names[smart_name]
	if smart == nil then
		abort("Wrong smart_name [%s] for [%s] faction in create_squad function", tostring(smart_name), tostring(player_name))
	end

	local squad = board:create_squad(smart, squad_id)


	board:enter_smart(squad, smart.id)

	for k in squad:squad_members() do
		board:setup_squad_and_group(k.object)
	end

	squad:update()
end

function create_squad_member(actor, obj, p)
	local squad_member_sect = p[1]
	local story_id			= p[2]
	local position			= nil
	local level_vertex_id	= nil
	local game_vertex_id	= nil
	if story_id == nil then
		abort("Wrong squad identificator [NIL] in 'create_squad_member' function")
	end
	local board = sim_board.get_sim_board()
	local squad = get_story_squad(story_id)
	local squad_smart = board.smarts[squad.smart_id].smrt
	if p[3] ~= nil then
		local spawn_point
		if p[3] == "simulation_point" then
			spawn_point = utils.cfg_get_string(sim_board.squad_ltx, squad:section_name(), "spawn_point", obj, false, "")
			if spawn_point == "" or spawn_point == nil then
				spawn_point = xr_logic.parse_condlist(obj, "spawn_point", "spawn_point", squad_smart.spawn_point)
			else
				spawn_point = xr_logic.parse_condlist(obj, "spawn_point", "spawn_point", spawn_point)
			end
			spawn_point = xr_logic.pick_section_from_condlist(db.actor, obj, spawn_point)
		else
			spawn_point = p[3]
		end
		position 		= patrol(spawn_point):point(0)
		level_vertex_id = patrol(spawn_point):level_vertex_id(0)
		game_vertex_id 	= patrol(spawn_point):game_vertex_id(0)
	else
		local commander = alife():object(squad:commander_id())
		position		= commander.position
		level_vertex_id = commander.m_level_vertex_id
		game_vertex_id	= commander.m_game_vertex_id
	end
	local new_member_id = squad:add_squad_member(squad_member_sect, position,  level_vertex_id, game_vertex_id)
	squad:assign_squad_member_to_smart(new_member_id, squad_smart)
	board:setup_squad_and_group(alife():object(new_member_id))
	--squad_smart:refresh()
	squad:update()
end

function remove_squad(actor, obj, p)
	local story_id = p[1]
	if story_id == nil then
		abort("Wrong squad identificator [NIL] in remove_squad function")
	end
	local squad = get_story_squad(story_id)
	if squad == nil then
		assert("Wrong squad identificator [%s]. squad doesnt exist", tostring(story_id))
		return
	end
	local board = sim_board.get_sim_board()
	board:remove_squad(squad)
end

function kill_squad(actor, obj, p)
	local story_id = p[1]
	if story_id == nil then
		abort("Wrong squad identificator [NIL] in kill_squad function")
	end
	local squad = get_story_squad(story_id)
	if squad == nil then
		return
	end
	local squad_npcs = {}
	for k in squad:squad_members() do
		squad_npcs[k.id] = true
	end

	for k,v in pairs(squad_npcs) do
		local cl_obj = db.storage[k] and db.storage[k].object
		if cl_obj == nil then
			alife():object(tonumber(k)):kill()
		else
			cl_obj:kill(cl_obj)
		end
	end
end

function heal_squad(actor, obj, p)
	local story_id = p[1]
	local health_mod = 1
	if p[2] and p[2] ~= nil then
		health_mod = math.ceil(p[2]/100)
	end
	if story_id == nil then
		abort("Wrong squad identificator [NIL] in heal_squad function")
	end
	local squad = get_story_squad(story_id)
	if squad == nil then
		return
	end
	for k in squad:squad_members() do
		local cl_obj = db.storage[k.id] and db.storage[k.id].object
		if cl_obj ~= nil then
			cl_obj.health = health_mod
		end
	end
end

--[[
function update_squad(actor, obj, p)
	local squad_id = p[1]
	if squad_id == nil then
		abort("Wrong squad identificator [NIL] in remove_squad function")
	end
	local board = sim_board.get_sim_board()
	local squad = board.squads[squad_id]
	if squad == nil then
		assert("Wrong squad identificator [%s]. squad doesnt exist", tostring(squad_id))
		return
	end
	squad:update()
end
]]--

function clear_smart_terrain(actor, obj, p)
	local smart_name = p[1]
	if smart_name == nil then
		abort("Wrong squad identificator [NIL] in clear_smart_terrain function")
	end

	local board = sim_board.get_sim_board()
	local smart = board.smarts_by_names[smart_name]
	local smart_id = smart.id
	for k,v in pairs(board.smarts[smart_id].squads) do
		if p[2] and p[2] == "false" then
			if not get_object_story_id(v.id) then
				board:exit_smart(v, smart_id)
				board:remove_squad(v)
			end
		else
			board:exit_smart(v, smart_id)
			board:remove_squad(v)
		end
	end
end

--[[
function set_actor_faction(actor, obj, p)
	if p[1] == nil then
		abort("Wrong parameters")
	end
	sim_board.get_sim_board():set_actor_community(p[1])
end
]]--
--'-----------------------------------------------------------------------------------
--' Quest support
--'-----------------------------------------------------------------------------------
function give_task(actor, obj, p)
	if p[1] == nil then
		abort("No parameter in give_task function.")
	end
	task_manager.get_task_manager():give_task(p[1])
end

function set_active_task(actor, npc, p)
	if(p[1]) then
		local t = db.actor:get_task(tostring(p[1]), true)
		if(t) then
			db.actor:set_active_task(t)
		end
	end
end

-- Функции для работы с отношениями

function actor_friend(actor, npc)
	printf("_bp: xr_effects: actor_friend(): npc='%s': time=%d", npc:name(), time_global())
	npc:force_set_goodwill( 1000, actor)
end

function actor_neutral(actor, npc)
	npc:force_set_goodwill( 0, actor)
end

function actor_enemy(actor, npc)
	npc:force_set_goodwill( -1000, actor)
end

function set_squad_neutral_to_actor(actor, npc, p)
	local story_id = p[1]
	local squad = get_story_squad(story_id)
	if squad == nil then
		printf("There is no squad with id[%s]", tostring(story_id))
		return
	end
	squad:set_squad_relation("neutral")
end

function set_squad_friend_to_actor(actor, npc, p)
	local story_id = p[1]
	local squad = get_story_squad(story_id)
	if squad == nil then
		printf("There is no squad with id[%s]", tostring(story_id))
		return
	end
	squad:set_squad_relation("friend")
end

--Сделать актера врагом к отряду, передается имя отряда
function set_squad_enemy_to_actor( actor, npc, p)
	local story_id = p[1]
	local squad = get_story_squad(story_id)
	if squad == nil then
		printf("There is no squad with id[%s]", tostring(story_id))
		return
	end
	squad:set_squad_relation("enemy")
end

--[[
function set_friends(actor, npc, p)
	local npc1
	for i, v in pairs(p) do
		npc1 = get_story_object(v)
		if npc1 and npc1:alive() then
			--printf("_bp: %d:set_friends(%d)", npc:id(), npc1:id())
			npc:set_relation(game_object.friend, npc1)
			npc1:set_relation(game_object.friend, npc)
		end
	end
end

function set_enemies(actor, npc, p)
	local npc1
	for i, v in pairs(p) do
		--printf("_bp: set_enemies(%d)", v)
		npc1 = get_story_object(v)
		if npc1 and npc1:alive() then
			npc:set_relation(game_object.enemy, npc1)
			npc1:set_relation(game_object.enemy, npc)
		end
	end
end

function set_gulag_relation_actor(actor, npc, p)
	if(p[1]) and (p[2]) then
		game_relations.set_gulag_relation_actor(p[1], p[2])
	end
end

function set_factions_community(actor, npc, p)
	if(p[1]~=nil) and (p[2]~=nil) and (p[3]~=nil) then
		game_relations.set_factions_community(p[1], p[2], p[3])
	end
end

function set_squad_community_goodwill(actor, npc, p)
	if(p[1]~=nil) and (p[2]~=nil) and (p[3]~=nil) then
		game_relations.set_squad_community_goodwill(p[1], p[2], p[3])
	end
end
]]--

--sets NPC relation to actor
--set_npc_sympathy(number)
--call only from npc`s logic
function set_npc_sympathy(actor, npc, p)
	if(p[1]~=nil) then
		game_relations.set_npc_sympathy(npc, p[1])
	end
end

--sets SQUAD relation to actor
--set_squad_goodwill(faction:number)
function set_squad_goodwill(actor, npc, p)
	if(p[1]~=nil) and (p[2]~=nil) then
		game_relations.set_squad_goodwill(p[1], p[2])
	end
end

function set_squad_goodwill_to_npc(actor, npc, p)
	if(p[1]~=nil) and (p[2]~=nil) then
		game_relations.set_squad_goodwill_to_npc(npc, p[1], p[2])
	end
end

function inc_faction_goodwill_to_actor(actor, npc, p)
	local community = p[1]
	local delta		= p[2]
	if delta and community then
		game_relations.change_factions_community_num(community,actor:id(), tonumber(delta))
	else
		abort("Wrong parameters in function 'inc_faction_goodwill_to_actor'")
	end
end

function dec_faction_goodwill_to_actor(actor, npc, p)
	local community = p[1]
	local delta		= p[2]
	if delta and community then
		game_relations.change_factions_community_num(community,actor:id(), -tonumber(delta))
	else
		abort("Wrong parameters in function 'dec_faction_goodwill_to_actor'")
	end
end


--[[
function add_custom_static(actor, npc, p)
	if p[1] ~= nil and p[2] ~= nil then
		get_hud():AddCustomStatic(p[1], true)
		get_hud():GetCustomStatic(p[1]):wnd():SetTextST(p[2])
	else
		abort("Invalid parameters in function add_custom_static!!!")
	end
end

function remove_custom_static(actor, npc, p)
	if p[1] ~= nil then
		get_hud():RemoveCustomStatic(p[1])
	else
		abort("Invalid parameters in function remove_custom_static!!!")
	end
end
]]--

function kill_actor(actor, npc)
	db.actor:kill(db.actor)
end

-----------------------------------------------------------------------
--  Treasures support
-----------------------------------------------------------------------
function give_treasure (actor, npc, p)
	if p == nil then
		abort("Required parameter is [NIL]")
	end
	for k,v in pairs(p) do
		treasure_manager.get_treasure_manager():give_treasure(v)
	end
end

--[[
function change_tsg(actor, npc, p)
	npc:change_team(p[1], p[2], p[3])
end

function exit_game(actor, npc)
	get_console():execute("quit")
end
]]--

function start_surge(actor, npc, p)
	surge_manager.start_surge(p)
end

function stop_surge(actor, npc, p)
	surge_manager.stop_surge()
end

function set_surge_mess_and_task(actor, npc, p)
	if(p) then
		surge_manager.set_surge_message(p[1])
		if(p[2]) then
			surge_manager.set_surge_task(p[2])
		end
	end
end

--[[
function enable_level_changer(actor, npc, p)
	if(p[1]~=nil) then
		local obj = get_story_object(p[1])
		if(obj) then
			if db.storage[obj:id()] and db.storage[obj:id()].s_obj then
				db.storage[obj:id()].s_obj.enabled = true
				db.storage[obj:id()].s_obj.hint = "level_changer_invitation"
			else
				return
			end
			obj:enable_level_changer(true)
			level_tasks.add_lchanger_location()
			obj:set_level_changer_invitation("level_changer_invitation")
		end
	end
end

function disable_level_changer(actor, npc, p)
	if(p[1]~=nil) then
		local obj = get_story_object(p[1])
		if(obj) then
			if not(db.storage[obj:id()] and db.storage[obj:id()].s_obj) then
				return
			end
			obj:enable_level_changer(false)
			level_tasks.del_lchanger_mapspot(tonumber(p[1]))
			db.storage[obj:id()].s_obj.enabled = false
			if(p[2]==nil) then
				obj:set_level_changer_invitation("level_changer_disabled")
				db.storage[obj:id()].s_obj.hint = "level_changer_disabled"
			else
				obj:set_level_changer_invitation(p[2])
				db.storage[obj:id()].s_obj.hint = p[2]
			end
		end
	end
end

function change_actor_community(actor, npc, p)
	if(p[1]~=nil) then
		db.actor:set_character_community(p[1], 0, 0)
	end
end

function set_faction_community_to_actor(actor, npc, p)
-- run_string xr_effects.change_actor_community(nil,nil,{"actor_dolg"})
	if(p[1]~=nil) and (p[2]~=nil) then
		local rel = 0
		if(p[2]=="enemy") then
			rel = -3000
		elseif(p[2]=="friend") then
			rel = 1000
		end
		db.actor:set_community_goodwill(p[1], rel)
	end
end

function disable_collision(actor, npc)
	npc:wounded(true)
end
function enable_collision(actor, npc)
	npc:wounded(false)
end

function disable_actor_collision(actor, npc)
	actor:wounded(true)
end
function enable_actor_collision(actor, npc)
	actor:wounded(false)
end

function relocate_actor_inventory_to_box(actor, npc, p)
	local function transfer_object_item(item)
		if item:section() ~= "wpn_binoc" and item:section() ~= "wpn_knife" and item:section() ~= "device_torch" then
			db.actor:transfer_item(item, inv_box_1)
		end
	end
	inv_box_1 = get_story_object (p[1])
	actor:inventory_for_each(transfer_object_item)
end
]]--

function set_level_faction_community(actor, npc, p)
	if(p[1]~=nil) and (p[2]~= nil) and (p[3]~= nil) then
		local faction = sim_board.get_sim_board().players[p[1]]
		local goodwill = 0
		if(p[3]=="enemy") then
			goodwill = -3000
		elseif(p[3]=="friend") then
			goodwill = 1000
		end
		for k,v in pairs(faction.squads) do
			local squad_level = alife():level_name(game_graph():vertex(alife():object(v:commander_id()).m_game_vertex_id):level_id())
			if(squad_level==p[2]) then
				for kk in v:squad_members() do
					local npc = kk.object
					local tbl = game_relations.temp_goodwill_table
					if(tbl.communities==nil) then
						tbl.communities = {}
					end
					if(tbl.communities[p[1]]==nil) then
						tbl.communities[p[1]] = {}
					end
					tbl.communities[p[1]][npc.id] = goodwill
					if(db.storage[npc.id]~=nil) then
						game_relations.set_level_faction_community(db.storage[npc.id].object)
					end
				end
			end
		end
	end
end

--[[
function make_actor_visible_to_npc(actor,npc,p)
	npc:make_object_visible_somewhen(db.actor)
end
]]--

function make_actor_visible_to_squad(actor,npc,p)
	local story_id = p and p[1]
	local squad = get_story_squad(story_id)
	if squad == nil then abort("There is no squad with id[%s]", story_id) end
	for k in squad:squad_members() do
		local obj = level.object_by_id(k.id)
		if obj ~= nil then
			obj:make_object_visible_somewhen( db.actor )
		end
	end
end

function stop_sr_cutscene(actor,npc,p)
	local obj = db.storage[npc:id()]
	if(obj.active_scheme~=nil) then
		obj[obj.active_scheme].signals["cam_effector_stop"] = true
	end
end

--[[
function reset_dialog_end_signal(actor, npc, p)
	local st = db.storage[npc:id()]
	if(st.active_scheme==nil) then
		return
	end
	if(st[st.active_scheme].signals==nil) then
		return
	end
	st[st.active_scheme].signals["dialog_end"] = nil
end

function add_map_spot(actor, npc, p)
	if(p[1]==nil) then
		abort("Story id for add map spot function is not set")
	else
		local story_id = tonumber(p[1])
		local id = id_by_sid(story_id)
		if(id==nil) then
			local obj = alife():object(p[1])
			id = obj and obj.id
		end
		if(id~=nil) then
			if(p[2]==nil) then
				p[2] = "primary_task_location"
			end
			if(p[3]==nil) then
				p[3] = "default"
			end
			if level.map_has_object_spot(id, p[2]) == 0 then
				level.map_add_object_spot_ser(id, p[2], p[3])
			end
		else
			abort("Wrong story id or name [%s] for map spot function", tostring(story_id))
		end
	end
end

function remove_map_spot(actor, npc, p)
	if(p[1]==nil) then
		abort("Story id for add map spot function is not set")
	else
		local story_id = tonumber(p[1])
		local id = id_by_sid(story_id)
		if(id==nil) then
			local obj = alife():object(p[1])
			id = obj and obj.id
		end
		if(id~=nil) then
			if(p[2]==nil) then
				p[2] = "primary_task_location"
			end
			if level.map_has_object_spot(id, p[2]) ~= 0 then
				level.map_remove_object_spot(id, p[2])
			end
		else
			abort("Wrong story id or name [%s] for map spot function", tostring(story_id))
		end
	end
end
]]--

-- Anomal fields support
function enable_anomaly(actor, npc, p)
	if p[1] == nil then
		abort("Story id for enable_anomaly function is not set")
	end

	local obj = get_story_object(p[1])
	if not obj then
		abort("There is no object with story_id %s for enable_anomaly function", tostring(p[1]))
	end
	obj:enable_anomaly()
end

function disable_anomaly(actor, npc, p)
	if p[1] == nil then
		abort("Story id for disable_anomaly function is not set")
	end

	local obj = get_story_object(p[1])
	if not obj then
		abort("There is no object with story_id %s for disable_anomaly function", tostring(p[1]))
	end
	obj:disable_anomaly()
end

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

--[[
function reset_faction_goodwill(actor, obj, p)
	if db.actor and p[1] then
		local board = sim_board.get_sim_board()
		local faction = board.players[ p[1] ]
		if faction then
			db.actor:set_community_goodwill(p[1], 0)
		end
	end
end
]]--

function add_cs_text(actor, npc, p)
	if p[1] then
		local hud = get_hud()
		local cs_text = hud:GetCustomStatic("text_on_screen_center")
		if cs_text then
			hud:RemoveCustomStatic("text_on_screen_center")
		end
		hud:AddCustomStatic("text_on_screen_center", true)
		cs_text = hud:GetCustomStatic("text_on_screen_center")
		cs_text:wnd():TextControl():SetText(game.translate_string(p[1]))
	end
end

function del_cs_text(actor, npc, p)
	local hud = get_hud()
	cs_text = hud:GetCustomStatic("text_on_screen_center")
	if cs_text then
		hud:RemoveCustomStatic("text_on_screen_center")
	end
end

function spawn_item_to_npc(actor, npc, p)
	local new_item = p[1]
	if p[1] then
		alife():create(new_item,
		npc:position(),
		npc:level_vertex_id(),
		npc:game_vertex_id(),
		npc:id())
	end
end

function give_money_to_npc(actor, npc, p)
	local money = p[1]
	if p[1] then
		npc:give_money(money)
	end
end

function seize_money_to_npc(actor, npc, p)
	local money = p[1]
	if p[1] then
		npc:give_money(-money)
	end
end

-- Передача предмета от непися к неписю
-- relocate_item(item_name:story_id_from:story_id_to)
function relocate_item(actor, npc, p)
	local item = p and p[1]
	local from_obj = p and get_story_object(p[2])
	local to_obj = p and get_story_object(p[3])
	if to_obj ~= nil then
		if from_obj ~= nil and from_obj:object(item) ~= nil then
			from_obj:transfer_item(from_obj:object(item), to_obj)
		else
			alife():create(item,
				to_obj:position(),
				to_obj:level_vertex_id(),
				to_obj:game_vertex_id(),
				to_obj:id())
		end
	else
		abort("Couldn't relocate item to NULL")
	end
end

-- Сделать сквады врагами, передаются два сквада set_squads_enemies(squad_name_1:squad_name_2)
function set_squads_enemies(actor, npc, p)
	if (p[1] == nil or p[2] == nil) then
		abort("Wrong parameters in function set_squad_enemies")
		return
	end

	local squad_1 = get_story_squad(p[1])
	local squad_2 = get_story_squad(p[2])

	if squad_1 == nil then
		assert("There is no squad with id[%s]", tostring(p[1]))
		return
	end
	if squad_2 == nil then
		assert("There is no squad with id[%s]", tostring(p[2]))
		return
	end

 	for k in squad_1:squad_members() do
		local npc_obj_1 = db.storage[k.id] and db.storage[k.id].object
		if npc_obj_1 ~= nil then
			for kk in squad_2:squad_members() do
				local npc_obj_2 = db.storage[kk.id] and db.storage[kk.id].object
				if npc_obj_2 ~= nil then
					npc_obj_1:set_relation(game_object.enemy, npc_obj_2)
					npc_obj_2:set_relation(game_object.enemy, npc_obj_1)
					printf("set_squads_enemies: %d:set_enemy(%d)", npc_obj_1:id(), npc_obj_2:id())
				end
			end
		end
	end
end

local particles_table = {
[1] = {particle = particles_object("anomaly2\\teleport_out_00"), sound = sound_object("anomaly\\teleport_incoming")},
[2] = {particle = particles_object("anomaly2\\teleport_out_00"), sound = sound_object("anomaly\\teleport_incoming")},
[3] = {particle = particles_object("anomaly2\\teleport_out_00"), sound = sound_object("anomaly\\teleport_incoming")},
[4] = {particle = particles_object("anomaly2\\teleport_out_00"), sound = sound_object("anomaly\\teleport_incoming")},
}

function jup_b16_play_particle_and_sound(actor, npc, p)
	particles_table[p[1]].particle :play_at_pos(patrol(npc:name().."_particle"):point(0))
	--particles_table[p[1]].sound    :play_at_pos(actor, patrol(npc:name().."_particle"):point(0), 0, sound_object.s3d)
end
--Функция установки состояния видимости кровососа.
-- Возможный набор параметров --> story_id:visibility_state(можно вызывать откуда угодно) или visibility_state(если вызывается из кастомдаты кровососа)
--  visibility_state -->
--						0 - невидимый
--						1 - полувидимый
--						2 - полностью видимый
function set_bloodsucker_state(actor, npc, p)
	if (p and p[1]) == nil then abort("Wrong parameters in function 'set_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
		if state == "default" then
			npc:force_visibility_state(-1)
		else
			npc:force_visibility_state(tonumber(state))
		end
	end
end

--Функция вставки предмета в определенную точку, сделал для сцены б57
function drop_object_item_on_point(actor, npc, p)
	local drop_object = db.actor:object(p[1])
	local drop_point  = patrol(p[2]):point(0)
	db.actor:drop_item_and_teleport(drop_object, drop_point)
end

--Функция отнятия предмета у игрока
function remove_item(actor, npc, p)
	if (p and p[1]) == nil then abort("Wrong parameters in function 'remove_item'!!!") end
	local item = p[1]

	local obj = db.actor:object(item)
	if obj ~= nil then
		alife():release(alife():object(obj:id()), true)
	else
		abort("Actor has no such item!")
	end
	news_manager.relocate_item(db.actor, "out", item)
end

-- Сюжетное сохранение в важных местах
function scenario_autosave(actor, npc, p)
	local save_name = p[1]
	if save_name == nil then
		abort("You are trying to use scenario_autosave without save name")
	end

	if IsImportantSave() then
		local save_param = user_name().." - "..game.translate_string(save_name)

		get_console():execute("save "..save_param)
	end
end



































function zat_b29_create_random_infop(actor, npc, p)
	if p[2] == nil then
		abort("Not enough parameters for zat_b29_create_random_infop!")
	end

	local amount_needed = p[1]
	local current_infop = 0
	local total_infop = 0

	if (not amount_needed or amount_needed == nil) then
		amount_needed = 1
	end

	for k,v in pairs(p) do
		if k > 1 then
			total_infop = total_infop + 1
			disable_info(v)
		end
	end

	if amount_needed > total_infop then
		amount_needed = total_infop
	end

	for i = 1, amount_needed do
		current_infop = math.random(1, total_infop)
		for k,v in pairs(p) do
			if k > 1 then
				if (k == current_infop + 1 and (not has_alife_info(v))) then
					db.actor:give_info_portion(v)
					break
				end
			end
		end
	end
end

function give_item_b29(actor, npc, p)
--	local story_object = p and get_story_object(p[1])
	local az_name
	local az_table = {
						"zat_b55_anomal_zone",
						"zat_b54_anomal_zone",
						"zat_b53_anomal_zone",
						"zat_b39_anomal_zone",
						"zaton_b56_anomal_zone",
						}

	for i = 16, 23 do
		if has_alife_info(dialogs_zaton.zat_b29_infop_bring_table[i]) then
			for k,v in pairs(az_table) do
				if has_alife_info(v) then
					az_name = v
					disable_info(az_name)
					break
				end
			end
			pick_artefact_from_anomaly(nil, nil, {p[1], az_name, dialogs_zaton.zat_b29_af_table[i]})
			break
		end
	end
end

function relocate_item_b29(actor, npc, p)
	local item
	for i = 16, 23 do
		if has_alife_info(dialogs_zaton.zat_b29_infop_bring_table[i]) then
			item = dialogs_zaton.zat_b29_af_table[i]
			break
		end
	end
	local from_obj = p and get_story_object(p[1])
	local to_obj = p and get_story_object(p[2])
	if to_obj ~= nil then
		if from_obj ~= nil and from_obj:object(item) ~= nil then
			from_obj:transfer_item(from_obj:object(item), to_obj)
		else
			alife():create(item,
				to_obj:position(),
				to_obj:level_vertex_id(),
				to_obj:game_vertex_id(),
				to_obj:id())
		end
	else
		abort("Couldn't relocate item to NULL")
	end
end

-- Функция ресетит секвенсную звукокую тему у непися. by peacemaker, hein, redstain
function reset_sound_npc(actor, npc, p)
	local obj_id = npc:id()
	if obj_id and xr_sound.sound_table and xr_sound.sound_table[obj_id] then
		xr_sound.sound_table[obj_id]:reset(obj_id)
	end
end

function jup_b202_inventory_box_relocate(actor, npc)
	local inv_box_out = get_story_object("jup_b202_actor_treasure")
	local inv_box_in = get_story_object("jup_b202_snag_treasure")
	local items_to_relocate = {}
	local function relocate(inv_box_out, item)
		table.insert(items_to_relocate, item)
	end
	inv_box_out:iterate_inventory_box	(relocate, inv_box_out)
	for k,v in pairs(items_to_relocate) do
		inv_box_out:transfer_item(v, inv_box_in)
	end
end

function clear_box(actor, npc, p)
	if (p and p[1]) == nil then abort("Wrong parameters in function 'clear_box'!!!") end

	local inv_box = get_story_object(p[1])

	if inv_box == nil then
		abort("There is no object with story_id [%s]", tostring(p[1]))
	end

	local items_table = {}

	local function add_items(inv_box, item)
		table.insert(items_table, item)
	end

	inv_box:iterate_inventory_box(add_items, inv_box)

	for k,v in pairs(items_table) do
		alife():release(alife():object(v:id()), true)
	end
end

function activate_weapon(actor, npc, p)
	local object = actor:object(p[1])
	if object == nil then
		assert("Actor has no such weapon! [%s]", p[1])
	end
	if object ~= nil then
		actor:make_item_active(object)
	end
end

function set_game_time(actor, npc, p)
	local real_hours = level.get_time_hours()
	local real_minutes = level.get_time_minutes()
	local hours = tonumber(p[1])
	local minutes = tonumber(p[2])
	if p[2] == nil then
		minutes = 0
	end
	local hours_to_change = hours - real_hours
	if hours_to_change <= 0 then
		hours_to_change = hours_to_change + 24
	end
	local minutes_to_change = minutes - real_minutes
	if minutes_to_change <= 0 then
		minutes_to_change = minutes_to_change + 60
		hours_to_change = hours_to_change - 1
	elseif hours == real_hours then
		hours_to_change = hours_to_change - 24
	end
	level.change_game_time(0,hours_to_change,minutes_to_change)
	level_weathers.get_weather_manager():forced_weather_change()
	surge_manager.get_surge_manager().time_forwarded = true
	printf("set_game_time: time changed to [%d][%d]", hours_to_change, minutes_to_change)
end

function forward_game_time(actor, npc, p)
	if not p then
		abort("Insufficient or invalid parameters in function 'forward_game_time'!")
	end

	local hours = tonumber(p[1])
	local minutes = tonumber(p[2])

	if p[2] == nil then
		minutes = 0
	end
	level.change_game_time(0,hours,minutes)
	level_weathers.get_weather_manager():forced_weather_change()
	surge_manager.get_surge_manager().time_forwarded = true
	printf("forward_game_time: time forwarded on [%d][%d]", hours, minutes)
end

function stop_tutorial()
	printf("stop tutorial called")
	game.stop_tutorial()
end

function jup_b10_spawn_drunk_dead_items(actor, npc, p)
	local items_all = {
					["wpn_ak74"] = 1,
					["ammo_5.45x39_fmj"] = 5,
					["ammo_5.45x39_ap"] = 3,
					["wpn_fort"] = 1,
					["ammo_9x18_fmj"] = 3,
					["ammo_12x70_buck"] = 5,
					["ammo_11.43x23_hydro"] = 2,
					["grenade_rgd5"] = 3,
					["grenade_f1"] = 2,
					["medkit_army"] = 2,
					["medkit"] = 4,
					["bandage"] = 4,
					["antirad"] = 2,
					["vodka"] = 3,
					["energy_drink"] = 2,
					["conserva"] = 1,
					["jup_b10_ufo_memory_2"] = 1,
					}

	local items = {
					[2] = 	{
							["wpn_sig550_luckygun"] = 1,
							},
					[1] = 	{
							["ammo_5.45x39_fmj"] = 5,
							["ammo_5.45x39_ap"] = 3,
							["wpn_fort"] = 1,
							["ammo_9x18_fmj"] = 3,
							["ammo_12x70_buck"] = 5,
							["ammo_11.43x23_hydro"] = 2,
							["grenade_rgd5"] = 3,
							["grenade_f1"] = 2,
							},
					[0] = 	{
							["medkit_army"] = 2,
							["medkit"] = 4,
							["bandage"] = 4,
							["antirad"] = 2,
							["vodka"] = 3,
							["energy_drink"] = 2,
							["conserva"] = 1,
							},
					}

	if p and p[1] ~= nil then
		local cnt = xr_logic.pstor_retrieve(actor, "jup_b10_ufo_counter", 0)
		if cnt > 2 then return end
		for k,v in pairs(items[cnt]) do
			local target_obj_id = get_story_object_id(p[1])
			if target_obj_id ~= nil then
				box = alife():object(target_obj_id)
				if box == nil then
					abort("There is no such object %s", p[1])
				end
				for i = 1,v do
					alife():create(k,vector(),0,0,target_obj_id)
				end
			else
				abort("object is nil %s", tostring(p[1]))
			end
		end
	else
		for k,v in pairs(items_all) do
			for i = 1,v do
				alife():create(k,
					npc:position(),
					npc:level_vertex_id(),
					npc:game_vertex_id(),
					npc:id())
			end
		end
	end

end

function pick_artefact_from_anomaly(actor, npc, p)
	local npc
	local az_name = p and p[2]
	local af_name = p and p[3]
	local af_id
	local af_obj
	local anomal_zone = db.anomaly_by_name[az_name]

	if p and p[1] then
--		if p[1] == "actor" then
--			npc = db.actor
--		else
--			npc = get_story_object(p[1])
--		end

		local npc_id = get_story_object_id(p[1])
		if npc_id == nil then
			abort("Couldn't relocate item to NULL in function 'pick_artefact_from_anomaly!'")
		end
		npc = alife():object(npc_id)
		if npc and (not IsStalker(npc) or not npc:alive()) then
			abort("Couldn't relocate item to NULL (dead or not stalker) in function 'pick_artefact_from_anomaly!'")
		end
	end

	if anomal_zone == nil then
		abort("No such anomal zone in function 'pick_artefact_from_anomaly!'")
	end

	if anomal_zone.spawned_count < 1 then
		printf("No artefacts in anomal zone [%s]", az_name)
		return
	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
			af_id = tonumber(k)
			af_obj = alife():object(tonumber(k))
			break
		end
		if af_name == nil then
			af_id = tonumber(k)
			af_obj = alife():object(tonumber(k))
			af_name = af_obj:section_name()
			break
		end
	end

	if af_id == nil then
		printf("No such artefact [%s] found in anomal zone [%s]", tostring(af_name), az_name)
		return
	end

	anomal_zone:on_artefact_take(af_obj)

	alife():release(af_obj, true)
	give_item(db.actor, npc, {af_name, p[1]})
--	alife():create(af_name,
--		npc.position,
--		npc.level_vertex_id,
--		npc.game_vertex_id,
--		npc.id)
end

function anomaly_turn_off (actor, npc, p)
	local anomal_zone = db.anomaly_by_name[p[1]]
	if anomal_zone == nil then
		abort("No such anomal zone in function 'anomaly_turn_off!'")
	end
	anomal_zone:turn_off()
end

function anomaly_turn_on (actor, npc, p)
	local anomal_zone = db.anomaly_by_name[p[1]]
	if anomal_zone == nil then
		abort("No such anomal zone in function 'anomaly_turn_on!'")
	end
	if p[2] then
		anomal_zone:turn_on(true)
	else
		anomal_zone:turn_on(false)
	end
end

function zat_b202_spawn_random_loot(actor, npc, p)
	local si_table = {}
	si_table[1] = {
		[1] = {item = {"bandage","bandage","bandage","bandage","bandage","medkit","medkit","medkit","conserva","conserva"}},
		[2] = {item = {"medkit","medkit","medkit","medkit","medkit","vodka","vodka","vodka","kolbasa","kolbasa"}},
		[3] = {item = {"antirad","antirad","antirad","medkit","medkit","bandage","kolbasa","kolbasa","conserva"}},
	}
	si_table[2] = {
		[1] = {item = {"grenade_f1","grenade_f1","grenade_f1"}},
		[2] = {item = {"grenade_rgd5","grenade_rgd5","grenade_rgd5","grenade_rgd5","grenade_rgd5"}}
	}
	si_table[3] = {
		[1] = {item = {"detector_elite"}},
		[2] = {item = {"detector_advanced"}}
	}
	si_table[4] = {
		[1] = {item = {"helm_hardhat"}},
		[2] = {item = {"helm_respirator"}}
	}
	si_table[5] = {
		[1] = {item = {"wpn_val","ammo_9x39_ap","ammo_9x39_ap","ammo_9x39_ap"}},
		[2] = {item = {"wpn_spas12","ammo_12x70_buck","ammo_12x70_buck","ammo_12x70_buck","ammo_12x70_buck"}},
		[3] = {item = {"wpn_desert_eagle","ammo_11.43x23_fmj","ammo_11.43x23_fmj","ammo_11.43x23_hydro","ammo_11.43x23_hydro"}},
		[4] = {item = {"wpn_abakan","ammo_5.45x39_ap","ammo_5.45x39_ap"}},
		[5] = {item = {"wpn_sig550","ammo_5.56x45_ap","ammo_5.56x45_ap"}},
		[6] = {item = {"wpn_ak74","ammo_5.45x39_fmj","ammo_5.45x39_fmj"}},
		[7] = {item = {"wpn_l85","ammo_5.56x45_ss190","ammo_5.56x45_ss190"}}
	}
	si_table[6] = {
		[1] = {item = {"specops_outfit"}},
		[2] = {item = {"stalker_outfit"}}
	}
	weight_table = {}
	weight_table[1] = 2
	weight_table[2] = 2
	weight_table[3] = 2
	weight_table[4] = 2
	weight_table[5] = 4
	weight_table[6] = 4
	local spawned_item = {}
	local max_weight = 12
	repeat
		local n = 0
		repeat
			n = math.random(1, #weight_table)
			local prap = true
			for k,v in pairs(spawned_item) do
				if v == n then
					prap = false
					break
				end
			end
		until (prap) and ((max_weight - weight_table[n]) >= 0)
		max_weight = max_weight - weight_table[n]
		table.insert(spawned_item,n)
		local item = math.random(1, #si_table[n])
		for k,v in pairs(si_table[n][item].item) do
			spawn_object_in(actor, npc, {tostring(v),"jup_b202_snag_treasure"})
		end
	until max_weight <= 0
end

function zat_a1_tutorial_end_give(actor, npc)
--	level.add_pp_effector("black.ppe", 1313, true) ---do not stop on r1 !
	db.actor:give_info_portion("zat_a1_tutorial_end")
end

function oasis_heal()
	local d_health = 0.005
	local d_power = 0.01
	local d_bleeding = 0.05
	local d_radiation = -0.05
	if(db.actor.health<1) then
		db.actor.health = d_health
	end
	if(db.actor.power<1) then
		db.actor.power = d_power
	end
	if(db.actor.radiation>0) then
		db.actor.radiation = d_radiation
	end
	if(db.actor.bleeding>0) then
		db.actor.bleeding = d_bleeding
	end
		db.actor.satiety = 0.01
end

--Функция принимает только одно значение, определяющее для какой групировки запускается. доступные значения [duty, freedom]
function jup_b221_play_main(actor, npc, p)
	local info_table = {}
	local main_theme
	local reply_theme
	local info_need_reply
	local reachable_theme = {}
	local theme_to_play = 0

	if (p and p[1]) == nil then
		abort("No such parameters in function 'jup_b221_play_main'")
	end
--Составляем таблицу инфопоршинов определяющих доступность той или иной темы, определяем префиксы темы, ответа и реакции, соответственно для долга или для свободы.
	if tostring(p[1]) == "duty" then
		info_table = {
			[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"
		}
		main_theme = "jup_b221_duty_main_"
		reply_theme = "jup_b221_duty_reply_"
		info_need_reply = "jup_b221_duty_reply"
	elseif tostring(p[1]) == "freedom" then
		info_table = {
			[1] = "jup_b207_freedom_know_about_depot",
			[2] = "jup_b46_duty_founder_pda_to_freedom",
			[3] = "jup_b4_monolith_squad_in_freedom",
			[4] = "jup_a6_freedom_leader_bunker_guards_work",
			[5] = "jup_a6_freedom_leader_employ_work",
			[6] = "jup_b207_freedom_wins"
		}
		main_theme = "jup_b221_freedom_main_"
		reply_theme = "jup_b221_freedom_reply_"
		info_need_reply = "jup_b221_freedom_reply"
	else
		abort("Wrong parameters in function 'jup_b221_play_main'")
	end
--Составляем таблицу достыпных тем(тлько номера тем).
	for k,v in pairs(info_table) do
		if (has_alife_info(v)) and (not has_alife_info(main_theme .. tostring(k) .. "_played")) then
			table.insert(reachable_theme,k)
--			printf("jup_b221_play_main: table reachable_theme ------------------------------> [%s]", tostring(k))
		end
	end
--Если таблица доступных тем пуста играем ответ. Если же она не пуста играем основную тему. Если играем основную тему заносим значение счетчика для повторного выполнения функции. Тему выбираем по рандому.
	if #reachable_theme ~= 0 then
		disable_info(info_need_reply)
		theme_to_play = reachable_theme[math.random(1, #reachable_theme)]
--		printf("jup_b221_play_main: variable theme_to_play ------------------------------> [%s]", tostring(theme_to_play))
		xr_logic.pstor_store(actor,"jup_b221_played_main_theme",tostring(theme_to_play))
		db.actor:give_info_portion(main_theme .. tostring(theme_to_play) .."_played")
		if theme_to_play ~= 0 then
			play_sound(actor, npc, {main_theme .. tostring(theme_to_play)})
		else
			abort("No such theme_to_play in function 'jup_b221_play_main'")
		end
	else
		db.actor:give_info_portion(info_need_reply)
		theme_to_play = tonumber(xr_logic.pstor_retrieve(actor,"jup_b221_played_main_theme",0))
		if theme_to_play ~= 0 then
			play_sound(actor, npc, {reply_theme..tostring(theme_to_play)})
		else
			abort("No such theme_to_play in function 'jup_b221_play_main'")
		end
		xr_logic.pstor_store(actor,"jup_b221_played_main_theme","0")
	end
end

function pas_b400_play_particle(actor, npc, p)
	db.actor:start_particles("zones\\zone_acidic_idle","bip01_head")
end

function pas_b400_stop_particle(actor, npc, p)
	db.actor:stop_particles("zones\\zone_acidic_idle","bip01_head")
end

function damage_actor_items_on_start(actor, npc)
	local actor = db.actor

	local obj = actor:object("helm_respirator")
	if obj ~= nil then
		obj:set_condition(0.8)
	end

	obj = actor:object("stalker_outfit")
	if obj ~= nil then
		obj:set_condition(0.76)
	end

	obj = actor:object("wpn_pm_actor")
	if obj ~= nil then
		obj:set_condition(0.9)
	end

	obj = actor:object("wpn_ak74u")
	if obj ~= nil then
		obj:set_condition(0.7)
	end

end

function damage_pri_a17_gauss()
	local obj = get_story_object("pri_a17_gauss_rifle")
	--local obj = npc:object("pri_a17_gauss_rifle")
	if obj ~= nil then
		obj:set_condition(0.0)
	end
end

function pri_a17_hard_animation_reset(actor, npc, p)
	--db.storage[npc:id()].state_mgr:set_state("pri_a17_fall_down", nil, nil, nil, {fast_set = true})
	db.storage[npc:id()].state_mgr:set_state("pri_a17_fall_down")

	local state_mgr = db.storage[npc:id()].state_mgr
	if state_mgr ~= nil then
		state_mgr.animation:set_state(nil, true)
		state_mgr.animation:set_state("pri_a17_fall_down")
		state_mgr.animation:set_control()
	end
end

function jup_b217_hard_animation_reset(actor, npc, p)
	db.storage[npc:id()].state_mgr:set_state("jup_b217_nitro_straight")

	local state_mgr = db.storage[npc:id()].state_mgr
	if state_mgr ~= nil then
		state_mgr.animation:set_state(nil, true)
		state_mgr.animation:set_state("jup_b217_nitro_straight")
		state_mgr.animation:set_control()
	end
end




function sleep(actor, npc)
	local sleep_zones = {
						"zat_a2_sr_sleep",
						"zat_cave_sr_sleep",
						"zat_noah_sr_sleep",
						"zat_dealer_sr_sleep",
						"zat_freilicht_sr_sleep",
						"zat_zombie_sr_sleep",
						"zat_boat1_sr_sleep",
						"zat_boat2_sr_sleep",
						"zat_suicidehut_sr_sleep",
						"jup_a6_sr_sleep",
						"jup_bandit_sr_sleep",
						"jup_radio_sr_sleep",
						"jup_kopachi_sr_sleep",
						"jup_zulu_sr_sleep",
						"jup_bunker_sr_sleep",						
						"pri_a16_sr_sleep",
						"pri_base_sr_sleep",
						"pri_house_sr_sleep",
						"pri_ambush_sr_sleep",
						"pri_kindergarten_sr_sleep",
						"actor_surge_hide_2"
						}

	for k,v in pairs(sleep_zones) do
		if utils.npc_in_zone(db.actor, db.zone_by_name[v]) then
			ui_sleep_dialog.sleep()
			give_info("sleep_active")
		end
	end

end



--[[
function set_tip_to_story(actor, npc, p)
	if p == nil or p[2] == nil then
		abort("Not enough parameters in 'set_tip_to_story' function!")
	end

	local obj = get_story_object(p[1])

	if not obj then
		return
	end

	local tip = p[2]

	obj:set_tip_text(tip)
end

function clear_tip_from_story(actor, npc, p)
	if p == nil or p[1] == nil then
		abort("Not enough parameters in 'clear_tip_from_story' function!")
	end

	local obj = get_story_object(p[1])

	if not obj then
		return
	end

	obj:set_tip_text("")
end
]]--

function mech_discount(actor, npc, p)
	if(p[1]) then
				inventory_upgrades.mech_discount(tonumber(p[1]))
	end
end

function polter_actor_ignore(actor, npc, p)
	if p[1] and p[1] == "true" then
				npc:poltergeist_set_actor_ignore(true)
	elseif p[1] and p[1] == "false" then
				npc:poltergeist_set_actor_ignore(false)
	end
end

function burer_force_gravi_attack(actor, npc)
	npc:burer_set_force_gravi_attack(true)
end

function burer_force_anti_aim(actor, npc)
	npc:set_force_anti_aim(true)
end

function show_freeplay_dialog(actor, npc, p)
	if p[1] and p[2] and p[2] == "true" then
		ui_freeplay_dialog.show("message_box_yes_no", p[1])
	elseif p[1] then
		ui_freeplay_dialog.show("message_box_ok", p[1])
	end
end



local detectors = { "detector_simple", "detector_advanced", "detector_elite", "detector_scientific" }

-- Только для state_mgr
function get_best_detector(npc)
	for k,v in pairs(detectors) do
		local obj = npc:object(v)
		if obj ~= nil then
			obj:enable_attachable_item(true)
			return
		end
	end
end

function hide_best_detector(npc)
	for k,v in pairs(detectors) do
		local obj = npc:object(v)
		if obj ~= nil then
			obj:enable_attachable_item(false)
			return
		end
	end
end

-- Инфопоршны для синхронизации анимации нпс с прочими действиями, и для других целей
function pri_a18_radio_start(actor, npc)
	db.actor:give_info_portion("pri_a18_radio_start")
end

function pri_a17_ice_climb_end(actor, npc)
	db.actor:give_info_portion("pri_a17_ice_climb_end")
end

function jup_b219_opening(actor, npc)
	db.actor:give_info_portion("jup_b219_opening")
end

function jup_b219_entering_underpass(actor, npc)
	db.actor:give_info_portion("jup_b219_entering_underpass")
end

function pri_a17_pray_start(actor, npc)
	db.actor:give_info_portion("pri_a17_pray_start")
end

function zat_b38_open_info(actor, npc)
	db.actor:give_info_portion("zat_b38_open_info")
end

function zat_b38_switch_info(actor, npc)
	db.actor:give_info_portion("zat_b38_switch_info")
end
function zat_b38_cop_dead(actor, npc)
	db.actor:give_info_portion("zat_b38_cop_dead")
end

function jup_b15_zulus_drink_anim_info(actor, npc)
	db.actor:give_info_portion("jup_b15_zulus_drink_anim_info")
end

function pri_a17_preacher_death(actor, npc)
	db.actor:give_info_portion("pri_a17_preacher_death")
end

function zat_b3_tech_surprise_anim_end(actor, npc)
	db.actor:give_info_portion("zat_b3_tech_surprise_anim_end")
end

function zat_b3_tech_waked_up(actor, npc)
	db.actor:give_info_portion("zat_b3_tech_waked_up")
end

function zat_b3_tech_drinked_out(actor, npc)
	db.actor:give_info_portion("zat_b3_tech_drinked_out")
end

function pri_a28_kirillov_hq_online(actor, npc)
	db.actor:give_info_portion("pri_a28_kirillov_hq_online")
end

function pri_a20_radio_start(actor, npc)
	db.actor:give_info_portion("pri_a20_radio_start")
end

function pri_a22_kovalski_speak(actor, npc)
	db.actor:give_info_portion("pri_a22_kovalski_speak")
end

function zat_b38_underground_door_open(actor, npc)
	db.actor:give_info_portion("zat_b38_underground_door_open")
end

function zat_b38_jump_tonnel_info(actor, npc)
	db.actor:give_info_portion("zat_b38_jump_tonnel_info")
end

function jup_a9_cam1_actor_anim_end(actor, npc)
	db.actor:give_info_portion("jup_a9_cam1_actor_anim_end")
end

function pri_a28_talk_ssu_video_end(actor, npc)
	db.actor:give_info_portion("pri_a28_talk_ssu_video_end")
end

function set_torch_state(actor, npc, p)
 	if p == nil or p[2] == nil then
		abort("Not enough parameters in 'set_torch_state' function!")
	end

	local obj = get_story_object(p[1])

	if not obj then
		return
	end
	local torch = obj:object("device_torch")
	if torch then
		if p[2] == "on" then
			torch:enable_attachable_item(true)
		elseif p[2] == "off" then
			torch:enable_attachable_item(false)
		end
	end
end


local actor_nightvision = false
local actor_torch		= false

function disable_actor_nightvision(actor, npc)
	local nightvision = db.actor:object("device_torch")
	if nightvision:night_vision_enabled() then
		nightvision:enable_night_vision(false)
		actor_nightvision = true
	end
end

function enable_actor_nightvision(actor, npc)
	local nightvision = db.actor:object("device_torch")
	if not nightvision:night_vision_enabled() and actor_nightvision then
		nightvision:enable_night_vision(true)
		actor_nightvision = false
	end
end

function disable_actor_torch(actor, npc)
	local torch = db.actor:object("device_torch")
	if torch:torch_enabled() then
		torch:enable_torch(false)
		actor_torch = true
	end
end

function enable_actor_torch(actor, npc)
	local torch = db.actor:object("device_torch")
	if not torch:torch_enabled() and actor_torch then
		torch:enable_torch(true)
		actor_torch = false
	end
end


function create_cutscene_actor_with_weapon(actor, npc, p)
	--' p[1] - секция кого спаунить
	--' p[2] - имя патрульного пути где спаунить.
	--' p[3] - точка патрульного пути
	--' p[4] - поворот по оси Y
	--' p[5] - принудительный слот - будет работать даже при disable_ui
	local spawn_sect = p[1]
	if spawn_sect == nil then
		abort("Wrong spawn section for 'spawn_object' function %s. For object %s", tostring(spawn_sect), obj:name())
	end

	local path_name = p[2]
	if path_name == nil then
		abort("Wrong path_name for 'spawn_object' function %s. For object %s", tostring(path_name), obj:name())
	end

	if not level.patrol_path_exists(path_name) then
		abort("Path %s doesnt exist. Function 'spawn_object' for object %s ", tostring(path_name), obj:name())
	end
	local ptr = patrol(path_name)
	local index = p[3] or 0
	local yaw = p[4] or 0

	local npc = alife():create(spawn_sect, ptr:point(index), ptr:level_vertex_id(0), ptr:game_vertex_id(0))
	if IsStalker( nil, npc:clsid()) then
		npc:o_torso().yaw = yaw * math.pi / 180
	else
		npc.angle.y = yaw * math.pi / 180
	end

	local slot_override = p[5] or 0

	local slot
	local active_item

	if slot_override == 0 then
		slot = db.actor:active_slot()
		if(slot~=2 and slot~=3) then
			return
		end
		active_item = db.actor:active_item()
	else
		if db.actor:item_in_slot(slot_override) ~= nil then
			active_item = db.actor:item_in_slot(slot_override)
		else
			if db.actor:item_in_slot(3) ~= nil then
				active_item = db.actor:item_in_slot(3)
			elseif db.actor:item_in_slot(2) ~= nil then
				active_item = db.actor:item_in_slot(2)
			else
				return
			end
		end
	end

	local actor_weapon = alife():object(active_item:id())
	local section_name = actor_weapon:section_name()
	if section_name == "pri_a17_gauss_rifle" then
		section_name = "wpn_gauss"
	end

	if (active_item) then
		local new_weapon = alife():create(section_name,
													ptr:point(index),
													ptr:level_vertex_id(0),
													ptr:game_vertex_id(0),
													npc.id)
		if section_name ~= "wpn_gauss" then
			new_weapon:clone_addons(actor_weapon)
		end
	end
end

-- Заставить играть уникальные анимации сна(у кровососа)
function set_force_sleep_animation(actor, npc, p)
	local num = p[1]
	npc:force_stand_sleep_animation(tonumber(num))
end
-- Убрать уникальные анимации сна(у кровососа)
function release_force_sleep_animation(actor, npc)
	npc:release_stand_sleep_animation()
end

function zat_b33_pic_snag_container(actor, npc)
	if xr_conditions.actor_in_zone(actor, npc, {"zat_b33_tutor"}) then
		give_actor(actor, npc, {"zat_b33_safe_container"})
		db.actor:give_info_portion("zat_b33_find_package")
		if not has_alife_info("zat_b33_safe_container") then
			local zone = db.zone_by_name["zat_b33_tutor"]
			play_sound(actor, zone, {"pda_news"})
		end
	end
end

--Отключение воздействия вражеского нпс на индикатор видимости врага на хаде игрока.
--Исп. только из логики нпс.
function set_visual_memory_enabled(actor, npc, p)
	if (p and p[1]) and (tonumber(p[1]) >= 0) and (tonumber(p[1]) <= 1) then
		local boolval = false
		if (tonumber(p[1]) == 1) then
			boolval = true
		end
		npc:set_visual_memory_enabled(boolval)
	end
end

function disable_memory_object (actor, npc)
	local best_enemy = npc:best_enemy()
	if best_enemy then
		npc:enable_memory_object(best_enemy, false)
	end
end

function zat_b202_spawn_b33_loot(actor, npc, p)
	local info_table = {
		"zat_b33_first_item_gived",
		"zat_b33_second_item_gived",
		"zat_b33_third_item_gived",
		"zat_b33_fourth_item_gived",
		"zat_b33_fifth_item_gived"
	}
	local item_table = {}
	item_table[1] = {
		"wpn_fort_snag"
	}
	item_table[2] = {
		"medkit_scientic",
		"medkit_scientic",
		"medkit_scientic",
		"antirad",
		"antirad",
		"antirad",
		"bandage",
		"bandage",
		"bandage",
		"bandage",
		"bandage"
	}
	item_table[3] = {
		"wpn_ak74u_snag"
	}
	item_table[4] = {
		"af_soul"
	}
	item_table[5] = {
		"helm_hardhat_snag"
	}
	for k,v in pairs(info_table) do
		local obj_id
		if (k == 1) or (k == 3) then
			obj_id = "jup_b202_stalker_snag"
		else
			obj_id = "jup_b202_snag_treasure"
		end
		if not has_alife_info(tostring(v)) then
			for l,m in pairs(item_table[k]) do
--				printf("zat_b202_spawn_b33_loot: number [%s] item [%s] to [%s]", tostring(k), tostring(m), tostring(obj_id))
				spawn_object_in(actor, npc, {tostring(m),tostring(obj_id)})
			end
		end
	end
end

function set_monster_animation (actor, npc, p)
	if not (p and p[1]) then
		abort("Wrong parameters in function 'set_monster_animation'!!!")
	end
	npc:set_override_animation (p[1])
end

function clear_monster_animation (actor, npc)
	npc:clear_override_animation ()
end

local actor_position_for_restore
local actor_direction_for_restore

function save_actor_position()
	actor_position_for_restore = get_story_object("actor"):position()
	--actor_direction_for_restore = get_story_object("actor"):direction()
end

function restore_actor_position()
	--db.actor:set_actor_direction(actor_direction_for_restore)
	db.actor:set_actor_position(actor_position_for_restore)
end

function upgrade_hint(actor, npc, p)
	if(p) then
		inventory_upgrades.cur_hint = p
	end
end

function force_obj(actor, npc, p)
	local obj = get_story_object(p[1])
	if not obj then
		abort("'force_obj' Target object does not exist")
		return
	end
	if p[2] == nil then p[2] = 20 end
	if p[3] == nil then p[3] = 100 end
	obj:set_const_force(vector():set(0,1,0), p[2], p[3])
end

function pri_a28_check_zones()
	local story_obj_id
	local dist
	local index = 0

	local zones_tbl = {
						[1] = "pri_a28_sr_mono_add_1",
						[2] = "pri_a28_sr_mono_add_2",
						[3] = "pri_a28_sr_mono_add_3",
						}

	local info_tbl = {
						[1] = "pri_a28_wave_1_spawned",
						[2] = "pri_a28_wave_2_spawned",
						[3] = "pri_a28_wave_3_spawned",
						}

	local squad_tbl = {
						[1] = "pri_a28_heli_mono_add_1",
						[2] = "pri_a28_heli_mono_add_2",
						[3] = "pri_a28_heli_mono_add_3",
						}

	for k,v in pairs(zones_tbl) do
		story_obj_id = get_story_object_id(v)
		if story_obj_id then
			local se_obj = alife():object(story_obj_id)
			local curr_dist = se_obj.position:distance_to(db.actor:position())
			if index == 0 then
				dist = curr_dist
				index = k
			elseif dist < curr_dist then
				dist = curr_dist
				index = k
			end
		end
	end

	if index == 0 then
		abort("Found no distance or zones in func 'pri_a28_check_zones'")
	end

	if has_alife_info(info_tbl[index]) then
		for k,v in pairs(info_tbl) do
			if not has_alife_info(info_tbl[k]) then
				db.actor:give_info_portion(info_tbl[k])
			end
		end
	else
		db.actor:give_info_portion(info_tbl[index])
	end

	create_squad(db.actor,nil,{squad_tbl[index],"pri_a28_heli"})
end

function eat_vodka_script()
	if db.actor:object("vodka_script") ~= nil then
		db.actor:eat(db.actor:object("vodka_script"))
	end
end

local mat_table = {
					"jup_b200_material_1",
					"jup_b200_material_2",
					"jup_b200_material_3",
					"jup_b200_material_4",
					"jup_b200_material_5",
					"jup_b200_material_6",
					"jup_b200_material_7",
					"jup_b200_material_8",
					"jup_b200_material_9",
					}

function jup_b200_count_found(actor)
	local cnt = 0
						
	for k,v in pairs(mat_table) do
		local material_obj = get_story_object(v)
		if material_obj then
			local parent = material_obj:parent()
			if parent then
				local parent_id = parent:id()
				if parent_id ~= 65535 and parent_id == actor:id() then
					cnt = cnt + 1
				end
			end
		end
	end
	
	cnt = cnt + xr_logic.pstor_retrieve(actor, "jup_b200_tech_materials_brought_counter", 0)
	xr_logic.pstor_store(actor, "jup_b200_tech_materials_found_counter", cnt)
end
