if (jit == nil) then
	profiler.setup_hook	()
end


function empty	(container)
	if (type(container) == "function") then
		for i in container do
			return	(false)
		end

		return		(true)
	end

	assert			(type(container) == "table")
	if (container[1] ~= nil) then
		return		(false)
	end

	for i,j in pairs(container) do
		return		(false)
	end

	return			(true)
end


schemes = {} -- ёююЄтхЄёЄтшх ёїхь ьюфєы ь
stypes = {} -- Єшяv ёїхь

-- │руЁєцрхЄ ёїхьє шч Їрщыр эр фшёъх ш ръЄштшЁєхЄ т ьюЄштрЄюЁх.
-- │фхё№:
-- 	filename - шь  Їрщыр, т ъюЄюЁюь Ёхрышчютрэр ёїхьр, схч Ёрё°шЁхэш 
-- 	scheme - шь  ёїхьv
function load_scheme(filename, scheme, stype)
	schemes[scheme] = filename
	stypes[scheme] = stype
end

----------------------------------------------------------------------
dev_debug = false
----------------------------------------------------------------------
local scripts_to_print =	{
	                            ["stalker_generic"] = true,
	                            ["xr_smartcover"] = true,
	                            ["xr_logic"] = true,
	                            ["xr_conditions"] = true,
	                            ["xr_cover"] = true,
	                            ["sim_combat"] = true,
	                            ["xr_motivator"] = true,
	                            ["xr_walker"] = true,
	                            ["xr_camper"] = true,
	                            ["xr_kamp"] = true,
	                            ["restrictor_manager"] = true,
	                            ["sim_board"] = true,
	                            ["sim_faction"] = true,
	                            ["post_combat_idle"] = true,
	                            ["xr_death"] = true,
	                            ["xr_sound"] = true,
	                            ["utils"] = true,
	                            ["treasure_manager"] = true,
	                            ["object_collection"] = true,
	                            ["minigames_manager"] = true,
	                            ["minigame_crowkiller"] = true,
	                            ["minigame_shooting"] = true,
	                            ["se_actor"] = true,
	                            ["smart_terrain"] = true,
	                            ["bind_physic_object"] = true,
	                            ["bind_heli"] = true,
	                            ["bind_anomaly_zone"] = true,
	                            ["bind_stalker"] = true,
	                            ["state_mgr_animation"] = true,
	                            ["se_stalker"] = true,
	                            ["db"] = true,
								["sim_squad_generic"] = true,
								["sim_squad_scripted"] = true,
								["se_smart_cover"] = true,
								["se_monster"] = true,
								["xr_use"] = true,
								["dialog_manager"] = true,
								["xr_combat_ignore"] = true,
								["xr_remark"] = true,
								["cover_manager"] = true,
								["xr_danger"]	 = true,
								--["task_manager"] = true,
								--["task_objects"]	 = true

							}
function printf(fmt,...)
	local is_g = 0
	local result = fmt
	if debug == nil then
		log(string.format(fmt,...))
		return
	end
	local info_table = debug.getinfo(2)
	local script_name = string.gsub(info_table.short_src, "%.script", "")
	script_name = string.gsub(script_name, "gamedata\\scripts\\", "")
	if scripts_to_print[script_name] == true then return end
	script_name,is_g = string.gsub(script_name, "_g", "")
	if is_g == 0 then
		result = script_name..":("..info_table.currentline.."):"..fmt
	end
	log(string.format(result,...))
end

----------------------------------------------------------------------
if nil == time_global then
	time_global = function () return device():time_global() end
end

function wait_game(time_to_wait)
    verify_if_thread_is_running()
    if (time_to_wait == nil) then
        coroutine.yield()
    else
        local time_to_stop = game.time() + time_to_wait
        while game.time() <= time_to_stop do
            coroutine.yield()
        end
    end
end

function wait(time_to_wait)
    verify_if_thread_is_running()
    if (time_to_wait == nil) then
        coroutine.yield()
    else
        local time_to_stop = time_global() + time_to_wait
        while time_global() <= time_to_stop do
            coroutine.yield()
        end
    end
end

function action(obj,...)
    local arg = {...}
    local act = entity_action()
    local i = 1
    while true do
        if (arg[i] ~= nil) then
            act:set_action(arg[i])
        else
            break
        end
        i = i + 1
    end
    if (obj ~= nil) then
        obj:command(act,false)
    end
    return  entity_action(act)
end

function action_first(obj,...)
    local arg = {...}
    local act = entity_action()
    local i = 1
    while true do
        if (arg[i] ~= nil) then
            act:set_action(arg[i])
        else
            break
        end
        i = i + 1
    end
    if (obj ~= nil) then
        obj:command(act,true)
    end
    return  entity_action(act)
end

function round (value)
    local min = math.floor (value)
    local max = min + 1
    if value - min > max - value then return max end
    return min
end

function debug_get_level_object(obj_name)
    local res = level.debug_object(obj_name)
    while res == nil do

