----------------------------------------------------------------------------------------------------
-- Script switching logic
----------------------------------------------------------------------------------------------------
-- Разработчик: Andrey Fidrya (Zmey) af@svitonline.com
----------------------------------------------------------------------------------------------------
--function printf()
--end

--[[
----------------------------------------------------------------------------------------------------
-- ФУНКЦИИ, КОТОРЫЕ РАЗРЕШЕНО ВЫЗЫВАТЬ ИЗ ДРУГИХ СКРИПТОВ
----------------------------------------------------------------------------------------------------
	Активация схем производится с помощью функций:

function gulag_activate(npc, ini, section, gulag_name, death, combat, actor_dialogs, trade, hit)
Предназначение:
	активирует заданную схему, используется схемой гулаг. Тип скрипта определяется автоматически по имени секции.
Здесь:
	npc - персонаж, для которого будет активирована схема
	ini - его customdata
	section - имя секции, которая должна быть активирована
	gulag_name - имя гулага, которое будет добавлено спереди к именам путей
	death, combat, actor_dialogs, trade, hit - имена секций, задающих поведение при смерти и в бою

function assign_storage_and_bind(npc, ini, scheme, section)
Предназначение:
	Вызывает функцию add_to_binder схемы, а также создает (если его еще нет) и возвращает ссылку на storage
	для схемы. Примечание: в storage при этом могут оставаться старые данные, схема должна очистить его
	самостоятельно.

function subscribe_action_for_events(npc, storage, new_action)
Предназначение:
	Регистрирует класс для получения нотификаций о таких событиях как сброс схемы, сохранение и т.д.
	Класс реализует соответствующие функции (reset_scheme() и т.д.), которые будут вызываться из xr_logic
	в нужные моменты.

function pick_section_from_condlist(actor, npc, condlist)
Предназначение:
	Проверяет условия condlist, и если они успешны - ставит указанные infoportions и возвращает текст.
	Если условия не выполняются - возвращает nil.

function try_switch_to_another_section(npc, st, actor)
Предназчанение:
	Используя настройки xr_logic из storage персонажа, пытается переключить его на другую схему, если
	хоть одно из условий переключения сработало. Обычно вызывается из метода update класса персонажа.

function is_active(npc, st)
Предназначение:
	Вызывается из evaluator-а (или в самом начале update у предметов и монстров) для проверки, что данная
	схема сейчас активна (схема определяется по данным в storage).

function cfg_get_switch_conditions(ini, section, npc)
Предназначение:
	Считывает все возможные условия переключения схем.

function parse_condlist(npc, section, field, src)
Предназначение:
	Распарсивает условия вида: {+infop1} section1 %-infop2%, {+infop3 -infop4} section2 ... в таблицу.
	Параметры section и field используются только в сообщениях об ошибках. Если строка src считана не из файла,
	а передается в эту функцию гулагом, то нужно задать следующие параметры:
--]]
--		section = "[[[gulag_tasks.script]]]"
--		field = "[[[gulag_name=имя_гулага]]]"
--[[
----------------------------------------------------------------------------------------------------
-- ПРИВАТНЫЕ ФУНКЦИИ
----------------------------------------------------------------------------------------------------

function activate_by_section(npc, ini, section, loading)
Предназначение:
	Активирует указанную секцию. Если в данный момент какая-либо секция уже активирована, сообщает об ошибке.

function switch_to_section(npc, st, section)
Предназначение:
	Выполняет переключение с одной секции на другую, если новая секция не nil. Если же она nil, остается
	активной старая секция.

function abort_syntax_error_in_cond(npc, section, field)
Предназначение:
	Сообщает о синтаксической ошибке в условиях переключения схем секции section и поля field, и останавливает
	игру.

function parse_infop(rslt, str)
Предназначение:
	Распарсивает условия вида " +infop1 =func -infop2 " и т.д. (все не перечислены) в таблицу.

function cfg_get_number_and_condlist(ini, section, field, npc)
function cfg_get_string_and_condlist(ini, section, field, npc)
function cfg_get_condlist(ini, section, field, npc)
Предназначение:
	Считывает из customdata различные условия переключения схем.

function add_condition(lst, at, cond)
Предназначение:
	Добавляет условие в список условий переключения схем.

function cfg_get_overrides(ini, section, npc)
Предназначение:
	Считывает настройки для схем общего поведения.

function generic_scheme_overrides(npc)
Предназначение:
	Возвращает ссылку на настройки схем общего поведения, актуальные для работающей в данный момент схемы,
	либо nil, если ни одна из секций не активна, либо настройки не заданы.

--]]

--[[
-- Предназначение:
--      вызывается при включении набора скриптов через секцию logic у персонажа. Если в секции logic присутствует только
--      поле cfg, использует конфигурационный файл, заданный в этом поле, и возвращает новый ini file.
-- Здесь:
--	npc - персонаж, для которого будет активирована схема
--	ini - его customdata
--	stype - тип скрипта. Поскольку имя секции все еще неизвестно, его нужно задавать явно. Допустимые значения
--	        перечислены в файле modules.script.
--	section - имя секции logic
--	gulag_name - имя гулага, если скрипт включается гулагом, а не биндером
--]]--
function configure_schemes(npc, ini, ini_filename, stype, section_logic, gulag_name)
	--printf("DEBUG: enable_scripts: npc:name()=%s", npc:name())

	local npc_id = npc:id()
	local st     = db.storage[npc_id]

	-- если какая-то схема была до этого активна, деактивировать её
	if st.active_section then
		issue_event(npc, st[st.active_scheme], "deactivate", npc)
	end

	local actual_ini
	local actual_ini_filename
	if not ini:section_exist(section_logic) then
		if gulag_name == "" then
			-- Общие схемы должны работать и без logic:
			actual_ini_filename = ini_filename
			actual_ini = ini -- персонаж не обязательно должен иметь секцию logic
		else
			-- Иначе это персонаж Gulag-а и ему не задали работу:
			abort("ERROR: object '%s': unable to find section '%s' in '%s'", npc:name(), section_logic, tostring(ini_filename))
		end
	else
		local filename = utils.cfg_get_string(ini, section_logic, "cfg", npc, false, "")
		if filename then
			actual_ini_filename = filename
			actual_ini = ini_file(filename)
			if not actual_ini:section_exist(section_logic) then
				abort("object '%s' configuration file [%s] NOT FOUND or section [logic] isn't assigned ", npc:name(), filename)
			end
			--printf("_bp: enable_scripts: object '%s' has external configuration file '%s'", npc:name(), filename)
			-- Рекурсивно обработать конфигурационный файл, на который ссылается поле cfg


			return configure_schemes(npc, actual_ini, actual_ini_filename, stype, section_logic, gulag_name)
			--[[
			if actual_ini:line_count(section_logic) == 0 then
				abort("file '%s' does not exist or is empty, or has no section '%s'",
					filename, section_logic)
			end
			]]--

		else
			if stype == modules.stype_stalker or stype == modules.stype_mobile then
				local current_smart = xr_gulag.get_npc_smart(npc)
				if current_smart ~= nil then
					local t = current_smart:getJob(npc_id)
					if t then
						st.job_ini = t.ini_path
					else
						st.job_ini = nil
					end
				end
			end
			--printf("_bp: enable_scripts: object '%s' has NO external configuration file, using '%s'", npc:name(), ini_filename)
			actual_ini_filename = ini_filename
			actual_ini = ini
		end
	end

	-- Поскольку в момент активации схемы могли работать ранее установленные общие схемы, нужно их все отключить:
	disable_generic_schemes(npc, stype)
	-- Включаем все общие схемы (раненный, коллбек на попадание и т.д.):
	enable_generic_schemes(actual_ini, npc, stype, section_logic)

	-- Инициализация торговли
	if stype == modules.stype_stalker or
	   npc:clsid() == clsid.script_trader
	then
		local trade_ini = utils.cfg_get_string(actual_ini, section_logic, "trade", npc, false, "", "misc\\trade_generic.ltx")
		trade_manager.trade_init(npc, trade_ini)
	end

	st.active_section = nil
	st.active_scheme = nil
	st.gulag_name = gulag_name

	st.stype = stype
	st.ini = actual_ini
	st.ini_filename = actual_ini_filename
	st.section_logic = section_logic

	return st.ini
