e4s-sdk/gamedata/scripts/xr_logic.script
2026-06-17 23:06:51 +03:00

1511 lines
52 KiB
Text
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

----------------------------------------------------------------------------------------------------
-- 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)
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
-- Инициализация торговли
if stype == modules.stype_stalker
then
local trade_ini = utils.cfg_get_string(actual_ini, section_logic, "trade", npc, false, "", "misc\\trade\\trade_generic.ltx")
trade_manager.trade_init(npc, trade_ini)
spawner.spawn_items(npc, st)
end
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
if db.offline_objects[npc:id()] and db.offline_objects[npc:id()].active_section ~= nil then
local sect_to_retr = db.offline_objects[npc:id()].active_section
db.offline_objects[npc:id()].active_section = nil
if ini:section_exist(sect_to_retr) then
return sect_to_retr
end
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_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_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")
xr_gather_items.set_gather_items(npc, ini, "gather_items", "gather_items")
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 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)
xr_help_wounded.set_help_wounded (npc, ini, "help_wounded")
xr_corpse_detection.set_corpse_detection (npc, ini, "corpse_detection")
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")
xr_reach_task.set_reach_task(npc, ini, "reach_task")
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, "")
if death_section then
mob_death.set_scheme(npc, ini, "mob_death", death_section)
end
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_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.reset_meet(npc, scheme, st, section)
xr_help_wounded.reset_help_wounded(npc, scheme, st, section)
xr_corpse_detection.reset_corpse_detection(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_gather_items.reset_gather_items(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)
stalker_generic.can_select_weapon(npc, scheme, st, section)
restrictor_manager.get_restrictor_manager(npc):reset_restrictions(st, section)
xr_hear.reset_hear_callback(st, section)
elseif st.stype == modules.stype_mobile then
--printf("_bp: disabling talk")
--npc:disable_talk() -- теперь делается в dialog_manager_reset
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)
stalker_generic.reset_invulnerability(npc, st.ini, section)
restrictor_manager.get_restrictor_manager(npc):reset_restrictions(st, section)
xr_hear.reset_hear_callback(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)
disable_info(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
--printf("[%s] switch to section [%s] %s", npc:name(), tostring(section), device():time_global())
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'", db.storage[npc:id()].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
if not ini:section_exist(tostring(section)) then
return
end
local line_count = ini:line_count(section)
local function add_conditions(func, cond)
for line_number = 0, line_count - 1 do
local result, id, value = ini:r_line(section,line_number,"","")
if string.find( id, "^"..cond.."%d*$" ) ~= nil then
c = func(ini, section, id, npc)
n = add_condition(l, n, c)
end
end
--[[ 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 ini:line_exist(section, "on_offline") then
l.on_offline_condlist = xr_logic.parse_condlist(npc, section, "on_offline", utils.cfg_get_string(ini, section, "on_offline", npc, false, "", "nil"))
else
l.on_offline_condlist = xr_logic.parse_condlist(npc, st.section_logic, "on_offline", utils.cfg_get_string(ini, st.section_logic, "on_offline", npc, false, "", "nil"))
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:object(get_story_object_id(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 val ~= nil and 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