-- !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
-- !!!!! =+ │L│+││+=TL│LTLгT+, L=L++ =+ +L-+T TL-=+ ++L++│ ││L │LTTTL=+T│+ ++-+│T+T !!!!!
-- !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
        printf("get_level_object() is waiting for object \"%s\"", obj_name)

        res         = level.object(obj_name)
        wait        ()
    end
    return          res
end

function debug_get_actor()
    local res       = level.debug_actor()
    while res == nil do
        res         = level.debug_actor()
        wait        ()
    end
    return          res
end

function distance_between(obj1, obj2)
    return obj1:position():distance_to(obj2:position())
end

-- +ёыш юфшэ юс·хъЄ nil, эряЁшьхЁ эхЄ ръЄхЁр, Єю ёўшЄрхь, ўЄю юэ фрыхъю
function distance_between_safe(obj1, obj2)
    if(obj1 == nil or obj2 == nil) then return 100000 end
	return obj1:position():distance_to(obj2:position())
end

local aa = nil
--' │ЁютхЁър эр шэЇюяюЁ°эv, фрцх хёыш шуЁюър эх ёє	хёЄтєхЄ
function has_alife_info(info_id)
	if aa == nil then
		return false
	end
	return aa:has_info(0, info_id)
end



function reset_action (npc, script_name)
    if npc:get_script () then
       npc:script (false, script_name)
    end
    npc:script (true, script_name)
end

class "script_object"

function script_object.__init(self,name,script,...)
	self.action         = action(nil,...)
	self.object_name    = name
	self.script_name    = script
	self.object         = nil
end

function script_object:update()
    local                   obj = self.object
    self.object             = level.object(self.object_name)
    if ((obj == nil) and (self.object ~= nil)) then
        self.object:script  (true,self.script_name)
        self.object:command (self.action,false)
    end
end

--
-- │хЁхфрўр яхЁёюэрцє шэЇюЁьрЎшш
--

function GiveInfoViaPda(obj_receiver, obj_sender, info_number)
    obj_receiver:give_info_portion_via_pda(info_number, obj_sender)
end


--------------------------------------------------
-- Functions and variables added by Zmey
--------------------------------------------------

-- │юэёЄрэЄр, ъюЄюЁє│ шёяюы№чютрЄ№ т ьхёЄрї, уфх эєцэю чрфрЄ№ эхюуЁрэшўхээюх тЁхь  фхщёЄтш 
time_infinite = 100000000

-- =рчтрэшх ёъЁшяЄр, ъюЄюЁvщ т фрээvщ ьюьхэЄ эрїюфшЄё  т юЄырфъх
-- (т ¤Єюь ёъЁшяЄх сєфєЄ ёЁрсрЄvтрЄ№ тvчютv ЇєэъЎшш debug_log)
debug_script_name = ""

-- TvтюфшЄ т ыюу ёЄЁюўъє, хёыш script_name == debug_script_name
-- Lёяюы№чєхЄё  фы  юЄЁрфъш ёЎхэрЁшхт
function debug_log(script_name, fmt, ...)
	if debug_script_name == script_name then
		log(string.format(fmt, ...))
	end
end

-- +ёыш т фрээvщ ьюьхэЄ тvяюыэ хЄё  ъръюх-Єю фхщёЄтшх, яЁхЁvтрхЄ хую ш юЄъы│ўрхЄ ёъЁшяЄютvщ Ёхцшь
function interrupt_action(who, script_name)
  if who:get_script() then
    who:script(false, script_name)
  end
end