end

-- Вызывается биндером с целью определить первую активную схему
function determine_section_to_activate(npc, ini, section_logic, actor)
	if not ini:section_exist(section_logic) then
		return "nil"
	end

	-- Распарсить строку выбора активной секции с учетом команд, заключенных в %%
	local active_section_cond = cfg_get_condlist(ini, section_logic, "active", npc)
	local active_section
	if not active_section_cond then
		return "nil"
		--'abort("object '%s': section '%s': unable to find field 'active'", npc:name(), section_logic)
	else
		active_section = pick_section_from_condlist(actor, npc, active_section_cond.condlist)
		if not active_section then
			abort("object '%s': section '%s': section 'active' has no conditionless else clause",
				npc:name(), section_logic)
		end
	end
	return active_section
end

------------------------------------------------------------------------------------------------------------
-- ВНОСЯ ИЗМЕНЕНИЯ В ЭТУ ФУНКЦИЮ, НЕ ЗАБЫВАЙТЕ ДОБАВЛЯТЬ СООТВЕТСТВУЮЩИЕ СТРОКИ И В enable_generic_schemes
------------------------------------------------------------------------------------------------------------
function disable_generic_schemes(npc, stype)
	if stype == modules.stype_stalker then
		xr_combat.disable_scheme(npc, "combat")
		xr_use.disable_scheme(npc, "use")
		xr_hit.disable_scheme(npc, "hit")
		xr_meet.disable_scheme(npc, "actor_dialogs")
		--'xr_heli_hunter.disable_scheme(npc, "heli_hunter")
		xr_combat_ignore.disable_scheme(npc, "combat_ignore")
		stalker_generic.disable_invulnerability(npc)
	elseif stype == modules.stype_mobile then
		mob_combat.disable_scheme(npc, "mob_combat")
		xr_combat_ignore.disable_scheme(npc, "combat_ignore")
		stalker_generic.disable_invulnerability(npc)
	elseif stype == modules.stype_trader then
		mob_trade.disable_scheme(npc, "mob_trade")
	elseif stype == modules.stype_item then
		ph_on_hit.disable_scheme(npc, "ph_on_hit")
	elseif stype == modules.stype_heli then
		xr_hit.disable_scheme(npc, "hit")
	end
end

------------------------------------------------------------------------------------------------------------
-- ВНОСЯ ИЗМЕНЕНИЯ В ЭТУ ФУНКЦИЮ, НЕ ЗАБЫВАЙТЕ ДОБАВЛЯТЬ СООТВЕТСТВУЮЩИЕ СТРОКИ И В disable_generic_schemes
------------------------------------------------------------------------------------------------------------
 function enable_generic_schemes(ini, npc, stype, section)
	if stype == modules.stype_stalker then
		--xr_reactions.set_reactions(npc, ini, "reactions", section)
		xr_danger.set_danger(npc, ini, "danger", "danger")

		local combat_section = utils.cfg_get_string(ini, section, "on_combat", npc, false, "")
		xr_combat.set_combat_checker(npc, ini, "combat", combat_section)

		stalker_generic.reset_invulnerability(npc, ini, section)

		local use_section = utils.cfg_get_string(ini, section, "on_use", npc, false, "")
		if use_section then
			xr_use.set_use_checker(npc, ini, "use", use_section)
		end
		local info_section = utils.cfg_get_string(ini, section, "info", npc, false, "")
		if info_section then
			stalker_generic.set_npc_info(npc, ini, "info", info_section)
		end

		local hit_section = utils.cfg_get_string(ini, section, "on_hit", npc, false, "")
		if hit_section then
			xr_hit.set_hit_checker(npc, ini, "hit", hit_section)
		end

		local actor_dialogs_section = utils.cfg_get_string (ini, section, "actor_dialogs", npc, false, "")
		if actor_dialogs_section then
			xr_meet.set_actor_dialogs(npc, ini, "actor_dialogs", actor_dialogs_section)
		end

		local wounded_section = utils.cfg_get_string (ini, section, "wounded", npc, false, "")
		xr_wounded.set_wounded (npc, ini, "wounded", wounded_section)

		xr_abuse.set_abuse(npc, ini, "abuse", section)

		local meet_section = utils.cfg_get_string (ini, section, "meet", npc, false, "")
		xr_meet.set_meet (npc, ini, "meet", meet_section)

		local death_section = utils.cfg_get_string (ini, section, "on_death", npc, false, "")
		xr_death.set_death (npc, ini, "death", death_section)

		--'local heli_hunter_section = utils.cfg_get_string(ini, section, "heli_hunter", npc, false, "")
		--'xr_heli_hunter.set_scheme(npc, ini, "heli_hunter", heli_hunter_section)

		xr_combat_ignore.set_combat_ignore_checker(npc, ini, "combat_ignore")

	elseif stype == modules.stype_mobile then
		local combat_section = utils.cfg_get_string(ini, section, "on_combat", npc, false, "")
		if combat_section then
			mob_combat.set_scheme(npc, ini, "mob_combat", combat_section)
		end

		local death_section = utils.cfg_get_string(ini, section, "on_death", npc, false, "")
		mob_death.set_scheme(npc, ini, "mob_death", death_section)

		stalker_generic.reset_invulnerability(npc, ini, section)

		local hit_section = utils.cfg_get_string(ini, section, "on_hit", npc, false, "")
		if hit_section then
			xr_hit.set_hit_checker(npc, ini, "hit", hit_section)
		end

		xr_combat_ignore.set_combat_ignore_checker(npc, ini, "combat_ignore")

	elseif stype == modules.stype_trader then
		local trade_section = utils.cfg_get_string(ini, section, "on_trade", npc, false, "")
		if trade_section then
			mob_trade.set_scheme(npc, ini, "mob_trade", trade_section)
		end

	elseif stype == modules.stype_item then
		local hit_section = utils.cfg_get_string(ini, section, "on_hit", npc, false, "")
		--printf("HIT SECTION [%s]", tostring(hit_section))
		if hit_section then
			ph_on_hit.set_scheme(npc, ini, "ph_on_hit", hit_section)
		end

	elseif stype == modules.stype_heli then
		local hit_section = utils.cfg_get_string(ini, section, "on_hit", npc, false, "")
		if hit_section then
			xr_hit.set_hit_checker(npc, ini, "hit", hit_section)
		end
	end
