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

--[[

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

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 not gulag_name then
      -- Общие схемы должны работать и без logic:
      actual_ini_filename = ini_filename
      actual_ini = ini -- персонаж не обязательно должен иметь секцию logic
    else
      -- Иначе это персонаж Gulag-а и ему не задали работу:
      abort("ERROR: object '%s': unable to find section '%s'", npc:name(), section_logic)
    end
  else
    local filename = utils.cfg_get_string(ini, section_logic, "cfg", npc, false, "")
    if filename then
      printf("_bp: enable_scripts: object '%s' has external configuration file '%s'", npc:name(), filename)
      -- Рекурсивно обработать конфигурационный файл, на который ссылается поле cfg
      actual_ini_filename = filename
      actual_ini = ini_file(filename)
      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
      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
  if gulag_name then
    st.gulag_name = gulag_name
  else
    st.gulag_name = ""
  end
  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
    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")
  elseif stype == modules.stype_mobile then
    mob_combat.disable_scheme(npc, "mob_combat")
    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)

    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)

    if anomaly_evader then
      anomaly_evader.set_evade(npc,ini,"evader",section)
    end

    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)

    local combat_ignore_section = utils.cfg_get_string(ini, section, "combat_ignore", npc, false, "")
    if combat_ignore_section then
      printf("combat_ignore_section= '%s'", combat_ignore_section )
      xr_combat_ignore.set_combat_ignore_checker(npc, ini, "combat_ignore", combat_ignore_section)
    end


  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)

    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

    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

    mob_panic.set_scheme(npc, ini, "mob_panic")

  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

function activate_by_section(npc, ini, section, loading)
  printf("DEBUG: object '%s': activate_by_section: looking for section '%s'", 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 db.storage[npc_id].active_section then
    abort("xr_logic: activate_by_section: while processing section '%s': character '%s': trying to " ..
      "activate more than one schemes at once (section '%s' is active)",
      section, npc:name(), db.storage[npc_id].active_section)
  end

  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 ini:section_exist(section) then
    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, db.storage[npc_id]["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 not loading then
--'     db.storage[npc_id].pstor = nil
--'   end

    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
  else
    abort("object '%s': activate_by_section: section '%s' does not exist",
      npc:name(), section)
  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()]

  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)
    stalker_generic.reset_threshold(npc, scheme, st, section)
    stalker_generic.reset_show_spot(npc, scheme, 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

    mob_panic.reset_panic(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)
    --mylog(tostring(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 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
          abort("object '%s': pick_section_from_condlist: function '%s' is " ..
            "not defined in xr_conditions.script", npc:name(), infop.func)
        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
            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, st, section)
  if section == nil or section == "" then
    return false
  end
  local active_section = db.storage[npc:id()].active_section
  if active_section == section then
    return false
  end

  -- call scheme::finalize()
  if active_section then
    issue_event(npc, db.storage[npc:id()][db.storage[npc:id()].active_scheme], "deactivate", npc)
  end

  db.storage[npc:id()].active_section = nil
  db.storage[npc:id()].active_scheme = nil
  activate_by_section(npc, st.ini, section, false)
  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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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 then
      --printf("_SWITCHED")
      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)

  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
  return nil
--' abort("xr_logic: pstor_retrieve: variable '%s' does not exist", varname)
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())

  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.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)
end

function load_obj(obj, reader)
  printf("load_obj: obj:name()='%s'", obj:name())
  local npc_id = obj:id()
  local st = db.storage[npc_id]

  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()
  if gulag_name == "" then
    gulag_name = nil
  end

  --local stype = reader:r_s32()

  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))

  load_logic(obj, reader)

  pstor_load_all(obj, reader)
end

function get_customdata_or_ini_file(npc, filename)
--  printf( "get_customdata_or_ini_file: filename=%s", filename )

  if filename == "<customdata>" then
    local ini = npc:spawn_ini()
    if ini then
      return ini
    else
      return ini_file([[scripts\dummy.ltx]])
    end
  elseif string.find( filename, "*" ) == 1 then
    -- динамический ltx
    local p = string.find( filename, "*", 2 )
    return gulag_tasks.loadLtx( string.sub(filename, 2, p-1), string.sub(filename, p+1) )
  else
    return ini_file(filename)
  end
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", nil)
    local sect = xr_logic.determine_section_to_activate(obj, ini, "logic", actor)
    xr_logic.activate_by_section(obj, ini, sect, false)
  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" )
      xr_logic.activate_by_section(obj, ini, st.loaded_active_section, true)
    end

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