function random_choice(...)
    local arg = {...}
    local r = math.random(1, #arg)
    return arg[r]
end

function new_action(...)
    local arg = {...}
    local act = entity_action()
    for i = 1, #arg do
        act:set_action(arg[i])
    end
    return act;
end

obj_last_actions = {};

function perform_action(obj, action_name, action)
  if (obj ~= nil) then
    obj_last_actions[obj] = action_name
    obj:command(act, false)
  end
end

function last_action(obj)
  return obj_last_actions[obj]
end

function if_then_else(cond, if_true, if_false)
    if cond then
        return if_true
    end
    return if_false
end

function update_action (npc, script, ...)
    local arg = {...}
    if npc == nil then return end
    local act = npc:action ()
    if arg.n == 0 then return end

    if act == nil then act = entity_action () end

    for a = 1, arg.n, 1 do
        if arg[a] ~= nil then act:set_action (arg[a]) end
    end
    reset_action (npc, script)
    npc:command (act, false)

end


function set_current_time (hour, min, sec)
    local current_time_factor = level.get_time_factor ()

    printf ("Need time : %d:%d:%d", hour, min, sec)

    local current_time = game.time ()
    local c_day = math.floor (current_time / 86400000)
    local c_time = current_time - c_day * 86400000
    local n_time = (sec + min * 60 + hour * 3600) * 1000

    if c_time > n_time then c_day = c_day + 1 end
    n_time = n_time + c_day * 86400000

    level.set_time_factor (10000)
    while game.time () < n_time do wait () end

    level.set_time_factor (current_time_factor)
end



if (editor() == false) then
class "pp_effector" (effector)

function pp_effector:__init(effector_type,start_time,dest_power,life_time) super(effector_type,start_time)
    self.start_time = start_time
    self.stop_time  = start_time + life_time
    self.max_power  = dest_power
end

function pp_effector:process(pp)
    effector.process(self,pp)

    local curr_time = time_global()
    local d         = 0.0

    if curr_time < self.start_time then
        d           = 0.0
    else
        if curr_time < self.stop_time then
            d           = (curr_time - self.start_time) / (self.stop_time - self.start_time)
        else
            self.info   = self.max_power
            return      true
        end
    end

    local dual      = duality()
    local noise     = noise()
    local base      = color()
    local gray      = color()
    local add       = color()

    dual.h          = self.max_power.dual.h         * d
    dual.v          = self.max_power.dual.v         * d

    noise.grain     = self.max_power.noise.grain        * d
    noise.intensity     = self.max_power.noise.intensity    * d
    noise.fps       = self.max_power.noise.fps      * d

    base.r          = self.max_power.color_base.r       * d
    base.g          = self.max_power.color_base.g       * d
    base.b          = self.max_power.color_base.b       * d

    gray.r          = self.max_power.color_gray.r       * d
    gray.g          = self.max_power.color_gray.g       * d
    gray.b          = self.max_power.color_gray.b       * d

    add.r           = self.max_power.color_add.r        * d
    add.g           = self.max_power.color_add.g        * d
    add.b           = self.max_power.color_add.b        * d

    pp.gray         = self.max_power.gray           * d
    pp.blur         = self.max_power.blur           * d

    pp.dual         = dual
    pp.noise        = noise
    pp.color_base       = base
    pp.color_gray       = gray
    pp.color_add        = add

    self.info       = pp

    return              true
end

function pp_effector:finished()
    return          self.stop_time < time_global()
end

--
-- postprocess for rainbow
--
class "pp_linear_lerp" (effector)

function pp_linear_lerp:__init(effector_type,start_time,life_time,start_power,dest_power) super(effector_type,start_time)
    self.start_time = start_time
    self.stop_time  = start_time + life_time
    self.min_power  = start_power
    self.max_power  = dest_power
end

function pp_linear_lerp:process(pp)
    effector.process(self,pp)

    local curr_time = time_global()
    local d         = 0.0

    if curr_time < self.start_time then
        d           = 0.0
    else
        if curr_time < self.stop_time then
            d           = (curr_time - self.start_time) / (self.stop_time - self.start_time)
        else
            self.info   = self.max_power
            return      true
        end
    end
    

		local dual      = duality()
		local noise     = noise()
		local base      = color()
		local gray      = color()
		local add       = color()

		dual.h          = self.min_power.dual.h         + (self.max_power.dual.h        - self.min_power.dual.h     )   * d
		dual.v          = self.min_power.dual.v         + (self.max_power.dual.v        - self.min_power.dual.v     )   * d

		noise.grain     = self.min_power.noise.grain        + (self.max_power.noise.grain       - self.min_power.noise.grain    )   * d
		noise.intensity     = self.min_power.noise.intensity    + (self.max_power.noise.intensity   - self.min_power.noise.intensity)   * d
		noise.fps       = self.min_power.noise.fps      + (self.max_power.noise.fps         - self.min_power.noise.fps  )   * d

		base.r          = self.min_power.color_base.r       + (self.max_power.color_base.r      - self.min_power.color_base.r   )   * d
		base.g          = self.min_power.color_base.g       + (self.max_power.color_base.g      - self.min_power.color_base.g   )   * d
		base.b          = self.min_power.color_base.b       + (self.max_power.color_base.b      - self.min_power.color_base.b   )   * d

		gray.r          = self.min_power.color_gray.r       + (self.max_power.color_gray.r      - self.min_power.color_gray.r   )   * d
		gray.g          = self.min_power.color_gray.g       + (self.max_power.color_gray.g      - self.min_power.color_gray.g   )   * d
		gray.b          = self.min_power.color_gray.b       + (self.max_power.color_gray.b      - self.min_power.color_gray.b   )   * d

		add.r           = self.min_power.color_add.r        + (self.max_power.color_add.r       - self.min_power.color_add.r    )   * d
		add.g           = self.min_power.color_add.g        + (self.max_power.color_add.g       - self.min_power.color_add.g    )   * d
		add.b           = self.min_power.color_add.b        + (self.max_power.color_add.b       - self.min_power.color_add.b    )   * d

		pp.gray         = self.min_power.gray           + (self.max_power.gray          - self.min_power.gray       )   * d
		pp.blur         = self.min_power.blur           + (self.max_power.blur          - self.min_power.blur       )   * d

		pp.dual         = dual
		pp.noise        = noise
		pp.color_base       = base
		pp.color_gray       = gray
		pp.color_add        = add

		self.info       = pp

    return          true
end

function pp_linear_lerp:finished()
    return          self.stop_time < time_global()
end
--
-- end of postprocess for rainbow
--

----------------------------------------------------------------------------------------------------------------------
-- Evaluators
----------------------------------------------------------------------------------------------------------------------
-- чрЁхчхЁтшЁютрэv id ё эюьхЁрьш юЄ 0 фю 256 фы  ёючфрэш  ёЄрэфрЁЄэvї ¤трыєрЄюЁют.

--Constant evaluator
class "const_evaluator" (property_evaluator)

function const_evaluator:__init (name, value) super (nil, name)
    self.value = value
end

function const_evaluator:evaluate()
    return          self.value
end

--Wait evaluator
class "wait_evaluator" (property_evaluator)

function wait_evaluator:__init (wait_time) super ()
    self.wait_time = wait_time
    self.first_call = true
    self.current_time = 0
end

function wait_evaluator:evaluate ()
    if self.first_call == true then
       self.first_call = false
       self.current_time = device ():time_global ()
       return false
    end

    local t = device():time_global () - self.current_time;
    if t > self.wait_time then return true end
    return false
end
--------------------------------------------------------------------------------
class "enabled_evaluator" (property_evaluator)

function enabled_evaluator:__init (name, storage) super ()
    self.a = storage
end

function enabled_evaluator:evaluate()
    return  self.a.enabled
end

end -- end of editor() == false


function str_split (str)

		local strlen = string.len (str)

		local parts = {{}, {}, {}, {}}
		local cpart = 1


		for a = 1, strlen, 1 do
				local char = string.byte (str, a)
				if char ~= 95 then
					 table.insert (parts[cpart], char)
				else
					 cpart = cpart + 1
					 if cpart > 4 then break end
				end
		end

		if cpart ~= 4 then return "unknown", "stalker", 0, 0 end

		local str1 = string.char ()
		local str2 = string.char ()
		local str3 = string.char ()
		local str4 = string.char ()

		local ref = parts[1]
		for a = 1, #ref, 1 do
				str1 = string.format ("%s%c", str1, ref[a])
		end

		ref = parts[2]
		for a = 1, #ref, 1 do
				str2 = string.format ("%s%c", str2, ref[a])
		end

		ref = parts[3]
		for a = 1, #ref, 1 do
				str3 = string.format ("%s%c", str3, ref[a])
		end

		ref = parts[4]
		for a = 1, #ref, 1 do
				str4 = string.format ("%s%c", str4, ref[a])
		end

		printf ("%s %s %d %d", str1, str2, str3, str4)
		return str1, str2, (str3 + 1) - 1, (str4 + 1) - 1
end

function random_number (min_value, max_value)
		math.randomseed (device ():time_global ())
		if min_value == nil and max_value == nil then
			return math.random ()
		else
			return math.random (min_value, max_value)
		end
end

-- Время суток в мс
-- Чугай
local ms_per_day = 24 * 60 * 60 * 1000
function day_time()
    return math.mod( game.time(), ms_per_day )
end

--Time in hours
function local_hours()
    return math.floor( math.mod( game.time()/1000, 86400 )/ 3600 )
end

-- парсит строку вида "ааа, ббб, ввв..." в таблицу { "ааа", "ббб", "ввв", ... }
-- Чугай
function parse_names( s )
    local t = {}
    for name in string.gfind( s, "([%w_\\]+)%p*" ) do
    --for name in string.gfind( s, "%s*([^%,]+)%s*" ) do
        table.insert( t, name )
    end

    return t
end


function parse_key_value( s )
    local t = {}
	if s == nil then
		return nil
	end
    local key, nam = nil, nil
    for name in string.gfind( s, "([%w_\\]+)%p*" ) do
		if key == nil then
			key = name
		else
			t[key] = name
			key = nil
		end
    end
    return t
end

function empty (container)
	if (type(container) == "function") then
		for i in container do
			return (false)
		end
		return  (true)
	end
	if (container[1] ~= nil) then
		return  (false)
	end
	for i,j in pairs(container) do
		return  (false)
	end
	return   (true)
end

-- парсит строку вида "n1, n2, n3..." в таблицу { n1, n2, n3, ... } где n1, n2, n3... - целые числа
-- Чугай
--[[function parse_nums( s )
    local t = {}

    for entry in string.gfind( s, "([%w_\\]+)%p*" ) do
        table.insert( t, tonumber( entry ) )
    end

    return t
end]]

-- парсит строку вида "n1, n2, n3..." в таблицу { n1, n2, n3, ... } где n1, n2, n3... - дробные числа
function parse_nums( s )
	local t = {}

	for entry in string.gfind( s, "([%-%d%.]+)%,*" ) do
		table.insert( t, tonumber( entry ) )
	end

	return t
end

-- проверяет, есть ли объект в онлайне
function is_object_online(obj_id)
	return level.object_by_id(obj_id) ~= nil
end

function get_clsid(npc)
    if npc == nil then return nil end

	return npc:clsid()

--    if is_object_online(npc:id()) then
--      return npc:clsid()
--    else
--        return nil
--    end
end

--Tvўшёы хЄ yaw т Ёрфшрэрї
function yaw( v1, v2 )
    return  math.acos( ( (v1.x*v2.x) + (v1.z*v2.z ) ) / ( math.sqrt(v1.x*v1.x + v1.z*v1.z ) * math.sqrt(v2.x*v2.x + v2.z*v2.z ) ) )
end

function yaw_degree( v1, v2 )
    return  (math.acos( ( (v1.x*v2.x) + (v1.z*v2.z ) ) / ( math.sqrt(v1.x*v1.x + v1.z*v1.z ) * math.sqrt(v2.x*v2.x + v2.z*v2.z ) ) ) * 57.2957)
end
function yaw_degree3d( v1, v2 )
    return  (math.acos((v1.x*v2.x + v1.y*v2.y + v1.z*v2.z)/(math.sqrt(v1.x*v1.x + v1.y*v1.y + v1.z*v1.z )*math.sqrt(v2.x*v2.x + v2.y*v2.y + v2.z*v2.z)))*57.2957)
end

function vector_cross(v1, v2)
    return vector():set(v1.y  * v2.z  - v1.z  * v2.y, v1.z  * v2.x  - v1.x  * v2.z, v1.x  * v2.y  - v1.y  * v2.x)
end

--TЁр	рхЄ тхъЄюЁ тюъЁєу юёш y яЁюЄшт ўрёютющ ёЄЁхыъш

function vector_rotate_y(v, angle)
    angle = angle * 0.017453292519943295769236907684886
    local c = math.cos (angle)
    local s = math.sin (angle)
    return vector ():set (v.x * c - v.z * s, v.y, v.x * s + v.z * c)
end

-- юўшёЄър ЄрсышЎv
function clear_table (t)
    while #t > 0 do
          table.remove (t, #t)
    end
end

--Использует для монстров. Выбор точки, куда идти в некотором радиусе и чтоб точка была дальше на расстоянии
-- min_radius от текущей позиции(если это получится). center_id - центр позиции, вокруг которой живем,
-- position_id - тукущая позиция, radius - в каком радиусе выбирать точку, min_radius - минимальное расстояние, от текущей позиции до новой точки.
function new_point(center_id, position_id,radius, min_radius)
    local dir = vector():set(math.random(-1000, 1000)/1000.0, 0.0001, math.random(-1000, 1000)/1000.0)
    local pos = level.vertex_in_direction(center_id, dir, radius)
    local i   = 1
	printf("vertex_position")
    while(level.vertex_position(position_id):distance_to(level.vertex_position(pos) ) < min_radius and i < 20) do
        dir = vector():set(math.random(-1000, 1000)/1000.0, 0.0001, math.random(-1000, 1000)/1000.0)
        pos = level.vertex_in_direction(center_id, dir, radius)
        i   = i + 1
    end

    return (level.vertex_position(pos))
end

function stop_play_sound(obj)
	if obj:alive() == true then
		obj:set_sound_mask(-1)
		obj:set_sound_mask(0)
	end
end

--возвращает произвольную точку пути у которой установлен бит
function point_with_bit(patrol_path, bit, old_point)      -- old_point - индекс точки, которую не надо выбирать,
	local points = {}                                       -- параметр не обязательный( например текущей точки )

		for i = 0, patrol_path:count()-1 do
			--Добовляем в таблицу точки с нужным битом
			if( patrol_path:flag(i, bit)) then
						--Добавляем точку если old_point == nil или новая точка не совпадает с old_point
						if(old_point == nil) then
								table.insert(points, patrol_path:point(i))
						elseif(old_point ~= i) then
								table.insert(points, patrol_path:point(i))
						end
				end
		end

		local number_point = #points

		if(number_point == 0) then
				return nil
		elseif(number_point == 1) then
				return points[1]
		else
				return points[math.random(1, number_point)]
		end
end

--возвращает произвольную точку пути у которой установлен бит
function point_with_bit_id(patrol_path, bit, old_point)        -- old_point - индекс точки, которую не надо выбирать,
    local points = {}                                          -- параметр не обязательный( например текущей точки )

    for i = 0, patrol_path:count()-1 do
      --Добовляем в таблицу точки с нужным битом
      if( patrol_path:flag(i, bit)) then
            --Добавляем точку если old_point == nil или новая точка не совпадает с old_point
            if(old_point == nil) then
                table.insert(points, i)
            elseif(old_point ~= i) then
                table.insert(points, i)
            end
        end
    end

    local number_point = #points

    if(number_point == 0) then
        return nil
    elseif(number_point == 1) then
        return patrol_path:level_vertex_id(points[1])
    else
        return patrol_path:level_vertex_id(points[math.random(1, number_point)])
    end
end

--Возвращает индекс самой ближней точки пути с заданым битом, от текущей точки
function near_point_with_bit(point, patrol_path, bit)
    local new_point = nil
    local index     = nil
    local dist      = 1000.0

    for i = 0, patrol_path:count()-1 do
        if( patrol_path:flag(i, bit) ) then
            if(new_point == nil or patrol_path:point(i):distance_to(point) < dist) then
                --Если эта точка первая из нашедшихся, либо от нее путь ближе, то запоминаем ее
                new_point   = patrol_path:point(i)
                index       = i
                dist        = new_point:distance_to(point)
             end
        end
    end

    return index
end

-- Рекурсивная распечатка таблицы
function print_table(table, subs)
  local sub
  if subs ~= nil then
    sub = subs
  else
    sub = ""
  end
  for k,v in pairs(table) do
    if type(v) == "table" then
      printf(sub.."%s:", tostring(k))
      print_table(v, sub.."    ")
    elseif type(v) == "function" then
      printf(sub.."%s:function", tostring(k))
    elseif type(v) == "userdata" then
      printf(sub.."%s:userdata", tostring(k))
    elseif type(v) == "boolean" then
	if v == true then
		printf(sub.."%s:true", tostring(k))
	else
		printf(sub.."%s:false", tostring(k))
	end
    else
      if v ~= nil then
        printf(sub.."%s:%s", tostring(k),v)
      else
        printf(sub.."%s:nil", tostring(k),v)
      end
    end
  end
end


function store_table(table, subs)
	local sub
	if subs ~= nil then
		sub = subs
	else
		sub = ""
	end
	printf(sub.."{")
	for k,v in pairs(table) do
		if type(v) == "table" then
			printf(sub.."%s = ", tostring(k))
			store_table(v, sub.."    ")
		elseif type(v) == "function" then
			printf(sub.."%s = \"func\",", tostring(k))
	    elseif type(v) == "userdata" then
      		printf(sub.."%s = \"userdata\",", tostring(k))
		elseif type(v) == "string" then
			printf(sub.."%s = \"%s\",", tostring(k), tostring(v))
		else
			printf(sub.."%s = %s,", tostring(k), tostring(v))
		end
	end
	printf(sub.."},")
end

-------------------------------------------------------------------------------------------
function switch_online (id)
    if id == -1 then return end
    local sim = alife ()
    if sim ~= nil then
       sim:set_switch_online  (id, true)
       sim:set_switch_offline (id, false)
    end
end
-------------------------------------------------------------------------------------------
function switch_offline (npc)
    if npc == nil or npc:alive () == false then return end
    local sim = alife ()
    if sim ~= nil then
       sim:set_switch_online  (npc:id (), false)
       sim:set_switch_offline (npc:id (), true)
    end
end
-------------------------------------------------------------------------------------------
function get_actor_id()
	if(level.actor() == nil) then return -1 end
	return level.actor():id()
end
-------------------------------------------------------------------------------------------
local monster_classes = {}
local stalker_classes = {}
local weapon_classes = {}
local artefact_classes = {}

function IsMonster (object, class_id)
    local id = class_id or get_clsid(object)
    return monster_classes[id] == true
end
function IsStalker (object, class_id)
    local id = class_id or get_clsid(object)
    return stalker_classes[id] == true
end

function isWeapon(object, class_id)
    local id = class_id or get_clsid(object)
	return weapon_classes[id] == true
end

function isArtefact(object, class_id)
    local id = class_id or get_clsid(object)
	return artefact_classes[id] == true
end


-------------------------------------------------------------------------------------------
function level_object_by_sid( sid )
	local sim = alife()

	if sim then
		local se_obj = sim:story_object( sid )
		if se_obj then
			return level.object_by_id( se_obj.id )
		end
	end

	return nil
end

function id_by_sid( sid )
	local sim = alife()

	if sim then
		local se_obj = sim:story_object( sid )
		if se_obj then
			return se_obj.id
		end
	end

	return nil
end

-- │Ёх°эєЄ№ шуЁє (яюёых тvтюфр ёююс	хэш  юс ю°шсъх т ыюу)
function abort(fmt, ...)
  local reason = string.format(fmt, ...)
  assert("ERROR: " .. reason)
  error_log("ERROR: " .. reason)
  log(string.format("%s",nil))
--  get_console():execute("load ~~~ " .. reason)
--  get_console():execute("flush")
--  string.format("%s")
end

function set_postprocess(name_ini_file)
	bind_stalker.post_process = postprocess.PostProcess(ini_file(name_ini_file))
end
function remove_postprocess()
	bind_stalker.post_process = nil
end

function set_inactivate_input_time(delta)
	db.storage[db.actor:id()].disable_input_time = game.get_game_time()
	db.storage[db.actor:id()].disable_input_idle = delta
	level.disable_input()
end
-- │ЁшэшьрхЄ: яючшЎш│ яюыюцхэш , яючшЎш│ ъєфр ёьюЄЁхЄ№, тЁхь  ёэр т ьшэєЄрї.
function set_sleep_relocate(point, look, timeout)
	db.storage[db.actor:id()].sleep_relocate_time = game.get_game_time()
	db.storage[db.actor:id()].sleep_relocate_idle = timeout*60
	db.storage[db.actor:id()].sleep_relocate_point = point
	db.storage[db.actor:id()].sleep_relocate_look = look

	--set_inactivate_input_time(timeout*60)
	--db.actor:actor_sleep(0, timeout)
end

-- яЁютхЁ хЄ Ўхыє│ ўрёЄ№ ўшёыр эр эхў┐ЄэюёЄ№
function odd( x )
	return math.floor( x * 0.5 ) * 2 == math.floor( x )
end


--' =рїюфшЄё  ыш =│T тю ЇЁєёЄЁєьх шуЁюър
function npc_in_actor_frustrum(npc)
	local actor_dir = device().cam_dir
	--local actor_dir = db.actor:direction()
	local npc_dir = npc:position():sub(db.actor:position())

	local yaw = yaw_degree3d(actor_dir, npc_dir)
	--printf("YAW %s", tostring(yaw))

	return yaw < 35
end

--' LёЄрыюёЄ№
function on_actor_critical_power()

end

function on_actor_critical_max_power()
end

--' │ЁютюЄхўхэшх
function on_actor_bleeding()

end

function on_actor_satiety()
end

--' │рфшрЎш 
function on_actor_radiation()

end

--' │ръышэшыю юЁєцшх
function on_actor_weapon_jammed()

end

--' эх ьюцхЄ їюфшЄ№ шччр тхёр
function on_actor_cant_walk_weight()

end

--' яёш тючфхщёЄтшх
function on_actor_psy()
end

function set_actor_rank(rank)
	if rank == "novice" then
		db.actor:set_character_rank(0)
	elseif rank == "stalker" then
		db.actor:set_character_rank(300)
	elseif rank == "veteran" then
		db.actor:set_character_rank(600)
	elseif rank == "master" then
		db.actor:set_character_rank(900)
	end
end

function get_texture_info(id_name, id_default)
	if id_default == nil then id_default = id_name end

	local task_info = GetTextureInfo(id_name, id_default)
	local r = task_info:get_rect()

	r.x2 = r.x2 - r.x1
	r.y2 = r.y2 - r.y1
	return task_info:get_file_name(), r
end

function start_game_callback()
	aa = alife()
	
	amk.on_game_start(obj)

monster_classes = {
	[clsid.bloodsucker_s] 			= true,
	[clsid.boar_s] 					= true,
	[clsid.dog_s] 					= true,
	[clsid.flesh_s] 				= true,
	[clsid.pseudodog_s] 			= true,
	[clsid.burer_s] 				= true,
	[clsid.cat_s] 					= true,
	[clsid.chimera_s] 				= true,
	[clsid.controller_s] 			= true,
	[clsid.fracture_s] 				= true,
	[clsid.poltergeist_s] 			= true,
	[clsid.gigant_s] 				= true,
	[clsid.zombie_s] 				= true,
	[clsid.snork_s] 				= true,
	[clsid.tushkano_s] 				= true,
	[clsid.psy_dog_s] 				= true,
	[clsid.psy_dog_phantom_s] 		= true}

stalker_classes = {
	[clsid.script_actor] 			= true,
	[clsid.script_stalker] 			= true}

weapon_classes = {
	[clsid.wpn_vintorez_s] 			= true,
    [clsid.wpn_ak74_s] 				= true,
    [clsid.wpn_lr300_s] 			= true,
    [clsid.wpn_hpsa_s] 				= true,
    [clsid.wpn_pm_s] 				= true,
    [clsid.wpn_shotgun_s] 			= true,
    [clsid.wpn_bm16_s] 				= true,
    [clsid.wpn_svd_s] 				= true,
    [clsid.wpn_svu_s] 				= true,
    [clsid.wpn_rpg7_s] 				= true,
    [clsid.wpn_val_s] 				= true,
    [clsid.wpn_walther_s] 			= true,
    [clsid.wpn_usp45_s] 			= true,
    [clsid.wpn_groza_s] 			= true,
    [clsid.wpn_knife_s] 			= true,
    [clsid.wpn_grenade_launcher] 	= true,
    [clsid.wpn_grenade_f1] 			= true,
    [clsid.wpn_grenade_rpg7] 		= true,
    [clsid.wpn_grenade_rgd5] 		= true,
    [clsid.wpn_grenade_fake] 		= true}

artefact_classes = {
    [clsid.art_bast_artefact] 		= true,
    [clsid.art_black_drops] 		= true,
    [clsid.art_dummy] 				= true,
    [clsid.art_electric_ball] 		= true,
    [clsid.art_faded_ball] 			= true,
    [clsid.art_galantine] 			= true,
    [clsid.art_gravi] 				= true,
    [clsid.art_gravi_black] 		= true,
    [clsid.art_mercury_ball] 		= true,
    [clsid.art_needles] 			= true,
    [clsid.art_rusty_hair] 			= true,
    [clsid.art_thorn] 				= true,
    [clsid.art_zuda] 				= true,
    [clsid.artefact] 				= true,
    [clsid.artefact_s] 				= true}


	printf	("start_game_callback called")
	smart_names.init_smart_names_table()
	task_manager.clear_task_manager()
	treasure_manager.load_treasures()

    sound_theme.load_sound()
    xr_sound.start_game_callback()

	dialog_manager.fill_phrase_table()
	xr_s.init()                              --' Distemper 03.2008 --
	sim_objects.clear()
	sim_board.clear()

    sr_light.clean_up ()


	-- TхёЄшЁютрэшх юяЄшьшчрЎшш
	--local test_object = test_object.test_object_class()
	--test_object:test()
end

function gi (info)
	db.actor:give_info_portion(info)
end

ammo_section = {}
ammo_section["ammo_9x18_fmj"]		= true
ammo_section["ammo_9x18_pbp"]		= true
ammo_section["ammo_9x18_pmm"]		= true
ammo_section["ammo_9x19_fmj"]		= true
ammo_section["ammo_9x19_pbp"]		= true
ammo_section["ammo_5.45x39_fmj"]	= true
ammo_section["ammo_5.45x39_ap"]		= true
ammo_section["ammo_5.56x45_ss190"]	= true
ammo_section["ammo_5.56x45_ap"]		= true
ammo_section["ammo_5.7x28_fmj"]		= true
ammo_section["ammo_5.7x28_ap"]		= true
ammo_section["ammo_7.62x54_7h1"]	= true
ammo_section["ammo_7.62x54_ap"]		= true
ammo_section["ammo_7.62x54_7h14"]	= true
ammo_section["ammo_9x39_pab9"]		= true
ammo_section["ammo_gauss"]			= true
ammo_section["ammo_9x39_ap"]		= true
ammo_section["ammo_9x39_sp5"]		= true
ammo_section["ammo_11.43x23_fmj"]	= true
ammo_section["ammo_11.43x23_hydro"]	= true
ammo_section["ammo_12x70_buck"]		= true
ammo_section["ammo_12x76_dart"]		= true
ammo_section["ammo_12x76_zhekan"]	= true
ammo_section["ammo_pkm_100"]	= true
-- ADDED BY IZTARI
ammo_section["grenade_f1"]	= true
ammo_section["grenade_rgd5"]	= true
ammo_section["grenade_gd-05"]	= true

quest_section = {}

function get_param_string(src_string , obj)
	--printf("src_string is [%s] obj name is [%s]", tostring(src_string), obj:name())
	local script_ids = db.script_ids[obj:id()]
	local out_string, num = string.gsub(src_string, "%$script_id%$", tostring(script_ids))
	if num > 0 then
		return out_string , true
	else
		return src_string , false
	end
end

local save_markers = {}

-- LєэъЎшш фы  яЁютхЁъш ъюЁЁхъЄэюёЄш ёхщт ыюрф
function set_save_marker(p, mode, check, prefix)

	-- +яЁхфхы хь ъы│ў ьрЁъхЁр.
	local result = ""
--	if debug ~= nil then
--		local info_table = debug.getinfo(2)
--		local script_name = string.gsub(info_table.short_src, "%.script", "")
--		script_name = string.gsub(script_name, "gamedata\\scripts\\", "")
--		result = script_name
--	end

--	if prefix ~= nil then
		result = result .. "_" .. prefix
--	end

	if check == true then
		if save_markers[result] == nil then
			abort("Trying to check without marker %s", result)
		end

		if mode == "save" then
			local dif = p:w_tell() - save_markers[result]
			printf(result..": SAVE DIF: %s", dif)
			if dif >= 8000 then
				printf("WARNING! may be this is problem save point")
			end
			if dif >= 10240 then
				abort("You are saving too much")
			end
			p:w_u16(dif)
		else
			local c_dif = p:r_tell() - save_markers[result]
			local dif = p:r_u16()
			 if dif ~= c_dif then
			 	abort("INCORRECT LOAD [%s].[%s][%s]", result, dif, c_dif)
			 else
			 	printf(result..": LOAD DIF: %s", dif)
			 end
		end
		return
	end

	if mode == "save" then
		printf(result..": set save marker: %s", p:w_tell())
		save_markers[result] = p:w_tell()
		if p:w_tell() > 16000 then
			abort("You are saving too much")
		end
	else
		printf(result..": set load marker: %s", p:r_tell())
		save_markers[result] = p:r_tell()
	end
 
end

function vec_to_str (vector)
	if vector == nil then return "nil" end
	return string.format("[%d:%d:%d]", vector.x, vector.y, vector.z)
end

function callstack()
	if debug ~= nil then
		log(debug.traceback(2))
	end
end

function change_team_sqaud_group(se_obj, team, squad, group)
	local cl_obj = db.storage[se_obj.id] and db.storage[se_obj.id].object
	if cl_obj ~= nil then
		cl_obj:change_team(team, squad, group)
	else
		se_obj.team = team
		se_obj.squad = squad
		se_obj.group = group
	end
	--printf("_G:TSG: [%s][%s][%s]", tostring(se_obj.team), tostring(se_obj.squad), tostring(se_obj.group))
end