end

-- Существует два способа вызова функции: с передаванием секции или без нее
-- В обоих случаях передавать gulag_name ОБЯЗАТЕЛЬНО
-- Если section не передана, то она берется из работы переданного гулага.
function activate_by_section(npc, ini, section, gulag_name, loading)
	--printf("LOGIC[%s]: Object '%s': activate_by_section: looking for section '%s'", tostring(time_global()), npc:name(), section)

	if loading == nil then
		abort("xr_logic: activate_by_section: loading field is nil, true or false expected")
	end

	local npc_id = npc:id()
	if not loading then
		db.storage[npc_id].activation_time = time_global()
		-- GAMETIME added by Stohe.
		db.storage[npc_id].activation_game_time = game.get_game_time()
	end

	if section == "nil" then
		db.storage[npc_id].overrides = nil
		reset_generic_schemes_on_scheme_switch(npc, "nil", "nil")
		db.storage[npc_id].active_section = nil
		db.storage[npc_id].active_scheme = nil
--'		db.storage[npc_id].pstor = nil
		return
	end

	if section == nil then
		local current_gulag = xr_gulag.get_npc_smart(npc)
		if current_gulag == nil then
			abort("xr_logic: activate_by_section: section is NIL and NPC not in gulag.")
		end
		local t = current_gulag:getJob(npc_id)
		section = t.section
	end

	if not ini:section_exist(section) then
		abort("object '%s': activate_by_section: section '%s' does not exist", npc:name(), section)
	end

	local scheme = utils.get_scheme_by_section(section)
	if scheme == nil then
		abort("object '%s': unable to determine scheme name from section name '%s'", npc:name(), section)
	end

	-- Загрузить оверрайды:
	db.storage[npc_id].overrides = cfg_get_overrides(ini, section, npc)

	-- Сбросить общие схемы:
	reset_generic_schemes_on_scheme_switch(npc, scheme, section)


	-- schemes[scheme] даст имя файла (модуля), в котором реализована схема
	-- _G[] даст указатель на неймспейс (таблицу) этого модуля
	local filename = schemes[scheme]
	if filename == nil then
		abort("xr_logic: scheme '%s' is not registered in modules.script", scheme)
	end
	--printf("_bp: calling module('%s')", filename)
	if not _G[filename] then
		abort("xr_logic: can't call %s.set_scheme() - a nil value", filename)
	end
	_G[filename].set_scheme(npc, ini, scheme, section, gulag_name)

	--printf("DEBUG: activate_by_section: scheme '%s' activated from section '%s'", scheme, section)
	db.storage[npc_id].active_section = section
	db.storage[npc_id].active_scheme = scheme

	if db.storage[npc_id].stype == modules.stype_stalker then
		-- чтобы избежать дальнейшего движения по пути при установке рестрикторов
		utils.send_to_nearest_accessible_vertex(npc, npc:level_vertex_id())

		issue_event(npc, db.storage[npc_id][scheme], "activate_scheme", loading, npc)
	else
		issue_event(npc, db.storage[npc_id][scheme], "reset_scheme", loading, npc)
	end
end

--[[
-- Предназначение:
--	Производит сброс состояния объекта (снимает коллбеки, отключает разговор) непосредственно перед включением
--	новой схемы.
	]] --

function reset_generic_schemes_on_scheme_switch(npc, scheme, section)
	--printf("_bp: reset_generic_schemes_on_scheme_switch: npc:name()='%s'", npc:name())
	local st = db.storage[npc:id()]

	st.exit_from_smartcover_initialized = nil

	if not st.stype then
		return
	end

	if st.stype == modules.stype_stalker then
		--xr_reactions.reset_reactions(npc, scheme, st, section)
		xr_meet.dialog_manager_reset(npc, st.stype)
		xr_meet.reset_meet(npc, scheme, st, section)
		xr_abuse.reset_abuse(npc, scheme, st, section)
		xr_wounded.reset_wounded(npc, scheme, st, section)
		xr_death.reset_death(npc, scheme, st, section)
		xr_danger.reset_danger(npc, scheme, st, section)
		xr_combat_ignore.reset_combat_ignore_checker(npc, scheme, st, section)

		stalker_generic.reset_threshold(npc, scheme, st, section)
		stalker_generic.reset_show_spot(npc, scheme, st, section)
--		stalker_generic.set_level_spot(npc, scheme, st, section)
		stalker_generic.reset_invulnerability(npc, st.ini, section)
		stalker_generic.reset_group(npc, st.ini, section)
		stalker_generic.take_items_enabled(npc, scheme, st, section)
		restrictor_manager.get_restrictor_manager(npc):reset_restrictions(st, section)

	elseif st.stype == modules.stype_mobile then
		--printf("_bp: disabling talk")
		--npc:disable_talk() -- теперь делается в dialog_manager_reset
		xr_meet.dialog_manager_reset(npc, st.stype)
		mob_release(npc)
		if get_clsid(npc) == clsid.bloodsucker_s then
			if scheme == "nil" then
				npc:set_manual_invisibility(false)
			else
				npc:set_manual_invisibility(true)
				-- Видимый или нет определяет схема, которая возьмет его под контроль:
				--npc:set_invisible(false)
			end
		end

		xr_combat_ignore.reset_combat_ignore_checker(npc, scheme, st, section)

		mob_panic.reset_panic(npc, scheme, st, section)
		stalker_generic.reset_invulnerability(npc, st.ini, section)
		restrictor_manager.get_restrictor_manager(npc):reset_restrictions(st, section)
	elseif st.stype == modules.stype_trader then
		stalker_generic.reset_show_spot(npc, scheme, st, section)

	elseif st.stype == modules.stype_item then
		npc:set_callback(callback.use_object, nil)
		npc:set_nonscript_usable(true)
		if get_clsid(npc) == clsid.car then
			-- Другие объекты под скрипт не берутся, поэтому для них не надо сбрасывать
			npc:destroy_car()
			mob_release(npc)
		end
	end
end

function assign_storage_and_bind(npc, ini, scheme, section)
	local npc_id = npc:id()
	local st

	if not db.storage[npc_id][scheme] then
		db.storage[npc_id][scheme] = {}
		st = db.storage[npc_id][scheme]

		st["npc"] = npc

		-- Схема стартует впервые - прибиндить
		--printf("DEBUG: assign_storage_and_bind: bind scheme: '%s'", scheme)
		_G[schemes[scheme]].add_to_binder(npc, ini, scheme, section, st)
	else
		st = db.storage[npc_id][scheme]
	end

	st["scheme"] = scheme
	st["section"] = section
	st["ini"] = ini

	return st
end

function subscribe_action_for_events(npc, storage, new_action)
	--printf("DEBUG: registering new action for reset event (npc:name() = '%s')", npc:name())

	if not storage.actions then
		storage.actions = {}
	end

	storage.actions[new_action] = true
end

function unsubscribe_action_from_events(npc, storage, new_action)
	if not storage.actions then
		storage.actions = {}
	end

	storage.actions[new_action] = nil
end

-- st - storage активной схемы
function issue_event(npc, st, event_fn, ...)
	if not st or not st.actions then
		return
	end

	local activation_count = 0
	local action_ptr, is_active = 0, 0

	for action_ptr, is_active in pairs(st.actions) do
		if is_active and action_ptr[event_fn] then
			action_ptr[event_fn](action_ptr, ...)
			activation_count = activation_count + 1
		end
	end

--	if activation_count == 0 and
--		event_fn == "activate_scheme"
--	then
--		abort("xr_logic: issue_event: activate_scheme handler not found, active_scheme is '%s'", db.storage[npc:id()].active_scheme)
--	end
end

--' Функция проверяет выполняется ли у активной схемы заданная функция
function check_action(npc, st, event_fn, p)
	if not st or not st.actions then
		return true
	end

	for action_ptr, is_active in pairs(st.actions) do
		if is_active and action_ptr[event_fn] then
			return action_ptr[event_fn](action_ptr, p)
		end
	end
	return true
end


function pick_section_from_condlist(actor, npc, condlist)
	local rval = nil -- math.random(100)
	--printf("_bp: pick_section_from_condlist: rval = %d", rval)

	local newsect = nil
	local infop_conditions_met
	for n, cond in pairs(condlist) do
		infop_conditions_met = true -- изначально считаем, что все условия переключения удовлетворены
		for inum, infop in pairs(cond.infop_check) do
			if infop.prob then
				if not rval then
					rval = math.random(100)
				end
				if infop.prob < rval then
					infop_conditions_met = false -- инфопоршен есть, но он не должен присутствовать
					break
				end
			elseif infop.func then
				--printf("_bp: infop.func = %s", infop.func)
				if not xr_conditions[infop.func] then
					if type(npc.name) == "function" then
						abort("object '%s': pick_section_from_condlist: function '%s' is " ..
							"not defined in xr_conditions.script", npc:name(), infop.func)
					else
						abort("object '%s': pick_section_from_condlist: function '%s' is " ..
							"not defined in xr_conditions.script", tostring(npc.name), infop.func)
					end
				end
				--if xr_conditions[infop.func](actor, npc) then
				if infop.params then
					if xr_conditions[infop.func](actor, npc, infop.params) then
						if not infop.expected then
							infop_conditions_met = false -- инфопоршен есть, но не должен присутствовать
							break
						end
					else
						if infop.expected then
							infop_conditions_met = false -- инфопоршен есть, но не должен присутствовать
							break
						end
					end
				else
					if xr_conditions[infop.func](actor, npc) then
						if not infop.expected then
							infop_conditions_met = false -- инфопоршен есть, но не должен присутствовать
							break
						end
					else
						if infop.expected then
							infop_conditions_met = false -- инфопоршен есть, но не должен присутствовать
							break
						end
					end
				end
			elseif has_alife_info(infop.name) then
				if not infop.required then
					--'printf("FAILED: actor has infop '%s', which is NOT needed [%s]", infop.name, tostring(has_alife_info(infop.name)))
					infop_conditions_met = false -- инфопоршен есть, но он не должен присутствовать
					break
				else
					--'printf("PASSED: actor has infop '%s', which is needed [%s]", infop.name, tostring(has_alife_info(infop.name)))
				end
			else
				if infop.required then
					--'printf("FAILED: actor has NO infop '%s', which is needed [%s]", infop.name, tostring(has_alife_info(infop.name)))
					infop_conditions_met = false -- инфопоршена нет, но он нужен
					break
				else
					--'printf("PASSED: actor has NO infop '%s', which is not needed [%s]", infop.name, tostring(has_alife_info(infop.name)))
				end
			end
		end
		--printf("_bp: infop_cond_met = %s", utils.to_str(infop_conditions_met))
		if infop_conditions_met then
			-- Условия выполнены. Независимо от того, задана ли секция, нужно проставить требуемые
			-- infoportions:
			for inum, infop in pairs(cond.infop_set) do
				if db.actor == nil then
					abort("TRYING TO SET INFOS THEN ACTOR IS NIL")
				end
				if infop.func then
					if not xr_effects[infop.func] then
						abort("object '%s': pick_section_from_condlist: function '%s' is " ..
							"not defined in xr_effects.script", if_then_else(npc, npc:name(), "nil"), infop.func)
					end
					if infop.params then
						xr_effects[infop.func](actor, npc, infop.params)
					else
						xr_effects[infop.func](actor, npc)
					end
				elseif infop.required then
					if not has_alife_info(infop.name) then
						actor:give_info_portion(infop.name)
					end
				else
					if has_alife_info(infop.name) then
						--printf("*INFO [disabled]*: npc='%s' id='%s'", actor:name(),infop.name)
						actor:disable_info_portion(infop.name)
					end
				end
			end
			if cond.section == "never" then
				return nil
			else
				return cond.section
			end
		end
	end

	--printf("_bp: pick_section_from_condlist: nil")
	return nil
end

-- Выполняет переключение на указанную секцию, если задана.
-- Если section == nil, остается работать старая секция.
function switch_to_section(npc, ini, section)
	if section == "" or section == nil then
		return false
	end

	--printf("section = [%s]", tostring(section))
	local npc_id = npc:id()
	local active_section = db.storage[npc_id].active_section

	if active_section == section then
		--printf("section = [%s]3", tostring(section))
		return false
	end

	if active_section then
		issue_event(npc, db.storage[npc_id][db.storage[npc_id].active_scheme], "deactivate", npc)
	end
	db.storage[npc_id].exit_from_smartcover_initialized = nil
	db.storage[npc_id].active_section = nil
	db.storage[npc_id].active_scheme = nil
	if section == nil then
		return true
	end
	activate_by_section(npc, ini, section, db.storage[npc_id].gulag_name, false)
	--printf("section = [%s]5", tostring(section))
	return true
end

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

function cond_name(cond, etalon)
	return string.find( cond, "^"..etalon.."%d*$" ) ~= nil
end

function try_switch_to_another_section(npc, st, actor)
	local l = st.logic
	local npc_id = npc:id()

	if not actor then
		abort("try_switch_to_another_section(): error in implementation of scheme '%s': actor is nil", st.scheme)
		return
	end

	if not l then
		abort("Can't find script switching information in storage, scheme '%s'", st.active_scheme)
	end

	local switched = false
	for n, c in pairs(l) do
		--printf("_bp: %d: %s", time_global(), c.name)
		if cond_name(c.name, "on_actor_dist_le") then
			--printf("_bp: dist=%d (need <= %d), see_actor: %s", distance_between(actor, npc), c.v1, utils.to_str(see_actor(npc)))
			if see_actor(npc) and distance_between(actor, npc) <= c.v1 then
				--printf("_bp: conditions met")
				switched = switch_to_section(npc, st.ini, pick_section_from_condlist(actor, npc, c.condlist))
			end
		elseif cond_name(c.name, "on_actor_dist_le_nvis") then
			if distance_between(actor, npc) <= c.v1 then
				switched = switch_to_section(npc, st.ini, pick_section_from_condlist(actor, npc, c.condlist))
			end
		elseif cond_name(c.name, "on_actor_dist_ge") then
			--printf("_bp: dist=%d (need <= %d), see_actor: %s", distance_between(actor, npc), c.v1, utils.to_str(see_actor(npc)))
			-- ТУТ УМЫШЛЕННО >, А НЕ >=, потому что оно составляет пару с on_actor_dist_le, где <=
			if see_actor(npc) and distance_between(actor, npc) > c.v1 then
				--printf("_bp: conditions met")
				switched = switch_to_section(npc, st.ini, pick_section_from_condlist(actor, npc, c.condlist))
			end
		elseif cond_name(c.name, "on_actor_dist_ge_nvis") then
			-- ТУТ УМЫШЛЕННО >, А НЕ >=, потому что оно составляет пару с on_actor_dist_le_nvis, где <=
			if distance_between(actor, npc) > c.v1 then
				switched = switch_to_section(npc, st.ini, pick_section_from_condlist(actor, npc, c.condlist))
			end
		elseif cond_name(c.name, "on_signal") then
			--printf("_bp: on_signal (c.v1 = %s)", c.v1)
			if st.signals and st.signals[c.v1] then
			    --printf("_bp: on_signal (c.v1 = %s) signalled [%s]", c.v1, npc:name())
				--printf("_bp: signalled")
				switched = switch_to_section(npc, st.ini, pick_section_from_condlist(actor, npc, c.condlist))
			end
		-- FIXME: не дублировать тут имена, оставить один on_info, но добавлять несколько его экземпляров в список
		elseif cond_name(c.name, "on_info") then
			switched = switch_to_section(npc, st.ini, pick_section_from_condlist(actor, npc, c.condlist))
		elseif cond_name(c.name, "on_timer") then
			--printf("_bp: on_timer: %d >= %d", time_global(),
			--	db.storage[npc_id].activation_time + c.v1)
			if time_global() >= db.storage[npc_id].activation_time + c.v1 then
				switched = switch_to_section(npc, st.ini, pick_section_from_condlist(actor, npc, c.condlist))
			end

		-- GAMETIME added by Stohe.
		elseif cond_name(c.name, "on_game_timer") then
			if  game.get_game_time():diffSec(db.storage[npc_id].activation_game_time) >= c.v1 then
				switched = switch_to_section(npc, st.ini, pick_section_from_condlist(actor, npc, c.condlist))
			end

		elseif cond_name(c.name, "on_actor_in_zone") then
			if utils.npc_in_zone(actor, db.zone_by_name[c.v1]) then
				switched = switch_to_section(npc, st.ini, pick_section_from_condlist(actor, npc, c.condlist))
			end
		elseif cond_name(c.name, "on_actor_not_in_zone") then
			if not utils.npc_in_zone(actor, db.zone_by_name[c.v1]) then
				switched = switch_to_section(npc, st.ini, pick_section_from_condlist(actor, npc, c.condlist))
			end
		elseif cond_name(c.name, "on_npc_in_zone") then
			if utils.npc_in_zone(level.object_by_id(c.npc_id), db.zone_by_name[c.v2]) then
				switched = switch_to_section(npc, st.ini, pick_section_from_condlist(actor, npc, c.condlist))
			end
		elseif cond_name(c.name, "on_npc_not_in_zone") then
			if not utils.npc_in_zone(level.object_by_id(c.npc_id), db.zone_by_name[c.v2]) then
				switched = switch_to_section(npc, st.ini, pick_section_from_condlist(actor, npc, c.condlist))
			end
		elseif cond_name(c.name, "on_actor_inside") then
			if utils.npc_in_zone(actor, npc) then
--				printf("_bp: TRUE")
				switched = switch_to_section(npc, st.ini, pick_section_from_condlist(actor, npc, c.condlist))
			end
		elseif cond_name(c.name, "on_actor_outside") then
			if not utils.npc_in_zone(actor, npc) then
				switched = switch_to_section(npc, st.ini, pick_section_from_condlist(actor, npc, c.condlist))
			end
		else
			abort(
				"WARNING: object '%s': try_switch_to_another_section: unknown condition '%s' encountered",
				npc:name(), c.name)
		end
		if switched == true then
			break
		end
	end

	return switched
end

function is_active(npc, st)
	if st.section == nil then
		abort("npc '%s': st.section is nil, active section is '%s'",
			npc:name(), utils.to_str(db.storage[npc:id()].active_section))
	end
	local is_act = (st.section == db.storage[npc:id()].active_section)

	-- Текущая секция активна и не сработало ни одно из условий переключения на другие секции
	return is_act
end


function abort_syntax_error_in_cond(npc, section, field)
	abort("object '%s': section '%s': field '%s': syntax error in switch condition",
		npc:name(), section, field)
end

-- На входе имеем пустой массив и строку вида "  +infop1  -infop2 +infop3 ... "
-- Заполнить массив:
-- { "infop_name" = true/false }.
function parse_infop1(rslt, str)
	--printf("_bp: parse_infop: %s", utils.to_str(str))
	if str then
		local infop_name, sign
		local infop_n = 1
		for s in string.gfind(str, "%s*([%-%+%~%=%!][^%-%+%~%=%!%s]+)%s*") do
			--printf("_bp: parse_infop: s=%s", utils.to_str(s))
			sign = string.sub(s, 1, 1)
			infop_name = string.sub(s, 2)
			if sign == "+" then
				rslt[infop_n] = { name = infop_name, required = true }
			elseif sign == "-" then
				rslt[infop_n] = { name = infop_name, required = false }
			elseif sign == "~" then
				rslt[infop_n] = { prob = tonumber(infop_name) }
			elseif sign == "=" then
				rslt[infop_n] = { func = infop_name, expected = true }
			elseif sign == "!" then
				rslt[infop_n] = { func = infop_name, expected = false }
			else
				abort_syntax_error_in_cond(npc, section, field)
			end
			infop_n = infop_n + 1
		end
	end
end

function parse_func_params(str)
	local lst = {}
	local n
	for par in string.gfind(str, "%s*([^:]+)%s*") do
		n = tonumber(par)
		if n then table.insert(lst, n)
		else table.insert(lst, par) end
	end
	return lst
end

function parse_infop(rslt, str)
	--printf("_bp: parse_infop1: %s", utils.to_str(str))
	if str then
		local infop_name, sign
		local infop_n = 1
		local at, params
		for s in string.gfind(str, "%s*([%-%+%~%=%!][^%-%+%~%=%!%s]+)%s*") do
			--printf("_bp: parse_infop: s=%s", utils.to_str(s))
			sign = string.sub(s, 1, 1)
			infop_name = string.sub(s, 2)
			params = nil

			-- парсим параметры функций
			at = string.find(infop_name, "%(")
			if at then
				if string.sub(infop_name, -1) ~= ")" then
					abort("wrong condlist %s", str)
				end
				if at < string.len(infop_name) - 1 then
					params = parse_func_params(string.sub(infop_name, at + 1, -2))
				else
					params = {}
				end
				infop_name = string.sub(infop_name, 1, at - 1)
			end

			if sign == "+" then
				rslt[infop_n] = { name = infop_name, required = true }
			elseif sign == "-" then
				rslt[infop_n] = { name = infop_name, required = false }
			elseif sign == "~" then
				rslt[infop_n] = { prob = tonumber(infop_name) }
			elseif sign == "=" then
				--printf("_bp: n = %s; r = %s", infop_name, utils.to_str(params))
				rslt[infop_n] = { func = infop_name, expected = true, params = params }
			elseif sign == "!" then
				--printf("_bp: n = %s; r = %s", infop_name, utils.to_str(params))
				rslt[infop_n] = { func = infop_name, expected = false, params = params }
			else
				abort_syntax_error_in_cond(npc, section, field)
			end
			infop_n = infop_n + 1
		end
	end
end

-- Распарсивает строку src вида:
-- {+infop1} section1 %-infop2%, {+infop3 -infop4} section2 ...
-- в таблицу:
-- {
--   1 = { infop_check = { 1 = {"infop1" = true} }, infop_set = { 1 = {"infop2" = false } }, section = "section1" },
--   2 = { infop_check = { 1 = {"infop3" = true}, 2 = {"infop4" = false} }, infop_set = {}, section = "section2" },
-- }
function parse_condlist(npc, section, field, src)
	local lst = {}

	-- 1) Разбиваем на разделенные запятыми части:
	local at, to, infop_check_lst, remainings, infop_set_lst, newsect

	--printf("_bp: src = %s", src)

	local n = 1
	for fld in string.gfind(src, "%s*([^,]+)%s*") do
		-- Здесь fld это набор infoportions в {} и имя секции, на которую переключиться.
		lst[n] = {}
		--printf("_bp: iter %d: fld = %s", n, fld)

		-- Выделяем список infoportions для проверки:
		at, to, infop_check_lst = string.find(fld, "{%s*(.*)%s*}")
		if infop_check_lst then
			--printf("_bp: infop_check_lst: [%s]", infop_check_lst)

			-- Выделяем оставшуюся часть поля, т.е. имя секции плюс список infoportions для установки:
			remainings = string.sub(fld, 1, at - 1) .. string.sub(fld, to + 1)
		else
			-- Список infoportions для проверки не был задан, следовательно, ничего не удаляем:
			remainings = fld
		end
		--printf("_bp: remainings: %s", remainings)

		-- Выделяем список infoportions для установки из remainings:
		at, to, infop_set_lst = string.find(remainings, "%%%s*(.*)%s*%%")
		if infop_set_lst then
			-- Выделяем оставшуюся часть поля, т.е. имя секции:
			newsect = string.sub(remainings, 1, at - 1) .. string.sub(remainings, to + 1)
		else
			-- Список infoportions для установки не был задан, следовательно, remainings и есть имя секции.
			newsect = remainings
		end
		--printf("_bp: newsect: %s", newsect)

		-- И сразу trim имя секции:
		at, to, newsect = string.find(newsect, "%s*(.*)%s*")
		if not newsect then
			abort_syntax_error_in_cond(npc, section, field)
		end

		-- Имя секции теперь можно сохранить:
		lst[n].section = newsect

		-- Теперь нужно распарсить infoportions в строке infop_check_lst и
		-- заполнить массив infop_check: { "infop_name" = true/false }.
		-- На входе имеем строку вида "  +infop1  -infop2 +infop3 ... "
		lst[n].infop_check = {}
		parse_infop(lst[n].infop_check, infop_check_lst)

		-- То же самое для устанавливаемых infoportions:
		lst[n].infop_set = {}
		parse_infop(lst[n].infop_set, infop_set_lst)

		n = n + 1
	end

	return lst
end

function cfg_get_number_and_condlist(ini, section, field, npc)
	local str = utils.cfg_get_string(ini, section, field, npc, false, "")
	if not str then
		return nil
	end

	local par = utils.parse_params(str)
	if not par[1] or not par[2] then
		abort_syntax_error_in_cond(npc, section, field)
	end

	local t = {}

	t.name = field
	t.v1 = tonumber(par[1])
	t.condlist = parse_condlist(npc, section, field, par[2])

	return t
end

function cfg_get_string_and_condlist(ini, section, field, npc)
	local str = utils.cfg_get_string(ini, section, field, npc, false, "")
	if not str then
		return nil
	end

	local par = utils.parse_params(str)
	if not par[1] or not par[2] then
		abort_syntax_error_in_cond(npc, section, field)
	end

	local t = {}

	t.name = field
	t.v1 = par[1]
	t.condlist = parse_condlist(npc, section, field, par[2])

	return t
end

function cfg_get_two_strings_and_condlist(ini, section, field, npc)
	local str = utils.cfg_get_string(ini, section, field, npc, false, "")
	if not str then
		return nil
	end

	local par = utils.parse_params(str)
	if not par[1] or not par[2] or not par[3] then
		abort_syntax_error_in_cond(npc, section, field)
	end

	local t = {}

	t.name = field
	t.v1 = par[1]
	t.v2 = par[2]
	t.condlist = parse_condlist(npc, section, field, par[3])

	return t
end

function cfg_get_condlist(ini, section, field, npc)
	local str = utils.cfg_get_string(ini, section, field, npc, false, "")
	if not str then
		return nil
	end

	local par = utils.parse_params(str)
	if not par[1] then
		abort_syntax_error_in_cond(npc, section, field)
	end

	local t = {}

	t.name = field
	t.condlist = parse_condlist(npc, section, field, par[1])

	return t
end

function add_condition(lst, at, cond)
	if cond then
		lst[at] = cond
		return at + 1
	end
	return at
end


function cfg_get_switch_conditions(ini, section, npc)
	local l = {}
	local t
	local n = 1

	local function add_conditions(func, cond)
		local i = 1
		local c = func(ini, section, cond, npc)

		while c ~= nil do
			n = add_condition(l, n, c, npc)

			i = i + 1

			c = func(ini, section, cond..i, npc)
		end
	end

	add_conditions( cfg_get_number_and_condlist, "on_actor_dist_le"      )
	add_conditions( cfg_get_number_and_condlist, "on_actor_dist_le_nvis" )
	add_conditions( cfg_get_number_and_condlist, "on_actor_dist_ge"      )
	add_conditions( cfg_get_number_and_condlist, "on_actor_dist_ge_nvis" )
	add_conditions( cfg_get_string_and_condlist, "on_signal"             )
	add_conditions( cfg_get_condlist           , "on_info"               )
	add_conditions( cfg_get_number_and_condlist, "on_timer"              )
	add_conditions( cfg_get_number_and_condlist, "on_game_timer"         )
	add_conditions( cfg_get_string_and_condlist, "on_actor_in_zone"      )
	add_conditions( cfg_get_string_and_condlist, "on_actor_not_in_zone"  )
	add_conditions( cfg_get_condlist           , "on_actor_inside"       )
	add_conditions( cfg_get_condlist           , "on_actor_outside"      )
	add_conditions( cfg_get_npc_and_zone       , "on_npc_in_zone"        )
	add_conditions( cfg_get_npc_and_zone       , "on_npc_not_in_zone"    )

	return l
end

function cfg_get_overrides(ini, section, npc)
	local l = {}

--	l.meet_enabled      = utils.cfg_get_bool(ini, section, "meet_enabled", npc, false)
--	l.meet_talk_enabled = utils.cfg_get_bool(ini, section, "meet_talk_enabled", npc, false)
--	l.meet_dialog       = utils.cfg_get_string(ini, section, "meet_dialog", npc, false, "")
--	l.meet_state        = utils.cfg_get_string(ini, section, "meet_state", npc, false, "")
--	l.reactions         = parse_names(utils.cfg_get_string(ini, section, "reactions", npc, false, "", ""))

	local tmp			= utils.cfg_get_string(ini, section, "heli_hunter", npc, false, "")
	if tmp then
		l.heli_hunter	= xr_logic.parse_condlist(npc, section, "heli_hunter", tmp)
	end

--	l.wounded_enabled   = utils.cfg_get_bool(ini, section, "wounded_enabled", npc, false)
	l.combat_ignore     = cfg_get_condlist(ini, section, "combat_ignore_cond", npc)
	l.combat_ignore_keep_when_attacked = utils.cfg_get_bool(ini, section, "combat_ignore_keep_when_attacked", npc, false)
	l.combat_type       = cfg_get_condlist(ini, section, "combat_type", npc)
	l.on_combat         = cfg_get_condlist(ini, section, "on_combat", npc)
--	l.companion_enabled = utils.cfg_get_bool(ini, section, "companion_enabled", npc, false)
	local st = db.storage[npc:id()]
	if ini:line_exist(st.section_logic, "post_combat_time") then
		l.min_post_combat_time,l.max_post_combat_time = utils.r_2nums( ini, st.section_logic, "post_combat_time", 10, 15 )
	else
		l.min_post_combat_time,l.max_post_combat_time = utils.r_2nums( ini, section, "post_combat_time", 10, 15 )
	end

	if string.find(section, "kamp") ~= nil then
		l.soundgroup		= utils.cfg_get_string(ini, section, "center_point", npc, false, "")
	else
		l.soundgroup		= utils.cfg_get_string(ini, section, "soundgroup", npc, false, "")
	end


	return l
end

function cfg_get_npc_and_zone(ini, section, field, npc)
	local t = cfg_get_two_strings_and_condlist(ini, section, field, npc)

	if t then
		local sim = alife()
		if sim then
			local se_obj = sim:story_object(tonumber(t.v1))
			if se_obj then
				t.npc_id = se_obj.id
			else
				t.npc_id = -1
				abort("object '%s': section '%s': field '%s': there is no object with story_id '%s'",
				            npc:name(), section, field, t.v1)
			end
		else
			t.npc_id = -1
			--printf("WARNING: object '%s': section '%s': field '%s': can't use story_id without simulation!", npc:name(), section, field)
		end
	end

	return t
end

-- Возвращает ссылку на оверрайды, зарегистрированные в активной на данный момент секции,
-- либо nil, если ни одна из секций не активна, или оверрайдов нет.
function generic_scheme_overrides(npc)
	return db.storage[npc:id()].overrides
end

function mob_release(mob)
	if mob:get_script() then
		mob:script(false, script_name())
	end
end

function mob_capture(mob, reset_actions)
	if reset_actions == nil then
		abort("mob_capture: reset_actions parameter's value is not specified")
	end

	if reset_actions then
		reset_action(mob, script_name())
	else
		if not mob:get_script() then
			mob:script(true, script_name())
		end
	end
end

function mob_captured(mob)
	return mob:get_script()
end

function save_logic(obj, packet)
	local npc_id = obj:id()
	local cur_tm = time_global()

	local activation_time = db.storage[npc_id].activation_time
	if not activation_time then
		activation_time = 0
	end
 	packet:w_s32(activation_time - cur_tm)

	-- GAMETIME added by Stohe.
	utils.w_CTime(packet, db.storage[npc_id].activation_game_time)
end

function load_logic(obj, reader)
	local npc_id = obj:id()
	local cur_tm = time_global()

	db.storage[npc_id].activation_time = reader:r_s32() + cur_tm

	-- GAMETIME added by Stohe.
	db.storage[npc_id].activation_game_time = utils.r_CTime(reader)
end

local pstor_number = 0
local pstor_string = 1
local pstor_boolean = 2

function pstor_is_registered_type(tv)
	if tv ~= "boolean" and tv ~= "string" and tv ~= "number" then
		return false
	end
	return true
end

function pstor_store(obj, varname, val)
	local npc_id = obj:id()

	if db.storage[npc_id].pstor == nil then
		db.storage[npc_id].pstor = {}
	end
	local tv = type(val)
	if not pstor_is_registered_type(tv) then
		abort("xr_logic: pstor_store: not registered type '%s' encountered", tv)
	end
	db.storage[npc_id].pstor[varname] = val
end

function pstor_retrieve(obj, varname, defval)
	local npc_id = obj:id()

	if db.storage[npc_id].pstor ~= nil then
		local val = db.storage[npc_id].pstor[varname]
		if val ~= nil then
			return val
		end
	end
	if defval ~= nil then
		return defval
	end
	--abort("xr_logic: pstor_retrieve: variable '%s' does not exist", varname)
	return nil
end

function pstor_save_all(obj, packet)
	local npc_id = obj:id()
	local pstor = db.storage[npc_id].pstor
	if not pstor then
		pstor = {}
		db.storage[npc_id].pstor = pstor
	end

	local ctr = 0
	for k, v in pairs(pstor) do
		ctr = ctr + 1
	end
	packet:w_u32(ctr)

	for k, v in pairs(pstor) do
		--printf("_bp: pstor_save_all: saving [%s]='%s'", utils.to_str(k), utils.to_str(v))
 		packet:w_stringZ(k)
		local tv = type(v)
		if tv == "number" then
			packet:w_u8(pstor_number)
	 		packet:w_float(v)
	 	elseif tv == "string" then
			packet:w_u8(pstor_string)
	 		packet:w_stringZ(v)
	 	elseif tv == "boolean" then
			packet:w_u8(pstor_boolean)
	 		packet:w_bool(v)
		else
			abort("xr_logic: pstor_save_all: not registered type '%s' encountered", tv)
		end
	end
end

function pstor_load_all(obj, reader)
	local npc_id = obj:id()
	local pstor = db.storage[npc_id].pstor
	if not pstor then
		pstor = {}
		db.storage[npc_id].pstor = pstor
	end
	local ctr = reader:r_u32()

	for i = 1, ctr do
		local varname = reader:r_stringZ()
		local tn = reader:r_u8()
		if tn == pstor_number then
			pstor[varname] = reader:r_float()
		elseif tn == pstor_string then
			pstor[varname] = reader:r_stringZ()
		elseif tn == pstor_boolean then
			pstor[varname] = reader:r_bool()
		else
			abort("xr_logic: pstor_load_all: not registered type N %d encountered", tn)
		end
		--printf("_bp: pstor_load_all: loaded [%s]='%s'", varname, utils.to_str(pstor[varname]))
	end
end

function save_obj(obj, packet)
	--printf("save_obj: obj:name()='%s'", obj:name())
	set_save_marker(packet, "save", false, "object"..obj:name())
	local npc_id = obj:id()
	local st = db.storage[npc_id]

	--printf("save_obj: ini_filename='%s'", utils.to_str(st.ini_filename))
	--printf("save_obj: section_logic='%s'", utils.to_str(st.section_logic))
	--printf("save_obj: active_section='%s'", utils.to_str(st.active_section))
	--printf("save_obj: gulag_name='%s'", utils.to_str(st.gulag_name))
	if st.job_ini then
		packet:w_stringZ(st.job_ini)
	else
		packet:w_stringZ("")
	end
	if st.ini_filename then
		packet:w_stringZ(st.ini_filename)
	else
		packet:w_stringZ("")
	end

	if st.section_logic then
		packet:w_stringZ(st.section_logic)
	else
		packet:w_stringZ("")
	end

	if st.active_section then
		packet:w_stringZ(st.active_section)
	else
		packet:w_stringZ("")
	end

	--if st.active_scheme then
	--	packet:w_stringZ(st.active_scheme)
	--else
	--	packet:w_stringZ("")
	--end

	if st.gulag_name then
		packet:w_stringZ(st.gulag_name)
	else
		packet:w_stringZ("")
	end

	--packet:w_s32(st.stype)

	save_logic(obj, packet)

	if st.active_scheme then
		issue_event(obj, db.storage[npc_id][st.active_scheme], "save")
	end

	pstor_save_all(obj, packet)
	set_save_marker(packet, "save", true, "object"..obj:name())
end

function load_obj(obj, reader)
	--printf("load_obj: obj:name()='%s'", obj:name())
	set_save_marker(reader, "load", false, "object"..obj:name())
	local npc_id = obj:id()
	local st = db.storage[npc_id]
	local job_ini = reader:r_stringZ()
	if job_ini == "" then
		job_ini = nil
	end
	local ini_filename = reader:r_stringZ()
	if ini_filename == "" then
		ini_filename = nil
	end

	local section_logic = reader:r_stringZ()
	if section_logic == "" then
		section_logic = nil
	end

	local active_section = reader:r_stringZ()
	if active_section == "" then
		-- В activate_by_section нужно передать строку "nil", а не nil, чтобы не активировать ни одной из схем.
		-- При этом реальная active_section станет равной nil.
		active_section = "nil"
	end

	--local active_scheme = reader:r_stringZ()
	--if active_scheme == "" then
	--	active_scheme = nil
	--end

	local gulag_name = reader:r_stringZ()

	--local stype = reader:r_s32()
	st.job_ini = job_ini
	st.loaded_ini_filename = ini_filename
	st.loaded_section_logic = section_logic
	st.loaded_active_section = active_section
	--st.loaded_active_scheme = active_scheme
	st.loaded_gulag_name = gulag_name
	--st.loaded_stype = stype

	--printf("load_obj: ini_filename='%s'", utils.to_str(st.loaded_ini_filename))
	--printf("load_obj: section_logic='%s'", utils.to_str(st.loaded_section_logic))
	--printf("load_obj: active_section='%s'", utils.to_str(st.loaded_active_section))
	--printf("load_obj: active_scheme='%s'", utils.to_str(st.loaded_active_scheme))
	--printf("load_obj: gulag_name='%s'", utils.to_str(st.loaded_gulag_name))
	--printf("load_obj: job_ini='%s'", utils.to_str(st.job_ini))

	load_logic(obj, reader)

	pstor_load_all(obj, reader)
	set_save_marker(reader, "load", true, "object"..obj:name())
end

function get_customdata_or_ini_file(npc, filename)
	--printf( "get_customdata_or_ini_file: filename=%s", filename )
	local st = db.storage[npc:id()]
	if filename == "<customdata>" then
		--printf("custom_data_or_ini:1!!!")
		local ini = npc:spawn_ini()
		if ini then
			--printf("custom_data_or_ini:2!!!")
			return ini
		else
			--printf("custom_data_or_ini:3!!!")
			return ini_file([[scripts\dummy.ltx]])
		end
	elseif string.find( filename, "*" ) == 1 then
		-- динамический ltx
		if st.job_ini ~= nil then
			--printf("custom_data_or_ini:job_ini!!!")
			return ini_file(st.job_ini)
		end
		--printf("custom_data_or_ini:4!!!")
		return xr_gulag.loadLtx(string.sub(filename, 2))
	else
		--printf("custom_data_or_ini:5!!!")
		return ini_file(filename)
	end
	--printf("custom_data_or_ini:6!!!")
end

function initialize_obj(obj, st, loaded, actor, stype)
	if not loaded then
		local ini_filename = "<customdata>"
		local ini = get_customdata_or_ini_file(obj, ini_filename)
		ini = xr_logic.configure_schemes(obj, ini, ini_filename, stype, "logic", "")
		local sect = xr_logic.determine_section_to_activate(obj, ini, "logic", actor)
		xr_logic.activate_by_section(obj, ini, sect,  st.gulag_name, false)
	    local relation = utils.cfg_get_string(ini, "logic", "relation", obj, false, "")
	    if(relation~=nil) then
	        obj:set_relation(game_object[relation], db.actor)
	    end
	    local sympathy = utils.cfg_get_number(ini, "logic", "sympathy", obj, false)
	    if(sympathy~=nil) then
	        obj:set_sympathy(sympathy)
	    end
	else
		local ini_filename = st.loaded_ini_filename
		if ini_filename then
			local ini = get_customdata_or_ini_file(obj, ini_filename)
			ini = xr_logic.configure_schemes(obj, ini, ini_filename, stype, st.loaded_section_logic, st.loaded_gulag_name)
			--printf( "initialize_obj: loaded, gulag_name %s", tostring(st.loaded_gulag_name))
			xr_logic.activate_by_section(obj, ini, st.loaded_active_section, st.loaded_gulag_name, true)
		end

--		if st.active_scheme then
--			issue_event(obj, db.storage[obj:id()][st.active_scheme], "load")
--		end
	end
end
