Перейти к контенту

Rolan

Рекомендуемые сообщения

Люди помогите пожалуйста!
Мне нужно сделать чтобы сталкеры шли от смарта к смарту,читал сообщения выше все так.

У меня только другое.

У меня прописано в 2-х сквадах 3 смарта.Прописал к какому идти,условие поставил.Вообщем они идут к смарту и идут все туда,хотя должны были 1 сквад к 1 смарту идти,а другой сквад к другому и + они до смарта дошли,все  по плану но обратно на базу или на другой смарт не идут:((

Что делать,что может быть не так?

[esc_stalker_base_default3_squad]:online_offline_group
faction = stalker
npc = sim_default_stalker_1, sim_default_stalker_0, sim_default_stalker_0, sim_default_stalker_0
target_smart = {+esc_lost_stoyanka} esc_lost_stoyanka, {+esc_lost_stoyanka2} esc_lost_stoyanka2, {+esc_stalker_base} esc_stalker_base, esc_lost_stoyanka
;spawn_point = esc_stalker_base_mini_bar_spawn_point
story_id = esc_stalker_base_default3_squad
 
[esc_stalker_base_default4_squad]:online_offline_group
faction = stalker
npc = sim_default_stalker_1, sim_default_stalker_1, sim_default_stalker_0, sim_default_stalker_0
target_smart = {+esc_lost_stoyanka} esc_lost_stoyanka, {+esc_lost_stoyanka2} esc_lost_stoyanka2, {+esc_stalker_base} esc_stalker_base, esc_lost_stoyanka
;spawn_point = esc_stalker_base_mini_bar_spawn_point
story_id = esc_stalker_base_default4_squad

 

 

[esc_stalker_base]
    255,255,255,144
[esc_lost_stoyanka]
    255,255,255,145
[esc_lost_stoyanka2]
    255,255,255,146

 

 

Поделиться этим сообщением


Ссылка на сообщение

А что нужно сделать,чтобы как в ЗП на затоне например ходили,к разным смартам и перемещались по ним а не оставались там?

Поделиться этим сообщением


Ссылка на сообщение
(изменено)

Что нужно прописать в таргет смарте,чтобы 1-ый сквад шел к 1-му смарту,а 2-й на 2-й смарт.И если например 1-ый смарт занят то он либо идет на свободный либо остается на своем смарте?

В оригинале смотрел,там условие стоит но хз что именно прописать надо.

Изменено пользователем ColR_iT

Поделиться этим сообщением


Ссылка на сообщение
(изменено)

Люди помогите пожалуйста.Сквады создавать умею.Единственная проблема,так это симмуляционные сквады.Создал автосейв.Он как сказал Андрей Непряхин нужен для норм. симмуляции на локации.Далее прописал логику автосейву,прописал его в текст\рус\файлик.В рестикторе сделал нот а рестиктор,имя норм,путь к логике рабочий.Прописываю автосейв скваду - вылет :(

В чем может быть проблема?



[esc_stalker_base_default3_squad]:online_offline_group


faction = stalker
npc = sim_default_stalker_1, sim_default_stalker_0, sim_default_stalker_0, sim_default_stalker_0
target_smart = (+st_save_start_escape) esc_lost_stoyanka, esc_lost_stoyanka2, esc_stalker_base
;spawn_point = esc_stalker_base_mini_bar_spawn_point
story_id = esc_stalker_base_default3_squad

[esc_stalker_base_default4_squad]:online_offline_group
faction = stalker
npc = sim_default_stalker_1, sim_default_stalker_1, sim_default_stalker_0, sim_default_stalker_0
target_smart = (+st_save_start_escape) esc_lost_stoyanka, esc_lost_stoyanka2, esc_stalker_base
;spawn_point = esc_stalker_base_mini_bar_spawn_point
story_id = esc_stalker_base_default4_squad

 

[logic]
active = sr_idle@game_start

[sr_idle@game_start]
on_info = {=actor_on_level(escape)} sr_idle@game_start_2 %=damage_actor_items_on_start%

[sr_idle@game_start_2]
on_info = sr_idle@nil %+esc_a1_game_start =scenario_autosave(st_save_start_escape)%

[sr_idle@nil]

 

Что не так?

Изменено пользователем dmitry-strelok

Поделиться этим сообщением


Ссылка на сообщение

Здравствуйте,тут такой вопрос.

Я сделал симмуляционный сквад.Появился вылет.

Expression : !m_error_code


Function : raii_guard::~raii_guard
File : D:\prog_repository\sources\trunk\xrServerEntities\script_storage.cpp
Line : 748
Description : ... - Зов Припяти\gamedata\scripts\smart_terrain.script:1256: attempt to compare nil with number

 

Вообще со сквадами у меня все хорошо,единственная проблема в симмуляционных сквадах.Уже как месяц пытаюсь разобраться.Вот и пришел к вам.

Вот что я делал.

simulation прописал вот что:

esc_stalker_base_default3_squad = esc_stalker_base
esc_stalker_base_default4_squad = esc_stalker_base

 

 

[esc_stalker_base]:default_base - база с которой 2 дефолтовых сквада должны идти.
sim_avail = true

[esc_stalker_base_default3_squad]:default_squad - 1-й дефолтовый сквад.
sim_avail = true

[esc_stalker_base_default4_squad]:default_squad - 2-й дефолтовый сквад.
sim_avail = true

[esc_lost_stoyanka]:default_resource - это свободный смарт,туда кто нибудь из сквадов должен идти.
sim_avail = true

[esc_lost_stoyanka2]:default_resource - это тоже свободный смарт и тоже кто нибудь из сквадов должен идти.
sim_avail = true

 

[esc_stalker_base_default3_squad]:online_offline_group
faction = stalker
npc = sim_default_stalker_1, sim_default_stalker_0, sim_default_stalker_0, sim_default_stalker_0
;spawn_point = esc_stalker_base_mini_bar_spawn_point
story_id = esc_stalker_base_default3_squad

[esc_stalker_base_default4_squad]:online_offline_group
faction = stalker
npc = sim_default_stalker_1, sim_default_stalker_1, sim_default_stalker_0, sim_default_stalker_0
;spawn_point = esc_stalker_base_mini_bar_spawn_point
story_id = esc_stalker_base_default4_squad
Тут в принципе 2 дефолтовых сквада.

 

[esc_stalker_base]
255,255,255,144
[esc_lost_stoyanka]
255,255,255,145
[esc_lost_stoyanka2]
255,255,255,146

 

Вот esc_lost_stoyanka:


[smart_terrain];esc_lost_stoyanka
squad_id = 4
max_population = 1
Вот esc_lost_stoyanka2:
[smart_terrain];esc_lost_stoyanka2
squad_id = 5
max_population = 1

Вроде все.
Что может быть не так?

Поделиться этим сообщением


Ссылка на сообщение
(изменено)

А нафиг мне разбираться если там все нормально!!!!
Но специально для тебя вот:

[smart_terrain];esc_stalker_base
squad_id = 3
max_population = 10
 
[exclusive]
!Скрыто!
Изменено пользователем dmitry-strelok

Поделиться этим сообщением


Ссылка на сообщение
(изменено)

Я заново по правил скрипты и все равно результат тот же.Может статья какая нибудь не полная.Параметры такие.

В restrictor type стоит NOT A restrictor.
Имя все норм.
Хз почему вылет.
Могу скрипты скинуть 2.
Надо?

Вот скрипты.

--'******************************************************


--'* Реестр смарт-террейнов. Игровое поле симуляции.
--'******************************************************

--' В этом ltx хранятся дескрипторы сквадов.
squad_ltx = system_ini()
setting_ini = ini_file("misc\\simulation.ltx")

local group_id_by_levels = {zaton = 1,
pripyat = 2,
jupiter = 3,
labx8 = 4,
jupiter_underground = 5,
escape = 6}

local board = nil

simulation_activities = {
stalker = {
squad = nil,
smart = { base = { prec = function(squad, target) return in_time_interval(18,8) and not xr_conditions.surge_started() and not travel_manager.check_squad_for_enemies(squad) and (target:name() == "zat_stalker_base_smart" or target:name() == "jup_a6" or target:name() == "pri_a16") end },
surge = { prec = function() return xr_conditions.surge_started() end },
territory= { prec = function() return in_time_interval(8,18) and not xr_conditions.surge_started() end },
resource = { prec = function(squad, target) return in_time_interval(8,18) and not xr_conditions.surge_started() end } -- and squad:has_detector()
},
actor = nil
},
bandit = {
squad = { stalker = { prec = function(squad, target) return in_time_interval(8,21) and not xr_conditions.surge_started() and simulation_objects.sim_dist_to(squad, target) <= 150 end }
},
smart = { base = { prec = function(squad, target) return in_time_interval(21,8) and not xr_conditions.surge_started() and not travel_manager.check_squad_for_enemies(squad) and (target:name() == "zat_stalker_base_smart" or target:name() == "jup_a10_smart_terrain") end },
territory= { prec = function() return in_time_interval(8,21) and not xr_conditions.surge_started() end },
surge = { prec = function() return xr_conditions.surge_started() end }
},
actor = { prec = function(squad, target) return has_alife_info("sim_bandit_attack_harder") and simulation_objects.sim_dist_to(squad, target) <= 150 end }
},
dolg = {
squad = { freedom = { prec = function(squad, target) return in_time_interval(8,19) and not xr_conditions.surge_started() and simulation_objects.sim_dist_to(squad, target) <= 150 end },
monster_predatory_day = { prec = function(squad, target) return in_time_interval(8,19) and not xr_conditions.surge_started() and simulation_objects.sim_dist_to(squad, target) <= 150 end },
monster_predatory_night = { prec = function(squad, target) return in_time_interval(8,19) and not xr_conditions.surge_started() and simulation_objects.sim_dist_to(squad, target) <= 150 end },
monster_vegetarian = { prec = function(squad, target) return in_time_interval(8,19) and not xr_conditions.surge_started() and simulation_objects.sim_dist_to(squad, target) <= 150 end },
monster_zombied_day = { prec = function(squad, target) return in_time_interval(8,19) and not xr_conditions.surge_started() and simulation_objects.sim_dist_to(squad, target) <= 150 end },
monster_special = { prec = function(squad, target) return in_time_interval(8,19) and not xr_conditions.surge_started() and simulation_objects.sim_dist_to(squad, target) <= 150 end }
},
smart = { base = { prec = function(squad, target) return in_time_interval(19,8) and not xr_conditions.surge_started() and not travel_manager.check_squad_for_enemies(squad) and (target:name() == "zat_stalker_base_smart" or target:name() == "jup_a6" or target:name() == "pri_a16") end },
territory= { prec = function() return in_time_interval(8,19) and not xr_conditions.surge_started() end },
surge = { prec = function() return xr_conditions.surge_started() end }
},
actor = nil
},
freedom = {
squad = { dolg = { prec = function(squad, target) return in_time_interval(8,19) and not xr_conditions.surge_started() and simulation_objects.sim_dist_to(squad, target) <= 150 end }
},
smart = { base = { prec = function(squad, target) return in_time_interval(19,8) and not xr_conditions.surge_started() and not travel_manager.check_squad_for_enemies(squad) and (target:name() == "zat_stalker_base_smart" or target:name() == "jup_a6" or target:name() == "pri_a16") end },
territory= { prec = function() return in_time_interval(8,19) and not xr_conditions.surge_started() end },
surge = { prec = function() return xr_conditions.surge_started() end }
},
actor = nil
},
killer = {
squad = nil,
smart = { territory= { prec = function() return not xr_conditions.surge_started() end },
surge = { prec = function() return xr_conditions.surge_started() end }
},
actor = { prec = function(squad, target) return simulation_objects.sim_dist_to(squad, target) <= 150 end }

},
zombied = {
squad = nil,
smart = { territory= { prec = function() return true end },
lair = { prec = function() return true end}
},
actor = nil

},
monster_predatory_day = {
squad = { monster_vegetarian = { prec = function() return in_time_interval(6,19) end },
stalker = { prec = function(squad, target) return in_time_interval(6, 19) and simulation_objects.sim_dist_to(squad, target) <= 150 end },
bandit = { prec = function(squad, target) return in_time_interval(6, 19) and simulation_objects.sim_dist_to(squad, target) <= 150 end },
dolg = { prec = function(squad, target) return in_time_interval(6, 19) and simulation_objects.sim_dist_to(squad, target) <= 150 end },
freedom = { prec = function(squad, target) return in_time_interval(6, 19) and simulation_objects.sim_dist_to(squad, target) <= 150 end },
killer = { prec = function(squad, target) return in_time_interval(6, 19) and simulation_objects.sim_dist_to(squad, target) <= 150 end }
},
smart = { territory= { prec = function() return in_time_interval(6, 19) end },
lair = { prec = function() return in_time_interval(19,6) end }
},
actor = { prec = function(squad, target) return in_time_interval(6, 19) and simulation_objects.sim_dist_to(squad, target) <= 150 end }
},
monster_predatory_night = {
squad = { monster_vegetarian = { prec = function() return in_time_interval(21,6) end },
stalker = { prec = function(squad, target) return in_time_interval(19,6) and simulation_objects.sim_dist_to(squad, target) <= 150 end },
bandit = { prec = function(squad, target) return in_time_interval(19,6) and simulation_objects.sim_dist_to(squad, target) <= 150 end },
dolg = { prec = function(squad, target) return in_time_interval(19,6) and simulation_objects.sim_dist_to(squad, target) <= 150 end },
freedom = { prec = function(squad, target) return in_time_interval(19,6) and simulation_objects.sim_dist_to(squad, target) <= 150 end },
killer = { prec = function(squad, target) return in_time_interval(19,6) and simulation_objects.sim_dist_to(squad, target) <= 150 end }
},
smart = { territory= { prec = function() return in_time_interval(19,6) end },
lair = { prec = function() return in_time_interval(6,19) end }
},
actor = { prec = function(squad, target) return in_time_interval(19,6) and simulation_objects.sim_dist_to(squad, target) <= 150 end }
},
monster_vegetarian = {
squad = nil,
smart = {
lair = { prec = function() return true end }
},
actor = { prec = function(squad, target) return in_time_interval(6, 19) and simulation_objects.sim_dist_to(squad, target) <= 150 end }
},
monster_zombied_day = {
squad = { stalker = { prec = function(squad, target) return in_time_interval(6, 19) and simulation_objects.sim_dist_to(squad, target) <= 150 end },
bandit = { prec = function(squad, target) return in_time_interval(6, 19) and simulation_objects.sim_dist_to(squad, target) <= 150 end },
dolg = { prec = function(squad, target) return in_time_interval(6, 19) and simulation_objects.sim_dist_to(squad, target) <= 150 end },
freedom = { prec = function(squad, target) return in_time_interval(6, 19) and simulation_objects.sim_dist_to(squad, target) <= 150 end },
killer = { prec = function(squad, target) return in_time_interval(6, 19) and simulation_objects.sim_dist_to(squad, target) <= 150 end }
},
smart = { territory= { prec = function() return not xr_conditions.surge_started() end },
lair = { prec = function() return in_time_interval(19,6) end }
},
actor = { prec = function(squad, target) return in_time_interval(6, 19) and simulation_objects.sim_dist_to(squad, target) <= 150 end }
},
monster_zombied_night = {
squad = { stalker = { prec = function(squad, target) return in_time_interval(19,6) and simulation_objects.sim_dist_to(squad, target) <= 150 end },
bandit = { prec = function(squad, target) return in_time_interval(19,6) and simulation_objects.sim_dist_to(squad, target) <= 150 end },
dolg = { prec = function(squad, target) return in_time_interval(19,6) and simulation_objects.sim_dist_to(squad, target) <= 150 end },
freedom = { prec = function(squad, target) return in_time_interval(19,6) and simulation_objects.sim_dist_to(squad, target) <= 150 end },
killer = { prec = function(squad, target) return in_time_interval(19,6) and simulation_objects.sim_dist_to(squad, target) <= 150 end }
},
smart = { territory= { prec = function() return in_time_interval(19,6) end },
lair = { prec = function() return in_time_interval(6,19) end }
},
actor = { prec = function(squad, target) return in_time_interval(19,6) and simulation_objects.sim_dist_to(squad, target) <= 150 end }
},
monster_special = {
squad = nil,
smart = { lair = { prec = function() return true end }
},
actor = nil
},
}








class "sim_board"
function sim_board:__init()
--' Таблица содержащая смарты и данные о них в формате:
--' smart = {smrt, targets = {}, dangers = {}, squads = {}, stayed_squad_quan = 0}
self.smarts = {}
self.simulation_started = true

--' Таблица смартов по именам.
self.smarts_by_names = {}

--' Таблица существующих отрядов.
self.squads = {}

--' отрисовывается ли сейчас поле на карте.
--self.show_flag = false

--' Таблица спаунсмартов. Смарт = уровень.
self.spawn_smarts = {}
-- Таблица для логовов мутантов на уровнях
self.mutant_lair = {}

-- Временная таблица
self.tmp_assigned_squad = {}
self.tmp_entered_squad = {}

printf("CREATE NEW SIM BOARD [%s]", tostring(self.sid))
end
function sim_board:start_sim()
self.simulation_started = true
end
function sim_board:stop_sim()
self.simulation_started = false
end
-- Перевод игрока в группировку.
function sim_board:set_actor_community(community)
---- Устанавливаем группировку игрока
db.actor:set_character_community(actor_communitites[community], 0, 0)
end
--' Регистрация нового смарта.
function sim_board:register_smart(obj)
printf("register_smart %s", obj:name())
if self.smarts[obj.id] ~= nil then
abort("Smart already exist in list [%s]", obj:name())
end

self.smarts[obj.id] = {smrt = obj, squads = {}, stayed_squad_quan = 0}

self.smarts_by_names[obj:name()] = obj

end
-- Инициализация смарта
function sim_board:init_smart(obj)
if self.tmp_assigned_squad[obj.id] ~= nil then
for k,v in pairs(self.tmp_assigned_squad[obj.id]) do
self:assign_squad_to_smart(v, obj.id)
end
self.tmp_assigned_squad[obj.id] = nil
end
if self.tmp_entered_squad[obj.id] ~= nil then
for k,v in pairs(self.tmp_entered_squad[obj.id]) do
self:enter_smart(v, obj.id)
end
self.tmp_entered_squad[obj.id] = nil
end
end
--' АнРегистрация смарта.
function sim_board:unregister_smart(obj)
if self.smarts[obj.id] == nil then
abort("Trying to unregister nil smart [%s]", obj:name())
end

self.smarts[obj.id] = nil
end

--' Создание нового отряда
function sim_board:create_squad(spawn_smart, sq_id)
printf("create squad called")
local squad_id = tostring(sq_id)

local squad = alife():create(squad_id,spawn_smart.position,
spawn_smart.m_level_vertex_id,
spawn_smart.m_game_vertex_id)
--local squad = squad_class(self, squad_id, faction_name, settings_id)
--squad:init_squad(spawn_smart)
printf("Creating squad[%s] in smart[%s]", squad_id, spawn_smart:name())
--' Определяем в каком смарте создать новый отряд
squad:create_npc(spawn_smart)
squad:set_squad_relation()
self:assign_squad_to_smart(squad, spawn_smart.id)

--' Пересчитываем Team, Squad, Group
for k in squad:squad_members() do
local obj = k.object
squad.board:setup_squad_and_group(obj)
end
return squad
end
--' Удалить отряд
function sim_board:remove_squad(squad)
printf("Remove squad %s", tostring(squad.id))
if squad.current_action == nil or
squad.current_action.dest_smrt == nil
then
squad.board:exit_smart(squad, squad.smart_id)
end
--squad:hide()

self:assign_squad_to_smart(squad, nil)

squad:remove_squad()
end
--' Назначение отряда в смарт.
function sim_board:assign_squad_to_smart(squad, smart_id)
-- Если смарта нету (например на загрузке он еще не загружен), то мы загоняем данные
-- во временную таблицу. И на загрузке смарта автодобавляем их.
--printf("assigned squad %s to smart [%s].", tostring(squad.id), tostring(smart_id))

if smart_id ~= nil and self.smarts[smart_id] == nil then
-- printf(" to tmp")
if self.tmp_assigned_squad[smart_id] == nil then
self.tmp_assigned_squad[smart_id] = {}
end
table.insert(self.tmp_assigned_squad[smart_id], squad)
return
end


--' Убираем отряд из старого смарта
local old_smart_id = nil
if squad.smart_id ~= nil then
old_smart_id = squad.smart_id
end
if old_smart_id ~= nil and self.smarts[old_smart_id] ~= nil then
self.smarts[old_smart_id].squads[squad.id] = nil
self.smarts[old_smart_id].smrt:refresh()
end

if smart_id == nil then
squad:assign_smart(nil)
return
end

squad:assign_smart(self.smarts[smart_id].smrt)

--' Прописываем отряд в новом смарте.
self.smarts[smart_id].squads[squad.id] = squad

self.smarts[smart_id].smrt:refresh()
end
--' Отряд покидает смарт (уменьшаются ресурсы)
function sim_board:exit_smart(squad, smart_id)
if smart_id == nil then
return
end

if squad.entered_smart ~= smart_id then
return
end

squad.entered_smart = nil

local smart = self.smarts[smart_id]

if smart == nil then
abort("Smart nil while smart_id not nil [%s]", tostring(smart_id))
end

printf("Squad %s exit smart %s. Quan = %s", tostring(squad.id), smart.smrt:name(), tostring(smart.stayed_squad_quan))
smart.stayed_squad_quan = smart.stayed_squad_quan - 1
smart.squads[squad.id] = nil

--smart.smrt:refresh()
end
--' Отряд занимает смарт (увеличиваются ресурсы)
function sim_board:enter_smart(squad, smart_id, after_load)
callstack()
if self.smarts[smart_id] == nil then
printf(" to tmp")
if self.tmp_entered_squad[smart_id] == nil then
self.tmp_entered_squad[smart_id] = {}
end
table.insert(self.tmp_entered_squad[smart_id], squad)
return
end

local smart = self.smarts[smart_id]

if squad.entered_smart ~= nil then
abort("Couldn enter to smart, becouse i'm not leave old one. Squad [%s]", squad.id)
end
squad.entered_smart = smart_id
printf("Squad %s enter smart %s. Quan = %s", tostring(squad.id), smart.smrt:name(), tostring(smart.stayed_squad_quan))

--smart.smrt:refresh()

smart.stayed_squad_quan = smart.stayed_squad_quan + 1
squad.items_spawned = false
end

-- установить squad и group в соответствии с работой
function sim_board:setup_squad_and_group(obj)
--printf("tsg["..obj:name().."]")
local level_name = level.name()
--' Группу берем из уровня.
local obj = alife():object(obj.id)

local group = group_id_by_levels[level_name] or 0

change_team_squad_group(obj, obj.team, obj.squad, group)

--' Сквад берем из смарта.
local squad = alife():object(obj.group_id)
if squad == nil then
change_team_squad_group(obj, obj.team, 0, obj.group)
--printf("TSG1: [%s][%s][%s]", tostring(obj.team), tostring(obj.squad), tostring(obj.group))
return
end

local smart = nil
if squad.current_action ~= nil and squad.current_action.name == "reach_target" then
smart = alife():object(squad.assigned_target_id)
elseif squad.smart_id ~= nil then
smart = alife():object(squad.smart_id)
end

if smart == nil then
change_team_squad_group(obj, obj.team, 0, obj.group)
--printf("TSG2: [%s][%s][%s]", tostring(obj.team), tostring(obj.squad), tostring(obj.group))
return
end
local obj_sq = 0
if smart:clsid() == clsid.smart_terrain then
obj_sq = smart.squad_id
end
change_team_squad_group(obj, obj.team, obj_sq, obj.group)
--printf("TSG3: [%s][%s][%s]", tostring(obj.team), tostring(obj.squad), tostring(obj.group))
end

--' Заполнение стартового расположения
function sim_board:fill_start_position()
if self.start_position_filled == true then
return
end
--printf("FILL START POSITION [%s]", self.player_name)
self.start_position_filled = true
for level in game_graph():levels() do
local section_name = "start_position_" .. alife():level_name(level.id)

if not setting_ini:section_exist(section_name) then
return
end

local n = setting_ini:line_count(section_name)
for i=0,n-1 do
local result, id, value = setting_ini:r_line(section_name,i,"","")
local smrt_names = utils.parse_names(value)
for k,v in pairs(smrt_names) do
local smart = self.smarts_by_names[v]
if smart == nil then
abort("Wrong smart name [%s] in start position", tostring(v))
end
local squad = self:create_squad(smart, id)
self:enter_smart(squad, smart.id)
--squad:update()
end
end
end
end


--' Возвратить смарт по его имени.
function sim_board:get_smart_by_name(name)
return self.smarts_by_names[name]
end
--' Возвращает количество отрядов в смарте.
function sim_board:get_smart_population(smart)
return self.smarts[smart.id].stayed_squad_quan
end

--' Получение игрового поля.
function get_sim_board()
if board == nil then
board = sim_board()
end
return board
end


function sim_board:get_squad_target(squad)
--printf("List of available target for %s", squad.id)

local available_targets = {}
local most_priority_task = nil
local max_prior = 0
for k,v in pairs(simulation_objects.get_sim_obj_registry().objects) do
local curr_prior = 0
-- Проверка против выдачи таска на себя.
if v.id ~= squad.id then
curr_prior = v:evaluate_prior(squad)
end
if curr_prior > 0 then
local target_tbl = {prior = curr_prior, target = v}
table.insert(available_targets, target_tbl)
end
end
if #available_targets > 0 then
table.sort(available_targets, function(a, B) return a.prior > b.prior end)
local max_id = math.floor(0.3 * #available_targets)
if max_id == 0 then max_id = 1 end
most_priority_task = available_targets[math.random(max_id)].target
end
--print_table(available_targets)
--printf("end of List of available target for %s", squad.id)
return most_priority_task or (squad.smart_id and alife():object(squad.smart_id)) or squad
end

local targets_by_squad_id = {}

--[[function sim_board:reset_targets()
for k,v in pairs(self.squads) do



end]]--
--' Обнуление списка на создании игры.
function clear()
board = nil
end

--' Тестовые функции
function print()
--print_table(get_sim_board().smarts)
end

 

local DEATH_IDLE_TIME = 10*60 -- секунд
local RESPAWN_IDLE = 1000 -- секунд игрового времени
local RESPAWN_RADIUS = 150 -- радиус респауна(если актер ближе, то не спаунить)
SMART_TERRAIN_SECT = "smart_terrain"
smart_terrains_by_name = {}
local locations_ini = ini_file("misc\\smart_terrain_masks.ltx")

nearest_to_actor_smart = {id = nil , dist = math.huge}

local path_fields = { "path_walk", "path_main", "path_home", "center_point" }

local valid_territory = {
default = true,
base = true,
resource = true,
territory = true
}

--' Проверка, что нпс подходит работе
local function job_avail_to_npc(npc_info, job_info, smart)
--printf("job_avail_to_npc %s job %s smart %s", npc_info.se_obj:name(), tostring(job_info.job_id), smart:name())
local job = smart.job_data[job_info.job_id]
if job ~= nil then
job = job.section
end

if smart.dead_time[job_info.job_id] ~= nil then
return false
end

-- Проверка условия "монстровости"
if job_info._precondition_is_monster ~= nil and job_info._precondition_is_monster ~= npc_info.is_monster then
return false
end

--' Проверяем подходит ли нпс по предикату
if job_info._precondition_function ~= nil then
if not job_info._precondition_function(npc_info.se_obj, smart, job_info._precondition_params, npc_info) then
return false
end
end
return true
end


-- Итерируемся по НПС, начинаем со свободных нпс, потом НПС на низкоприоритетных работах, потом на высокоприоритетных.
-- Для каждого конкретного НПС ищем работу.
-- Отсеиваем в поиске работы, приоритет которых ниже, чем у текущей.
local function job_iterator(jobs, npc_data, selected_job_prior, smart)
--printf(" iterate")
-- итерируемся по работам
local current_job_prior = selected_job_prior
local selected_job_id = nil
local selected_job_link = nil
for k,v in pairs(jobs) do
-- Если приоритет у проверяемой работы ниже, чем приоритет текущей выбранной работы НПС - завершаем выполнение
if current_job_prior > v._prior then
return selected_job_id, current_job_prior, selected_job_link
end
-- Проверяем, может ли НПС занять данную работу
if job_avail_to_npc(npc_data, v, smart) then
-- Это работа-кластер или работа-описание.
if v.job_id == nil then
-- Вызываем рекурсивно себя для списка работ кластера
selected_job_id, current_job_prior, selected_job_link = job_iterator(v.jobs, npc_data, selected_job_prior, smart)
else
-- Если работа пустая или ее занимаем мы сами - выбираем ее.
if v.npc_id == nil then
return v.job_id, v._prior, v
elseif v.job_id == npc_data.job_id then
return v.job_id, v._prior, v
end
end
end
end
return selected_job_id, current_job_prior, selected_job_link
end

-- Расстояние до работы
local function arrived_to_smart(obj, smart)
local obj_gv, obj_pos

local storage = db.storage[obj.id]

if storage == nil then
obj_gv, obj_pos = game_graph():vertex(obj.m_game_vertex_id), obj.position
else
local obj = db.storage[obj.id].object
obj_gv, obj_pos = game_graph():vertex(obj:game_vertex_id()), obj:position()
end

local smart_gv = game_graph():vertex(smart.m_game_vertex_id)

if obj.group_id then
local squad = smart.board.squads[obj.group_id]
if squad ~= nil and squad.current_action then
if squad.current_action.name == "reach_target" then
local squad_target = simulation_objects.get_sim_obj_registry().objects[squad.assigned_target_id]
if squad_target ~= nil then
return squad_target:am_i_reached(squad)
else
return alife():object(squad.assigned_target_id):am_i_reached(squad)
end
elseif squad.current_action.name == "stay_point" then
return true
end
end
end

if obj_gv:level_id() == smart_gv:level_id() then
return obj_pos:distance_to_sqr(smart.position) <= 10000 --Ближе 100 метров
else
return false
end
end

----------------------------------------------------------------------------------------------------------------------
-- Класс "se_smart_terrain". Обеспечивает поддержку smart terrain в ОФЛАЙНЕ.
----------------------------------------------------------------------------------------------------------------------
class "se_smart_terrain" (cse_alife_smart_zone)
function se_smart_terrain:__init(section) super(section)
self.initialized = false
self.b_registred = false
self.population = 0

self.npc_to_register = {}
self.npc_by_job_section = {}
self.dead_time = {}

-- Таблица для хранения зарегистренных НПС
self.npc_info = {} -- Те, кто уже пришел и стал на работу
self.arriving_npc = {} -- Только идущие на работу.
end
function se_smart_terrain:on_before_register()
cse_alife_smart_zone.on_before_register(self)
self.board = sim_board.get_sim_board()
self.board:register_smart(self)
self.smart_level = alife():level_name(game_graph():vertex(self.m_game_vertex_id):level_id())
--printf("SMARTLEVEL %s level %s", self:name(), tostring(self.smart_level))
end

function se_smart_terrain:on_register()
cse_alife_smart_zone.on_register(self)
-- Проверяем кастомдату обьекта на наличие стори айди.
story_objects.check_spawn_ini_for_story_id(self)
simulation_objects.get_sim_obj_registry():register(self)

printf("register smart %s", self:name())

if dev_dedug then
self:refresh()
end

printf("Returning alife task for object [%s] game_vertex [%s] level_vertex [%s] position %s", self.id, self.m_game_vertex_id, self.m_level_vertex_id, vec_to_str(self.position))
self.smart_alife_task = CALifeSmartTerrainTask(self.m_game_vertex_id, self.m_level_vertex_id)

smart_terrains_by_name[self:name()] = self
self.b_registred = true

self:load_jobs()

self.board:init_smart(self)

if self.need_init_npc == true then
self.need_init_npc = false
self:init_npc_after_load()
end

-- Регистрим персонажей, которые добавили до регистрации смарта. (отложенный список)
self:register_delayed_npc()

self.check_time = time_global()
end
-- анрегистрация объекта в симуляторе.
-- вызывается симулятором.
function se_smart_terrain:on_unregister()
cse_alife_smart_zone.on_unregister(self)
self.board:unregister_smart(self)
smart_terrains_by_name[self:name()] = nil
unregister_story_object_by_id(self.id)
simulation_objects.get_sim_obj_registry():unregister(self)
end
-- чтение custom data.
function se_smart_terrain:read_params()
self.ini = self:spawn_ini()

if not self.ini:section_exist( SMART_TERRAIN_SECT ) then
abort( "[smart_terrain %s] no configuration!", self:name() )
self.disabled = true
return
end
local filename = utils.cfg_get_string(self.ini, SMART_TERRAIN_SECT, "cfg", self, false, "")
local fs = getFS()
if filename then
if fs:exist("$game_config$",filename) then
self.ini = ini_file(filename)
else
abort("There is no configuration file [%s] in smart_terrain [%s]", filename, self:name())
end
end
local ini = self.ini
self.sim_type = utils.cfg_get_string(ini, SMART_TERRAIN_SECT, "sim_type", self, false, "", "default")

--' Вычитка симуляционных свойств
if valid_territory[self.sim_type] == nil then
abort("Wrong sim_type value [%s] in smart [%s]", self.sim_type, self:name())
end

self.squad_id = utils.cfg_get_number(ini, SMART_TERRAIN_SECT, "squad_id", self, false, 0)
self.respawn_sector = utils.cfg_get_string(ini, SMART_TERRAIN_SECT, "respawn_sector", self, false, "")
self.respawn_radius = utils.cfg_get_number(ini, SMART_TERRAIN_SECT, "respawn_radius", self, false, 150)
if self.respawn_sector ~= nil then
if self.respawn_sector == "default" then
self.respawn_sector = "all"
end
self.respawn_sector = xr_logic.parse_condlist(nil, SMART_TERRAIN_SECT, "respawn_sector", self.respawn_sector)
end

self.mutant_lair = utils.cfg_get_bool(ini, SMART_TERRAIN_SECT, "mutant_lair", self, false)
self.no_mutant = utils.cfg_get_bool(ini, SMART_TERRAIN_SECT, "no_mutant", self, false)
if self.no_mutant == true then
printf("Found no mutant point %s", self:name())
end
self.forbidden_point = utils.cfg_get_string(ini, SMART_TERRAIN_SECT, "forbidden_point", self, false, "")

--' Рестрикторы для симуляции
self.def_restr = utils.cfg_get_string(ini, SMART_TERRAIN_SECT, "def_restr", self, false, "", nil)
self.att_restr = utils.cfg_get_string(ini, SMART_TERRAIN_SECT, "att_restr", self, false, "", nil)
self.safe_restr = utils.cfg_get_string(ini, SMART_TERRAIN_SECT, "safe_restr", self, false, "", nil)

self.spawn_point = utils.cfg_get_string(ini, SMART_TERRAIN_SECT, "spawn_point", self, false, "")

self.arrive_dist = utils.cfg_get_number(ini, SMART_TERRAIN_SECT, "arrive_dist", self, false, 30)

-- self.max_population = utils.cfg_get_number(ini, SMART_TERRAIN_SECT, "max_population", self, false, 0)
local max_population = utils.cfg_get_string(ini, SMART_TERRAIN_SECT, "max_population", self, false, "", 0)
local parsed_condlist = xr_logic.parse_condlist(nil, SMART_TERRAIN_SECT, "max_population", max_population)
self.max_population = tonumber(xr_logic.pick_section_from_condlist(get_story_object("actor"), nil, parsed_condlist))

-- self.sim_avail = utils.cfg_get_string(ini, SMART_TERRAIN_SECT, "sim_avail", self, false, "")
-- if self.sim_avail ~= nil then
-- self.sim_avail = xr_logic.parse_condlist(nil, SMART_TERRAIN_SECT, "sim_avail", self.sim_avail)
-- end

local respawn_params = utils.cfg_get_string(ini, SMART_TERRAIN_SECT, "respawn_params", self, false, "", nil)
self.respawn_only_smart = utils.cfg_get_bool(ini, SMART_TERRAIN_SECT, "respawn_only_smart", self, false, false)

local smart_control_section = utils.cfg_get_string(ini, SMART_TERRAIN_SECT, "smart_control", self, false, "", nil)

if smart_control_section ~= nil then
self.base_on_actor_control = smart_terrain_control.CBaseOnActorControl(self, ini, smart_control_section)
end
self.respawn_point = false
if respawn_params ~= nil then
self:check_respawn_params(respawn_params)
end


if level.patrol_path_exists(self:name() .. "_traveller_actor") then
printf("Smart_terrain [%s] has no traveller_actor path!!!!!", self:name())
self.traveler_actor_path = self:name() .. "_traveller_actor"
end

if level.patrol_path_exists(self:name() .. "_traveller_squad") then
printf("Smart_terrain [%s] has no traveller_squad path!!!!!", self:name())
self.traveler_squad_path = self:name() .. "_traveller_squad"
end

if not locations_ini:section_exist(self:name()) then
printf("! SMART_TERRAIN [%s] has no terrain_mask section in smart_terrain_masks.ltx!!!",self:name())
end
end

--*******************************************************
-- МЕТОДЫ ДЛЯ РАБОТЫ С НПС
--*******************************************************
-- заполнить информацию о персонаже
-- у монстров нету метода profile_name()
function se_smart_terrain:fill_npc_info(obj)
local npc_info = {}
printf("filling npc_info for obj [%s]", tostring(obj:name()))

local is_stalker = IsStalker(obj)
npc_info.se_obj = obj
npc_info.is_monster = not is_stalker
npc_info.need_job = "nil" -- Специально для смены гвардов. Указывает на какую работу хочет данный чувак.
npc_info.job_prior = -1
npc_info.job_id = -1
npc_info.begin_job = false

if is_stalker then
npc_info.stype = modules.stype_stalker
else
npc_info.stype = modules.stype_mobile
end

return npc_info
end

function se_smart_terrain:refresh_script_logic(obj_id)
local object = alife():object(obj_id)
local stype = modules.stype_mobile
if IsStalker(object) then
stype = modules.stype_stalker
end
xr_logic.initialize_obj(db.storage[object.id].object, db.storage[object.id], false, db.actor, stype)
end

-- добавить npc в smart terrain.
function se_smart_terrain:register_npc(obj)
printf("[smart_terrain %s] register called obj=%s", self:name(), obj:name())
self.population = self.population + 1

if self.b_registred == false then
table.insert(self.npc_to_register, obj)
return
end

-- Только для монстров, чтобы ходили по смартам.
if not IsStalker(obj) then
obj:smart_terrain_task_activate()
end

obj.m_smart_terrain_id = self.id
if arrived_to_smart(obj, self) then
self.npc_info[obj.id] = self:fill_npc_info(obj)

-- Затычка на случай если мы регистримся в смарт, из которого только что сами вынесли всех врагов.
self.dead_time = {}

-- тут надо найти чуваку работу
self:select_npc_job(self.npc_info[obj.id])
else
self.arriving_npc[obj.id] = obj
end
end
-- Регистрация НПС в список отложенных. Осуществляется на загрузке или на регистрации НПС, пока не зарегистрен смарт
function se_smart_terrain:register_delayed_npc()
for k,v in pairs(self.npc_to_register) do
self:register_npc(v)
end
self.npc_to_register = {}
end
-- отпустить npc
function se_smart_terrain:unregister_npc(obj)
--callstack()
printf("smart [%s] unregister npc [%s]", self:name(), obj:name())

self.population = self.population - 1

if self.npc_info[obj.id] ~= nil then
-- TODO: Тут надо выгнать чувака с занимаемой им работы
self.npc_info[obj.id].job_link.npc_id = nil
self.npc_info[obj.id] = nil
obj:clear_smart_terrain()

if db.storage[obj.id] ~= nil then
local object = db.storage[obj.id].object
local stype = modules.stype_mobile
if IsStalker(obj) then
stype = modules.stype_stalker
end
xr_logic.initialize_obj(object, db.storage[obj.id], false, db.actor, stype)
end
return
end
if self.arriving_npc[obj.id] ~= nil then
self.arriving_npc[obj.id] = nil
obj:clear_smart_terrain()
return
end

abort("self.npc_info[obj.id] = nil !!! obj.id=%d", obj.id)
end
-- Убрать убитого
function se_smart_terrain:clear_dead(obj)
if self.npc_info[obj.id] ~= nil then
-- Устанавливаем таймер смерти на работе
self.dead_time[self.npc_info[obj.id].job_id] = game.get_game_time()

self.npc_info[obj.id].job_link.npc_id = nil
self.npc_info[obj.id] = nil
obj:clear_smart_terrain()
return
end
if self.arriving_npc[obj.id] ~= nil then
self.arriving_npc[obj.id] = nil
obj:clear_smart_terrain()
return
end

abort("self.npc_info[obj.id] = nil !!! obj.id=%d", obj.id)
end
-- выдать объекту задание.
function se_smart_terrain:task(obj)
if self.arriving_npc[obj.id] ~= nil then
return self.smart_alife_task
end
return self.job_data[self.npc_info[obj.id].job_id].alife_task
end


--*******************************************************
-- Функции для работы с работами
--*******************************************************
-- Загрузка работ (из gulag_general)
function se_smart_terrain:load_jobs()
--printf("LOAD JOBS %s", self:name())
-- Загружаем иерархию работ
self.jobs = gulag_general.load_job(self)

-- Загружаем ltx работ.
self.ltx, self.ltx_name = xr_gulag.loadLtx(self:name())
-- Сортируем всю иерархию по уменьшению приоритета
-- Рекурсивная функция сортировки
local function sort_jobs(jobs)
for k,v in pairs(jobs) do
if v.jobs ~= nil then
sort_jobs(v.jobs)
end
end
table.sort(jobs, function(a, B) return a._prior > b._prior end )
end

-- if self:name() == "jup_a10_smart_terrain" then
-- printf("before sort")
-- store_table(self.jobs)
-- end

sort_jobs(self.jobs)

--if self:name() == "jup_a10_smart_terrain" then
-- printf("after sort")
-- store_table(self.jobs)
--end


-- Надо сделать постобработку работ. Проинитить все неиниченные поля
-- Для более быстрого доступа нужно вычленить параметры работ в отдельную таблицу вида:
--self.job_data[job_id] = {}
local id = 0
self.job_data = {}
local function get_jobs_data(jobs)
for k,v in pairs(jobs) do
if v.jobs ~= nil then
get_jobs_data(v.jobs)
else
if v.job_id == nil then
print_table(self.jobs)
abort("Incorrect job table")
end
self.job_data[id] = v.job_id

self.job_data[id]._prior = v._prior -- Кешируем для проверки
v.job_id = id
id = id + 1
end
end
end

get_jobs_data(self.jobs)
-- Пробегаемся по работам и высчитываем для каждой работы alife_task
for k,v in pairs(self.job_data) do
local section = v.section
local ltx = v.ini_file or self.ltx
if not ltx:line_exist(section, "active") then
abort("gulag: ltx=%s no 'active' in section %s", self.ltx_name, section)
end
local active_section = ltx:r_string(section, "active")


-- printf("job_type %s job_section %s", tostring(v.job_type), tostring(section))
-- В зависимости от типа работы по разному считаем alife_path
if v.job_type == "path_job" then -- работа задается патрульным путем
local path_field
for i,vv in pairs(path_fields) do
if ltx:line_exist(active_section, vv) then
path_field = vv
break
end
end

--printf("path_field %s prefix_name %s active_section %s", tostring(path_field), tostring(v.prefix_name), tostring(active_section))
local path_name = ltx:r_string(active_section, path_field)
if v.prefix_name ~= nil then
path_name = v.prefix_name .. "_" .. path_name
else
path_name = self:name() .. "_" .. path_name
end

if path_field == "center_point" then --' TODO убрать затык когда переделаем кемпы на смарткаверы
if level.patrol_path_exists(path_name .. "_task") then
path_name = path_name .. "_task"
end
end

v.alife_task = CALifeSmartTerrainTask(path_name)

elseif v.job_type == "smartcover_job" then -- работа задается смарткавером
local smartcover_name = ltx:r_string(active_section, "cover_name")
local smartcover = se_smart_cover.registered_smartcovers[smartcover_name]
if smartcover == nil then
abort("There is an exclusive job with wrong smatrcover name [%s] smartterrain [%s]", tostring(smartcover_name), self:name())
end
printf("Returning alife task for object [%s] game_vertex [%s] level_vertex [%s] position %s", smartcover.id, smartcover.m_game_vertex_id, smartcover.m_level_vertex_id, vec_to_str(smartcover.position))
v.alife_task = CALifeSmartTerrainTask(smartcover.m_game_vertex_id, smartcover.m_level_vertex_id)

elseif v.job_type == "point_job" then -- работа задается позицией
v.alife_task = self.smart_alife_task
end

v.game_vertex_id = v.alife_task:game_vertex_id()
v.level_id = game_graph():vertex(v.game_vertex_id):level_id()
v.position = v.alife_task:position()
end
end

-- Апдейт работ смарттеррейна.
-- Если передается object, то значит нужно найти только для него
function se_smart_terrain:update_jobs()
self:check_alarm()
--printf("UPDATE JOBS %s", self:name())

-- Проверяем, дошел ли кто-то до смарта
for k,v in pairs(self.arriving_npc) do
if arrived_to_smart(v, self) then
self.npc_info[v.id] = self:fill_npc_info(v)

-- Затычка на случай если мы регистримся в смарт, из которого только что сами вынесли всех врагов.
self.dead_time = {}

-- тут надо найти чуваку работу
self:select_npc_job(self.npc_info[v.id])

self.arriving_npc[k] = nil
end
end

-- Сортируем НПС по увеличению приоритета занимаемой работы
table.sort(self.npc_info, function(a, B) return a.job_prior < b.job_prior end )
for k,v in pairs(self.npc_info) do
self:select_npc_job(v)
end
end
-- Выбор работы для персонажа
function se_smart_terrain:select_npc_job(npc_info)
-- Выбираем работу
local selected_job_id, selected_job_prior, selected_job_link = job_iterator(self.jobs, npc_info, 0, self)
if selected_job_id == nil then
print_table(self.jobs)
abort("Insufficient smart_terrain jobs %s", self:name())
end

-- Назначаем работу
if selected_job_id ~= npc_info.job_id and selected_job_link ~= nil then
-- Установить себе выбранную работу
--printf("NPC %s FOUND JOB %s SECTION %s", npc_info.se_obj:name(), selected_job_id, self.job_data[selected_job_link.job_id].section)
-- Если НПС был на работе - выгоняем его с нее.
if npc_info.job_link ~= nil then
self.npc_by_job_section[self.job_data[npc_info.job_link.job_id].section] = nil
npc_info.job_link.npc_id = nil
end

selected_job_link.npc_id = npc_info.se_obj.id
self.npc_by_job_section[self.job_data[selected_job_link.job_id].section] = selected_job_link.npc_id

npc_info.job_id = selected_job_link.job_id
npc_info.job_prior = selected_job_link._prior
npc_info.begin_job = false
-- сохраняем ссылку на работу, для облегчения удаления
npc_info.job_link = selected_job_link

-- завершаем текущую работу
local obj_storage = db.storage[npc_info.se_obj.id]
if obj_storage ~= nil then
xr_logic.switch_to_section(obj_storage.object, self.ltx, "nil")
end
end

if npc_info.begin_job ~= true then
-- Проверяем, дошел ли персонаж до работы (то есть может ли он начать ее выполнение)
local job_data = self.job_data[npc_info.job_id]
-- Начинаем выполнять работу
printf("[smart_terrain %s] gulag: beginJob: obj=%s job= %s", self:name(), npc_info.se_obj:name(), job_data.section)
-- Смена работы, очищаем память для оффлайнового обьекта.
db.offline_objects[npc_info.se_obj.id] = {}
npc_info.begin_job = true

local obj_storage = db.storage[npc_info.se_obj.id]
if obj_storage ~= nil then
self:setup_logic(obj_storage.object)
end
end
end
-- настроить логику для объекта, который в онлайне.
function se_smart_terrain:setup_logic(obj)
--printf("setup npc logic %s", obj:name())
-- callstack()
local npc_data = self.npc_info[obj:id()]
local job = self.job_data[npc_data.job_id]
local ltx = job.ini_file or self.ltx
local ltx_name = job.ini_path or self.ltx_name

xr_logic.configure_schemes(obj, ltx, ltx_name, npc_data.stype, job.section, job.prefix_name or self:name())

local sect = xr_logic.determine_section_to_activate(obj, ltx, job.section, db.actor)
if utils.get_scheme_by_section(job.section) == "nil" then
abort("[smart_terrain %s] section=%s, don't use section 'nil'!", self:name(), sect)
end

xr_logic.activate_by_section(obj, ltx, sect, job.prefix_name or self:name(), false)
end
-- получить работу, которую занимает объект
function se_smart_terrain:getJob(obj_id)
return self.npc_info[obj_id] and self.job_data[self.npc_info[obj_id].job_id]
end
-- Получение персонажа, который занимает указанную работу.
function se_smart_terrain:idNPCOnJob(job_name)
return self.npc_by_job_section[job_name]
end
function se_smart_terrain:switch_to_desired_job(npc)
-- Берем текущую работу НПС
local npc_id = npc:id()
local npc_info = self.npc_info[npc_id]

--printf("***** %s -> %s", npc:name(), tostring(npc_info.need_job))
local changing_npc_id = self.npc_by_job_section[npc_info.need_job]
--printf("changing_npc_id %s", tostring(changing_npc_id))

if changing_npc_id == nil then
-- Мы не нашли с кем меняться, просто ресетим себя
self.npc_info[npc_id].job_link = nil
self.npc_info[npc_id].job_id = -1
self.npc_info[npc_id].job_prior = -1
self:select_npc_job(self.npc_info[npc_id])

--print_table(self.npc_by_job_section)
--abort("ERROR during channging NPC")
return
end

if self.npc_info[changing_npc_id] == nil then
-- Мы не нашли с кем меняться, просто ресетим себя
self.npc_info[npc_id].job_link = nil
self.npc_info[npc_id].job_id = -1
self.npc_info[npc_id].job_prior = -1
self:select_npc_job(self.npc_info[npc_id])

--print_table(self.npc_by_job_section)
--abort("ERROR during channging NPC")
return
end

local desired_job = self.npc_info[changing_npc_id].job_id

-- Переключаем НПС на желаемую работу
if npc_info.job_link ~= nil then
self.npc_by_job_section[self.job_data[npc_info.job_link.job_id].section] = nil
npc_info.job_link.npc_id = nil
end

local selected_job_link = self.npc_info[changing_npc_id].job_link

selected_job_link.npc_id = npc_info.se_obj.id

self.npc_by_job_section[self.job_data[selected_job_link.job_id].section] = selected_job_link.npc_id

npc_info.job_id = selected_job_link.job_id
npc_info.job_prior = selected_job_link._prior
npc_info.begin_job = true

-- сохраняем ссылку на работу, для облегчения удаления
npc_info.job_link = selected_job_link
npc_info.need_job = "nil"

local obj_storage = db.storage[npc_id]
if obj_storage ~= nil then
self:setup_logic(obj_storage.object)
end

-- Освобождаем НПС, который занимает желаемую работу и говорим ему перевыбрать работу
self.npc_info[changing_npc_id].job_link = nil
self.npc_info[changing_npc_id].job_id = -1
self.npc_info[changing_npc_id].job_prior = -1
self:select_npc_job(self.npc_info[changing_npc_id])
end


--*******************************************************
-- СЕЙВ/ЛОАД
--*******************************************************
-- сохранение
function se_smart_terrain:STATE_Write(packet)
cse_alife_smart_zone.STATE_Write(self, packet)

set_save_marker(packet, "save", false, "se_smart_terrain")

-- Информацию о НПС, идущих в смарт
local n = 0
for k,v in pairs(self.arriving_npc) do
n = n + 1
end
packet:w_u8(n)
for k,v in pairs(self.arriving_npc) do
packet:w_u16(k)
end


-- Информацию о НПС в смарте
n = 0
for k,v in pairs(self.npc_info) do
n = n + 1
end

packet:w_u8(n)
for k,v in pairs(self.npc_info) do
packet:w_u16(k)
packet:w_u8(v.job_prior)
packet:w_u8(v.job_id)
packet:w_bool(v.begin_job)
packet:w_stringZ(v.need_job)
end

n = 0
for k,v in pairs(self.dead_time) do
n = n + 1
end
packet:w_u8(n)
for k,v in pairs(self.dead_time) do
packet:w_u8(k)
utils.w_CTime(packet, v)
end

if self.base_on_actor_control ~= nil then
packet:w_bool(true)
self.base_on_actor_control:save(packet)
else
packet:w_bool(false)
end

if self.respawn_point then
packet:w_bool(true)
local n = 0
for k,v in pairs(self.already_spawned) do
n = n + 1
end
packet:w_u8(n)
for k,v in pairs(self.already_spawned) do
packet:w_stringZ(k)
packet:w_u8(v.num)
end

if self.last_respawn_update ~= nil then
packet:w_bool(true)
utils.w_CTime(packet, self.last_respawn_update)
else
packet:w_bool(false)
end
else
packet:w_bool(false)
end

if self.population < 0 then
abort("Smart_terrain [%s] population can't be less than zero!!!", self:name())
end
packet:w_u8(self.population)

set_save_marker(packet, "save", true, "se_smart_terrain")
end

-- восстановление
function se_smart_terrain:STATE_Read(packet, size)
cse_alife_smart_zone.STATE_Read(self, packet, size)

-- под LevelEditor не пытаться читать из пакета ничего
if editor() then
return
end

set_save_marker(packet, "load", false, "se_smart_terrain")
self:read_params()

-- Информацию о НПС, идущих в смарт
local n = packet:r_u8()
self.arriving_npc = {}
for i = 1,n do
local id = packet:r_u16()
self.arriving_npc[id] = false
end

-- Информацию о НПС в смарте
n = packet:r_u8()
--printf("load %s npc", tostring(n))
self.npc_info = {}
for i = 1,n do
local id = packet:r_u16()
--printf("__ id %s", tostring(id))
self.npc_info[id] = {}
local npc_info = self.npc_info[id]
npc_info.job_prior = packet:r_u8()
--printf("__ job_prior %s", tostring(npc_info.job_prior))
if npc_info.job_prior == 255 then
npc_info.job_prior = -1
end
npc_info.job_id = packet:r_u8()
--printf("__ job_id %s", tostring(npc_info.job_id))
if npc_info.job_id == 255 then
npc_info.job_id = -1
end
npc_info.begin_job = packet:r_bool()
--printf("__ begin_job %s", tostring(npc_info.begin_job))
npc_info.need_job = packet:r_stringZ()
end

n = packet:r_u8()
self.dead_time = {}
--printf("load %s dead_time", tostring(n))
for i =1,n do
local job_id = packet:r_u8()
--printf("__ job_id %s", tostring(job_id))
local dead_time = utils.r_CTime(packet)
self.dead_time[job_id] = dead_time
end

self.need_init_npc = true

if self.script_version > 9 then
if packet:r_bool() == true then
--self.base_on_actor_control
self.base_on_actor_control:load(packet)
end
end

local respawn_point = packet:r_bool()
--printf("LOAD RESPAWN %s", self:name())
if respawn_point then
n = packet:r_u8()
for i = 1, n do
local id = packet:r_stringZ()
local num = packet:r_u8()
self.already_spawned[id].num = num
end

if self.script_version > 11 then
local exist = packet:r_bool()
if exist then
self.last_respawn_update = utils.r_CTime(packet)
else
self.last_respawn_update = nil
end
end
end

self.population = packet:r_u8()

set_save_marker(packet, "load", true, "se_smart_terrain")
end
-- Инициализация НПС после загрузки.
function se_smart_terrain:init_npc_after_load()
local function find_job(jobs, npc_info)
for k,v in pairs(jobs) do
if v.jobs ~= nil then
find_job(v.jobs, npc_info)
else
if v.job_id == npc_info.job_id then
npc_info.job_link = v
v.npc_id = npc_info.se_obj.id
return
end
end
end
end


local sim = alife()
--printf("[%s] init_npc_after_load", self:name())
for k,v in pairs(self.arriving_npc) do
local sobj = sim:object(k)
if sobj ~= nil then
self.arriving_npc[k] = sobj
else
self.arriving_npc[k] = nil
end
end

for k,v in pairs(self.npc_info) do
local sobj = sim:object(k)
if sobj ~= nil then
local npc_info = self:fill_npc_info(sobj)

npc_info.job_prior = v.job_prior
npc_info.job_id = v.job_id
npc_info.begin_job = v.begin_job
npc_info.need_job = v.need_job

--Теперь надо найти данную работу и выставить ссылку на нее.
find_job(self.jobs, npc_info)

self.npc_info[k] = npc_info
if npc_info.job_link ~= nil then
self.npc_by_job_section[self.job_data[npc_info.job_link.job_id].section] = k
end
else
self.npc_info[k] = nil
end
end
end


--' Возвращает отформатированную строку свойств смарта
function se_smart_terrain:get_smart_props()
local props = smart_names.get_smart_terrain_name(self)
if(props==nil) or (_G.dev_debug) then
props = self:name().." ["..self.id.."]\\n"..
self.sim_type.."\\n"..
"squad_id = "..tostring(self.id).."\\n"..
"capacity = "..tostring(self.max_population).." ("..sim_board.get_sim_board():get_smart_population(self)..")\\n"

if self.respawn_point ~= nil and self.already_spawned ~= nil then
props = props.."\\nalready_spawned :\n"
for k,v in pairs(self.already_spawned) do
props = props.."["..k.."] = "..v.num.."("..xr_logic.pick_section_from_condlist(db.actor, nil,self.respawn_params[k].num)..")\\n"
end
if self.last_respawn_update then
props = props.."\\ntime_to_spawn:"..tostring(RESPAWN_IDLE - game.get_game_time():diffSec(self.last_respawn_update)).."\\n"
end
end

--' Добавляем информацию о находящихся в смарте отрядах
for k,v in pairs(sim_board.get_sim_board().smarts[self.id].squads) do
props = props .. tostring(v.id) .. "\\n"
end
end
return props
end



--' Отрисовка смарта на игровом поле
function se_smart_terrain:show()
local time = time_global()
if(self.showtime~=nil) and (self.showtime+200>=time) then
return
end
self.showtime = time

local player = self.player_name
local spot = "neutral"

if self.sim_avail == nil or xr_logic.pick_section_from_condlist(db.actor or alife():actor(), self, self.sim_avail) == "true" then
spot = "friend"
else
spot = "enemy"
end


if(self.smrt_showed_spot==spot) then
level.map_change_spot_hint(self.id, "alife_presentation_smart_"..self.sim_type.."_"..self.smrt_showed_spot, self:get_smart_props())
return
end

if(_G.dev_debug) then
if(self.smrt_showed_spot~=nil) then
level.map_remove_object_spot(self.id, "alife_presentation_smart_"..self.sim_type.."_"..self.smrt_showed_spot)
end
level.map_add_object_spot(self.id, "alife_presentation_smart_"..self.sim_type.."_"..spot, self:get_smart_props())
self.smrt_showed_spot = spot
else

if(self.smrt_showed_spot~=nil) and
(level.map_has_object_spot(self.id, "alife_presentation_smart_"..self.sim_type.."_"..self.smrt_showed_spot)~=0)
then
level.map_remove_object_spot(self.id, "alife_presentation_smart_base_"..self.smrt_showed_spot)
end

end
end
--' Обновление информации о смарте на игровом поле
function se_smart_terrain:refresh()
self:show()
end
--' Убирание отрисовки смарта на игровом поле
function se_smart_terrain:hide()
if self.smrt_showed_spot == nil then
return
end
level.map_remove_object_spot(self.id, "alife_presentation_smart_"..self.sim_type.."_"..self.smrt_showed_spot)
end


local function is_only_monsters_on_jobs(npc_info)
for k,v in pairs (npc_info) do
if v.is_monster == false then
return false
end
end
return true
end

-- Обновление.
-- В онлайне вызывается через binder.
-- Также может вызваться принудительно из xr_effects
function se_smart_terrain:update()
cse_alife_smart_zone.update( self )
if dev_debug then
self:refresh() -- Не забыть потом заремить
end

local current_time = time_global()

if simulation_objects.is_on_the_same_level(self, alife():actor()) then
local dist_to_actor = self.position:distance_to(alife():actor().position)
local old_dist_to_actor = (nearest_to_actor_smart.id == nil and nearest_to_actor_smart.dist) or alife():object(nearest_to_actor_smart.id).position:distance_to(alife():actor().position)
if dist_to_actor < old_dist_to_actor then
nearest_to_actor_smart.id = self.id
nearest_to_actor_smart.dist = dist_to_actor
end
end

-- Апдейт респауна отрядов симуляции.
if self.respawn_params ~= nil then
self:try_respawn()
end

if self.check_time~=nil and current_time < self.check_time then
return
end

--проверить есть ли кто-то в смарте, если есть и костры не включены то включить,
--еще проверить есть ли актер, чтоб была гарантия что костры проспонились...
if is_only_monsters_on_jobs(self.npc_info) and self.campfires_on then
bind_campfire.turn_off_campfires_by_smart_name(self:name())
self.campfires_on = false
elseif not is_only_monsters_on_jobs(self.npc_info) and not self.campfires_on then
bind_campfire.turn_on_campfires_by_smart_name(self:name())
self.campfires_on = true
end

if db.actor ~= nil then
local distance = db.actor:position():distance_to_sqr(self.position)
local idle_time = math.max(60, 0.003 * distance)
self.check_time = current_time + idle_time
else
self.check_time = current_time + 10
end

-- Проверяем, не истек ли запрет на занимание работы, на которой убили НПС
local current_time = game.get_game_time()
for k,v in pairs(self.dead_time) do
if current_time:diffSec(v) >= DEATH_IDLE_TIME then
self.dead_time[k] = nil
end
end

-- Перевыбор работ
self:update_jobs()

-- Апдейтим контрол реакции базы на игрока
if self.base_on_actor_control ~= nil then
self.base_on_actor_control:update()
end
-- Апдейт доступности для симуляции.
simulation_objects.get_sim_obj_registry():update_avaliability(self)
end
-- Переведение смарта в напряженное состояние
function se_smart_terrain:set_alarm()
self.smart_alarm_time = game.get_game_time()
end
-- Проверяет. а не прошел ли аларм в смарте
function se_smart_terrain:check_alarm()
if self.smart_alarm_time == nil then
return
end
if game.get_game_time():diffSec(self.smart_alarm_time) > 21600 then -- 6 Игровых часов
self.smart_alarm_time = nil
end
end


-- установить логику и сообщить смарту, что объект перешёл в онлайн.
-- вызывается из net_spawn() объектов
function setup_gulag_and_logic_on_spawn(obj, st, sobject, stype, loaded)
local sim = alife()
local sobject = alife():object(obj:id())
if sim ~= nil and sobject then
local strn_id = sobject.m_smart_terrain_id
printf( "setup_gulag_and_logic_on_spawn obj=%s, strn_id=%s, loaded=%s", obj:name(), tostring(strn_id), tostring(loaded))

if strn_id ~= nil and strn_id ~= 65535 then
local strn = sim:object(strn_id)
local need_setup_logic = (not loaded) and (strn.npc_info[obj:id()] and strn.npc_info[obj:id()].begin_job == true)

if need_setup_logic then
strn:setup_logic(obj)
else
xr_logic.initialize_obj(obj, st, loaded, db.actor, stype)
end
else
xr_logic.initialize_obj(obj, st, loaded, db.actor, stype)
end
else
xr_logic.initialize_obj(obj, st, loaded, db.actor, stype)
end
end

-- Убираем объект из смарта при смерти
function on_death(obj)
local sim = alife()
if sim then
local obj = sim:object(obj.id)
if obj == nil then return end
local strn_id = obj:smart_terrain_id()
if strn_id ~= 65535 then
printf("clear dead object %s", obj:name())
sim:object(strn_id):clear_dead(obj)
end
end
end


--***********************************************************************************************
--* SIMULATION_TARGET_SMART *
--***********************************************************************************************
-- Получить позицию, левел вертекс, гейм вертекс обьекта.
function se_smart_terrain:get_location()
return self.position, self.m_level_vertex_id, self.m_game_vertex_id
end

-- Достигнут ли я отрядом выбравшим меня как цель.
function se_smart_terrain:am_i_reached(squad)
local squad_pos, squad_lv_id, squad_gv_id = squad:get_location()
local target_pos, target_lv_id, target_gv_id = self:get_location()
if game_graph():vertex(squad_gv_id):level_id() ~= game_graph():vertex(target_gv_id):level_id() then
return false
end
if IsMonster(alife():object(squad:commander_id())) and squad:get_script_target() == nil then
return squad_pos:distance_to_sqr(target_pos) <= 25
end
return squad.always_arrived or squad_pos:distance_to_sqr(target_pos) <= self.arrive_dist^2
end

-- Вызывается 1 раз после достижения меня отрядом выбравшим меня как цель.
function se_smart_terrain:on_after_reach(squad)
for k in squad:squad_members() do
local obj = k.object
squad.board:setup_squad_and_group(obj)
end
squad.current_target_id = self.id
end

-- Вызывается 1 раз в момент выбора меня как цели.
function se_smart_terrain:on_reach_target(squad)
-- squad.sound_manager:set_storyteller(squad:commander_id())
-- squad.sound_manager:set_story("squad_begin_attack")
squad:set_location_types(self:name())
self.board:assign_squad_to_smart(squad, self.id)
for k in squad:squad_members() do
if db.offline_objects[k.id] ~= nil then
db.offline_objects[k.id] = {}
end
end
-- self.board:exit_smart(squad, squad.smart_id)
end

-- Возвращает CALifeSmartTerrainTask на меня, вызывается из smart_terrain:task()
function se_smart_terrain:get_alife_task()
return self.smart_alife_task
end

function smart_terrain_squad_count(board_smart_squads)
local count = 0
for k,v in pairs(board_smart_squads) do
if v:get_script_target() == nil then
count = count + 1
end
end
return count
end

function se_smart_terrain:sim_available()
if self.base_on_actor_control ~= nil and self.base_on_actor_control.status ~= smart_terrain_control.NORMAL then
return false
end
return true
end

local is_squad_monster =
{
["monster_predatory_day"] = true,
["monster_predatory_night"] = true,
["monster_vegetarian"] = true,
["monster_zombied_day"] = true,
["monster_zombied_night"] = true,
["monster_special"] = true
}
function surge_stats()
local sim_obj_registry = simulation_objects.get_sim_obj_registry().objects
local sim_squads = {
["zaton"] = {},
["jupiter"] = {},
["pripyat"] = {},
["escape"] = {}
}
local sim_smarts = {
["zaton"] = {},
["jupiter"] = {},
["pripyat"] = {},
["escape"] = {}
}
for k,v in pairs(sim_obj_registry) do
if v:clsid() == clsid.smart_terrain and tonumber(v.props["surge"]) > 0 then
local level_name = alife():level_name(game_graph():vertex(v.m_game_vertex_id):level_id())
if sim_smarts[level_name] ~= nil then
table.insert(sim_smarts[level_name], v)
end
end
if v:clsid() == clsid.online_offline_group_s then
local squad_params = sim_board.simulation_activities[v.player_id]
if squad_params ~= nil then
local smart_params = squad_params.smart.surge
if smart_params ~= nil then
local level_name = alife():level_name(game_graph():vertex(v.m_game_vertex_id):level_id())
if sim_squads[level_name] ~= nil then
table.insert(sim_squads[level_name], v)
end
end
end
end
end
local function print_smarts_and_squads_by_level(level_name)
printf("LEVEL: [%s]", level_name)
local max_capacity_total = 0
for i = 1, #sim_smarts[level_name] do
local smart = sim_smarts[level_name]
max_capacity_total = max_capacity_total + smart.max_population
local squad_count = smart_terrain_squad_count(sim_board.get_sim_board().smarts[smart.id].squads)
printf("smart: [%s] max_population [%d] squad_count [%d]", smart:name(),smart.max_population, squad_count)
end
printf("TOTAL: capacity total : [%d] squads total [%d]" , max_capacity_total, #sim_squads[level_name])
end
print_smarts_and_squads_by_level("zaton")
print_smarts_and_squads_by_level("jupiter")
print_smarts_and_squads_by_level("pripyat")
print_smarts_and_squads_by_level("escape")
end
-- Мой прекондишн.
function se_smart_terrain:target_precondition(squad, need_to_dec_population)
if self.respawn_only_smart == true then
return false
end

local squad_count = smart_terrain_squad_count(self.board.smarts[self.id].squads)
if need_to_dec_population then
squad_count = squad_count - 1
end
if squad_count ~= nil and (self.max_population <= squad_count) then
--printf("smart terrain [%s] precondition returns false for squad [%s]", self:name(), squad:name())
-- if tonumber(self.props["surge"]) > 0 and xr_conditions.surge_started() then
-- printf("SURGE_SMART_STATS : smart [%s]\n max_population = %d \ squad_count = %d", self:name(), self.max_population, squad_count)
-- end
return false
end

local squad_params = sim_board.simulation_activities[squad.player_id]
if squad_params == nil or squad_params.smart == nil then
--printf("smart terrain [%s] precondition returns false for squad [%s]", self:name(), squad:name())
return false
end

if tonumber(self.props["resource"] )> 0 then
local smart_params = squad_params.smart.resource
if smart_params ~= nil and smart_params.prec(squad, self) then
return true
end
end
if tonumber(self.props["base"] )> 0 then
local smart_params = squad_params.smart.base
if smart_params ~= nil and smart_params.prec(squad, self) then
return true
end
end
if tonumber(self.props["lair"] )> 0 then
local smart_params = squad_params.smart.lair
if smart_params ~= nil and smart_params.prec(squad, self) then
return true
end
end
if tonumber(self.props["territory"] )> 0 then
local smart_params = squad_params.smart.territory
if smart_params ~= nil and smart_params.prec(squad, self) then
return true
end
end
if tonumber(self.props["surge"] )> 0 then
local smart_params = squad_params.smart.surge
if smart_params ~= nil and smart_params.prec(squad, self) then
return true
end
end
--printf("smart terrain [%s] precondition returns false for squad [%s]", self:name(), squad:name())
return false


--[[
local squad_count = smart_terrain_squad_count(self.board.smarts[self.id].squads)
if squad_count ~= nil and (self.max_population <= squad_count) then return false end


if squad.player_id == "stalker" and in_time_interval(9,19) and tonumber(self.props["resource"] )> 0 then
return true
end
--if squad.player_id ~= "monster_predatory" and squad.player_id ~= "monster_vegetarian" then

if not is_squad_monster[squad.player_id] then
if tonumber(self.props["base"]) > 0 and in_time_interval(20,8) then
return true
end
if tonumber(self.props["base"] ) > 0 and xr_conditions.surge_started() then
return true
end
else
if tonumber(self.props["lair"] ) > 0 and xr_conditions.surge_started() then
return true
end
if tonumber(self.props["lair"] ) > 0 and in_time_interval(7,20) then
return true
end
end
return false
]]
end

-- Посчитать мой приоритет для отряда.
function se_smart_terrain:evaluate_prior(squad)
return simulation_objects.evaluate_prior(self, squad)
end

-- Респаун симуляции.

function se_smart_terrain:check_respawn_params(respawn_params)
--printf("CHECK RESPAWN PARAMS %s", self:name())
self.respawn_params = {}
self.already_spawned = {}
self.respawn_point = true
if not self.ini:section_exist(respawn_params) then
abort("Wrong smatr_terrain respawn_params section [%s](there is no section)", respawn_params)
end
local n = self.ini:line_count(respawn_params)
if n == 0 then
abort("Wrong smatr_terrain respawn_params section [%s](empty params)", respawn_params)
end
for j=0,n-1 do
local result, prop_name, prop_condlist = self.ini:r_line(respawn_params,j,"","")
if not self.ini:section_exist(prop_name) then
abort("Wrong smatr_terrain respawn_params section [%s] prop [%s](there is no section)", respawn_params, prop_name)
end
local spawn_squads = utils.cfg_get_string(self.ini, prop_name, "spawn_squads", self, false, "", nil)
local spawn_num = utils.cfg_get_string(self.ini, prop_name, "spawn_num", self, false, "", nil)
if spawn_squads == nil then
abort("Wrong smatr_terrain respawn_params section [%s] prop [%s] line [spawn_squads](there is no line)", respawn_params, prop_name)
elseif spawn_num == nil then
abort("Wrong smatr_terrain respawn_params section [%s] prop [%s] line [spawn_num](there is no line)", respawn_params, prop_name)
end
spawn_squads = utils.parse_names(spawn_squads)
spawn_num = xr_logic.parse_condlist(nil, prop_name, "spawn_num", spawn_num)
self.respawn_params[prop_name] = {}
self.already_spawned[prop_name] = {}
self.respawn_params[prop_name].squads = spawn_squads
self.respawn_params[prop_name].num = spawn_num
self.already_spawned[prop_name].num = 0
end
end

function se_smart_terrain:call_respawn()
local available_sects = {}
printf("respawn called from smart_terrain [%s]", self:name())
for k,v in pairs(self.respawn_params) do
if tonumber(xr_logic.pick_section_from_condlist(db.actor, nil,v.num)) > self.already_spawned[k].num then
table.insert(available_sects,k)
end
end
if #available_sects > 0 then
local sect_to_spawn = available_sects[math.random(1,#available_sects)]
local sect_to_spawn_params = self.respawn_params[sect_to_spawn]
local squad = sect_to_spawn_params.squads[math.random(1,#sect_to_spawn_params.squads)]
squad = self.board:create_squad(self, squad)
squad.respawn_point_id = self.id
squad.respawn_point_prop_section = sect_to_spawn
self.board:enter_smart(squad, self.id)
for m in squad:squad_members() do
self.board:setup_squad_and_group(m.object)
end
self.already_spawned[sect_to_spawn].num = self.already_spawned[sect_to_spawn].num + 1
end
end

function se_smart_terrain:try_respawn()
--printf("TRY RESPAWN %s", self:name())
local curr_time = game.get_game_time()
if self.last_respawn_update == nil or curr_time:diffSec(self.last_respawn_update) > RESPAWN_IDLE then
self.last_respawn_update = curr_time

if self.sim_avail ~= nil and xr_logic.pick_section_from_condlist(db.actor or alife():actor(), self, self.sim_avail) ~= "true" then return end

local squad_count = smart_terrain_squad_count(self.board.smarts[self.id].squads)
if self.max_population <= squad_count then printf("%s cannot respawn due to squad_count %s of %s", self:name(), self.max_population, squad_count) return end

local dist_to_actor = alife():actor().position:distance_to_sqr(self.position)
if dist_to_actor < RESPAWN_RADIUS^2 then printf("%s cannot respawn due to distance", self:name()) return end

self:call_respawn()
end
end

 

--------------------------------------------------------------------------------
-- Surge manager class ---------------------------------------------------------
-- Made by Peacemaker ----------------------------------------------------------
-- 05.03.07 --------------------------------------------------------------------
--------------------------------------------------------------------------------
local surge_manager = nil

local surge_shock_pp_eff = 1
local earthquake_cam_eff = 2
local sleep_cam_eff = 3
local sleep_fade_pp_eff = 4

local START_MIN_SURGE_TIME = 2*60*60
local START_MAX_SURGE_TIME = 4*60*60
local MIN_SURGE_TIME = 12*60*60
local MAX_SURGE_TIME = 24*60*60
local prev_sec = 0

local immuned_to_surge_squads = {
["monster_predatory_day"] = true,
["monster_predatory_night"] = true,
["monster_vegetarian"] = true,
["monster_zombied_day"] = true,
["monster_zombied_night"] = true,
["monster_special"] = true,
["monster"] = true,
["zombied"] = true
}


class "CSurgeManager"
function CSurgeManager:__init()
end

function CSurgeManager:initialize()
self.ini = ini_file("misc\\surge_manager.ltx")

self.levels_respawn = {zaton = false, jupiter = false, pripyat = false, escape = false}

self.started = false
self.finished = true
self.time_forwarded = false
self.skip_message = false

self.task_given = false
self.effector_set = false
self.second_message_given = false
self.ui_disabled = false
self.blowout_sound = false

self.surge_time = 190
self.inited_time = game.CTime()
self.last_surge_time = game.get_game_time()
self._delta = math.random(START_MIN_SURGE_TIME, START_MAX_SURGE_TIME) -- global minutes, время между выбросами

self.count = 0
self.covers = {}

self.condlist = {}
self.survive = {}

local ini = self.ini
local cond_string = "true"
if(ini:line_exist("settings", "condlist")) then
cond_string = ini:r_string("settings", "condlist")
end
self.condlist = xr_logic.parse_condlist(nil, "surge_manager", "condlist", cond_string)

cond_string = "false"
if(ini:line_exist("settings", "survive")) then
cond_string = ini:r_string("settings", "survive")
end
self.survive = xr_logic.parse_condlist(nil, "surge_manager", "survive_condlist", cond_string)

self:init_surge_covers()

self.surge_message = ""
self.surge_task_sect = ""
self.loaded = false
end

function CSurgeManager:init_surge_covers()
local ini = self.ini
for i = 0, ini:line_count("list")-1 do
temp1, id, temp2 = ini:r_line("list", i, "", "")
local zone = db.zone_by_name[id]
if zone ~= nil then
self.count = self.count + 1
self.covers[self.count] = zone
if(ini:line_exist(id, "condlist")) then
self.covers[self.count].condlist = {}
self.covers[self.count].condlist = xr_logic.parse_condlist(npc, id, "condlist", ini:r_string(id, "condlist"))
end
end
end
end

function CSurgeManager:get_nearest_cover()
if(self.loaded) then
self:init_surge_covers()
end
local hides = {}
utils.copy_table(hides, self.covers)
if(self.count>0) then
for k,v in pairs(hides) do
if (v.condlist) then
local sect = xr_logic.pick_section_from_condlist(db.actor, nil, v.condlist)
if(sect~="true" and sect~=nil) then
table.remove(hides, k)
end
end
end
local nearest_cover_id = hides[1]:id()
local nearest_cover_dist = hides[1]:position():distance_to(db.actor:position())
for k,v in pairs(hides) do
if db.storage[v:id()].object:inside(db.actor:position()) then
return v:id()
end
local dist = v:position():distance_to(db.actor:position())
if(dist if(v.condlist) then
local sect = xr_logic.pick_section_from_condlist(db.actor, nil, v.condlist)
if(sect=="true") then
nearest_cover_id = v:id()
nearest_cover_dist = dist
end
else
nearest_cover_id = v:id()
nearest_cover_dist = dist
end
end
end
if(nearest_cover_id==hides[1]:id()) then
if(hides[1].condlist) then
local sect = xr_logic.pick_section_from_condlist(db.actor, nil, hides[1].condlist)
if(sect~="true" and sect~=nil) then
return nil
end
end
end
return nearest_cover_id
else
return nil
end
end

function CSurgeManager:update()
if(device().precache_frame > 1) then
return
end
if not(self.started) then
local g_time = game.get_game_time()
if(self.time_forwarded) then
log("--->delta="..tostring(self._delta))
log("--->diffSec="..tostring(g_time:diffSec(self.last_surge_time)))
local diff = math.abs(self._delta - g_time:diffSec(self.last_surge_time))
log("--->diff="..tostring(diff))
if(diff<3600) then
self._delta = 3*3600+g_time:diffSec(self.last_surge_time)
end
self.time_forwarded = false
end
if(g_time:diffSec(self.last_surge_time) < self._delta) then
return
end
if(xr_logic.pick_section_from_condlist(get_story_object("actor"), nil, self.condlist) ~= "true") then
return
end
if not(self:get_nearest_cover()) then
return
end
self:start()
return
end
-------------------------------------------------------------------- update here
local diff_sec = math.ceil(game.get_game_time():diffSec(self.inited_time)/level.get_time_factor())
if(prev_sec~=diff_sec) then
prev_sec = diff_sec
log("------>diff_sec="..tostring(diff_sec))
local cover = self:get_nearest_cover()
if(cover==nil and self.count==0) then
self:init_surge_covers()
return
end
local level_name = level.name()
if(level_name=="labx8" or level_name=="jupiter_underground") then
printf("Surge stopped because of level!")
self:end_surge()
return
end
if(diff_sec>=self.surge_time) then
if(level) then
if(level.name()=="zaton") then
xr_sound.set_sound_play(db.actor:id(), "zat_a2_stalker_barmen_after_surge")
elseif(level.name()=="jupiter") then
xr_sound.set_sound_play(db.actor:id(), "jup_a6_stalker_medik_after_surge")
elseif not has_alife_info("pri_b305_fifth_cam_end") then
xr_sound.set_sound_play(db.actor:id(), "pri_a17_kovalsky_after_surge")
end
end
self:end_surge()
else
if(self.loaded) then
if(self.blowout_sound)then
xr_sound.play_sound_looped(db.actor:id(), "blowout_rumble")
end
if(self.effector_set) then
level.add_pp_effector("surge_shock.ppe", surge_shock_pp_eff, true)
end
if(self.second_message_given) then
xr_sound.play_sound_looped(db.actor:id(), "surge_earthquake_sound_looped")
level.add_cam_effector("camera_effects\\earthquake.anm", earthquake_cam_eff, true, "")
end
self.loaded = false
end
self:launch_rockets()
if(self.effector_set) then
level.set_pp_effector_factor(surge_shock_pp_eff, diff_sec/90, 0.1)
end
if(self.blowout_sound) then
xr_sound.set_volume_sound_looped(db.actor:id(), "blowout_rumble", diff_sec/180)
end
if(diff_sec>=140 and not(self.ui_disabled) and (cover==nil or not(db.storage[cover].object:inside(db.actor:position())))) then
local att = 1-(185-diff_sec)/(185-140)
att = att*att*att*0.3
local h = hit()
h.type = hit.telepatic
h.power = att
h.impulse = 0.0
h.direction = vector():set(0,0,1)
h.draftsman = db.actor
if(xr_logic.pick_section_from_condlist(get_story_object("actor"), nil, self.survive)=="true") then
if(db.actor.health<=h.power) then
h.power = db.actor.health - 0.05
if(h.power<0) then
h.power = 0
end
end
end
db.actor:hit(h)
end
if(diff_sec>=185) and not(self.ui_disabled) then
self:kill_all_unhided()
self.ui_disabled = true
elseif(diff_sec>=140) and not(self.second_message_given) then
if(level) then
if(level.name()=="zaton") then
xr_sound.set_sound_play(db.actor:id(), "zat_a2_stalker_barmen_surge_phase_2")
elseif(level.name()=="jupiter") then
xr_sound.set_sound_play(db.actor:id(), "jup_a6_stalker_medik_phase_2")
elseif not has_alife_info("pri_b305_fifth_cam_end") then
xr_sound.set_sound_play(db.actor:id(), "pri_a17_kovalsky_surge_phase_2")
end
end
xr_sound.play_sound_looped(db.actor:id(), "surge_earthquake_sound_looped")
level.add_cam_effector("camera_effects\\earthquake.anm", earthquake_cam_eff, true, "")
self.second_message_given = true
elseif(diff_sec>=100) and not(self.effector_set) then
level.add_pp_effector("surge_shock.ppe", surge_shock_pp_eff, true)
-- level.set_pp_effector_factor(surge_shock_pp_eff, 0, 10)
self.effector_set = true
elseif(diff_sec>=35) and not(self.blowout_sound)then
xr_sound.set_sound_play(db.actor:id(), "blowout_begin")
xr_sound.play_sound_looped(db.actor:id(), "blowout_rumble")
xr_sound.set_volume_sound_looped(db.actor:id(), "blowout_rumble", 0.25)
self.blowout_sound = true
elseif(diff_sec>=0) and not(self.task_given)then
if(level) then
if(level.name()=="zaton") then
xr_sound.set_sound_play(db.actor:id(), "zat_a2_stalker_barmen_surge_phase_1")
elseif(level.name()=="jupiter") then
xr_sound.set_sound_play(db.actor:id(), "jup_a6_stalker_medik_phase_1")
elseif not has_alife_info("pri_b305_fifth_cam_end") then
xr_sound.set_sound_play(db.actor:id(), "pri_a17_kovalsky_surge_phase_1")
end
end
level.set_weather_fx("fx_surge_day_3")
self:give_surge_hide_task()
self.task_given = true
end
end
end
end

function CSurgeManager:start(manual)
local Y, M, D, h, m, s, ms = 0, 0, 0, 0, 0, 0, 0
Y, M, D, h, m, s, ms = self.last_surge_time:get(Y, M, D, h, m, s, ms)
if(manual) then
self.inited_time = game.get_game_time()
else
self.inited_time:set(Y, M, D, h, m, s + self._delta, ms)
end

diff_sec = math.ceil(game.get_game_time():diffSec(self.inited_time)/level.get_time_factor())
log("--->start diff_sec="..tostring(diff_sec))
local level_name = level.name()
if(level_name=="labx8" or level_name=="jupiter_underground") then
printf("Surge skipped because of level!")
self.skip_message = true
self:skip_surge()
return
end
if(diff_sec+6>self.surge_time)then
printf("Surge skipped while time forwarding!")
self:skip_surge()
else
self.started = true
self.finished = false
-- autosave
if not has_alife_info("pri_b305_fifth_cam_end") or has_alife_info("pri_a28_actor_in_zone_stay") then
xr_effects.scenario_autosave(nil,nil,{"st_save_uni_surge_start"})
end
end
end

function CSurgeManager:skip_surge()
local Y, M, D, h, m, s, ms = 0, 0, 0, 0, 0, 0, 0
Y, M, D, h, m, s, ms = self.inited_time:get(Y, M, D, h, m, s, ms)
self.last_surge_time:set(Y, M, D, h, m, s + self.surge_time, ms)

self.started = false
self.finished = true
self.levels_respawn = {zaton = true, jupiter = true, pripyat = true, escape = true}
self._delta = math.random(MIN_SURGE_TIME, MAX_SURGE_TIME)
self.surge_message = ""
self.surge_task_sect = ""
self.task_given = false

self.effector_set = false
self.second_message_given = false
self.ui_disabled = false
self.blowout_sound = false
prev_sec = 0

self:respawn_artefacts_and_replace_anomaly_zone()
xr_statistic.inc_surges_counter()
if (not self.skip_message) then
news_manager.send_tip(db.actor, "st_surge_while_asleep", nil, "recent_surge", nil, nil)
self.skip_message = true
end
end

function CSurgeManager:end_surge(manual)
self.started = false
self.finished = true
self.levels_respawn = {zaton = true, jupiter = true, pripyat = true, escape = true}
self.last_surge_time = game.get_game_time()
self._delta = math.random(MIN_SURGE_TIME, MAX_SURGE_TIME)
self.surge_message = ""
self.surge_task_sect = ""
self.task_given = false

if(self.effector_set) then
xr_sound.stop_sound_looped(db.actor:id(), "blowout_rumble")
end
if(self.second_message_given) then
xr_sound.stop_sound_looped(db.actor:id(), "surge_earthquake_sound_looped")
end
level.remove_pp_effector(surge_shock_pp_eff)
level.remove_cam_effector(earthquake_cam_eff)

if(manual or (self.time_forwarded and level_weathers.get_weather_manager().weather_fx)) then
level.stop_weather_fx()
-- level_weathers.get_weather_manager():select_weather(true)
level_weathers.get_weather_manager():forced_weather_change()
end

self.effector_set = false
self.second_message_given = false
self.ui_disabled = false
self.blowout_sound = false
prev_sec = 0

for k,v in pairs(db.signal_light) do
v:stop_light()
v:stop()
end

if self.loaded then
self:kill_all_unhided()
end

self:respawn_artefacts_and_replace_anomaly_zone()
xr_statistic.inc_surges_counter()
end

function CSurgeManager:respawn_artefacts_and_replace_anomaly_zone()
local lvl_nm = level.name()
if(self.levels_respawn[lvl_nm]) then
self.levels_respawn[lvl_nm] = false
end
local anomalies = db.anomaly_by_name
for k,v in pairs(anomalies) do
v:respawn_artefacts_and_replace_anomaly_zone()
--printf("respawn artefacts in anomal zone [%s]", tostring(k))
end
pda.change_anomalies_names()
end

function CSurgeManager:give_surge_hide_task()
if(self.surge_message~="empty") then
local mess = ""
if(self.surge_message=="") then
local time = 0
mess = game.translate_string("hide_from_surge_message")
else
mess = game.translate_string(self.surge_message)
end
end
if(self.surge_task_sect~="empty") then
if(self.surge_task_sect=="") then
task_manager.get_task_manager():give_task("hide_from_surge")
else
task_manager.get_task_manager():give_task(self.surge_task_sect)
end
end
end

function get_squad_members(squad_id)
local npcs_tbl = {}
local squad = alife():object(squad_id)
if(squad) then
for obj in squad:squad_members() do
npcs_tbl[obj.id] = true
end
end
return npcs_tbl
end

function check_squad_level(squad_id)
local squad = alife():object(squad_id)
if(squad) then
local squad_level = alife():level_name(game_graph():vertex(squad.m_game_vertex_id):level_id())
if(squad_level==level.name()) then
return true
end
end
return false -- can't delete squad on other level
end

function check_squad_community_and_story_id(squad_id)
local squad = alife():object(squad_id)
if(squad) then
if(immuned_to_surge_squads[squad.player_id]) then
return false -- can't delete squad immune to surge
end
if(get_object_story_id(squad.id)) then
return false -- can't delete squad with story id
end
end
return true
end

function check_squad_community(squad_id)
local squad = alife():object(squad_id)
if(squad) then
if(immuned_to_surge_squads[squad.player_id]) then
return false -- can't delete squad immune to surge
end
end
return true
end

function check_squad_smart_props(squad_id)
local squad = alife():object(squad_id)
if(squad) then
local board = sim_board.get_sim_board()
if(board and squad.smart_id and board.smarts[squad.smart_id]) then
local smart = board.smarts[squad.smart_id].smrt
if(tonumber(smart.props["surge"])<=0) then
return true
end
end
end
return false -- can't delete squad in his smart if squad is in cover
end

function CSurgeManager:kill_all_unhided()
local h = hit()
h.type = hit.fire_wound
h.power = 0.9
h.impulse = 0.0
h.direction = vector():set(0,0,1)
h.draftsman = db.actor
for k,v in pairs(bind_crow.crow_storage) do
local obj = alife():object(v)
if obj then
local crow = level.object_by_id(obj.id)
if(crow and crow:alive()) then
crow:hit(h)
end
end
end

local board = sim_board.get_sim_board()
for k,v in pairs(board.squads) do
local squad = v
if(check_squad_level(squad.id)) then
if(check_squad_community_and_story_id(squad.id)) then
local squad_npcs = get_squad_members(squad.id)
for kk,vv in pairs(squad_npcs) do
local obj = alife():object(kk)
if(obj and not(get_object_story_id(obj.id))) then
if(check_squad_smart_props(squad.id)) then
printf("Releasing npc [%s] from squad [%s] because of surge!",obj:name(), squad:name())
local cl_obj = level.object_by_id(obj.id)
if cl_obj ~= nil then
cl_obj:kill(cl_obj)
else
obj:kill()
end
else
local release = true
for i = 1,#self.covers do
local sr = self.covers
if(sr and sr:inside(obj.position)) then
release = false
end
end
if(release) then
printf("Releasing npc [%s] from squad [%s] because of surge!",obj:name(), squad:name())
local cl_obj = level.object_by_id(obj.id)
if cl_obj ~= nil then
cl_obj:kill(cl_obj)
else
obj:kill()
end
end
end
end
end
end
end
end

local cover = self:get_nearest_cover()
if(db.actor and db.actor:alive()) then
if not(cover and db.storage[cover] and db.storage[cover].object:inside(db.actor:position())) then
if has_alife_info("anabiotic_in_process") then
local counter_name = "actor_marked_by_zone_cnt"
local cnt_value = xr_logic.pstor_retrieve(db.actor, counter_name, 0)
xr_logic.pstor_store(db.actor, counter_name, cnt_value + 1)
end
--[[
local hud = get_hud()
hud:HideActorMenu()
hud:HidePdaMenu()
db.actor:stop_talk()
level.disable_input()
level.hide_indicators_safe()
db.actor:hide_weapon()
]]--
xr_effects.disable_ui_only(db.actor, nil)
if(xr_logic.pick_section_from_condlist(get_story_object("actor"), nil, self.survive)~="true") then
self:kill_all_unhided_after_actor_death()
db.actor:kill(db.actor)
return
else
level.add_cam_effector("camera_effects\\surge_02.anm", sleep_cam_eff, false, "surge_manager.surge_callback")
level.add_pp_effector("surge_fade.ppe", sleep_fade_pp_eff, false)
db.actor.health = db.actor.health-0.05
end
end
end
end

function CSurgeManager:kill_all_unhided_after_actor_death()
local board = sim_board.get_sim_board()
for k,v in pairs(board.squads) do
local squad = v
if(check_squad_level(squad.id)) then
if(check_squad_community(squad.id)) then
local squad_npcs = get_squad_members(squad.id)
for kk,vv in pairs(squad_npcs) do
local obj = alife():object(kk)
if obj then
local release = true
for i = 1,#self.covers do
local sr = self.covers
if(sr and sr:inside(obj.position)) then
release = false
end
end
if(release) then
printf("Releasing npc [%s] from squad [%s] after actors death because of surge!",obj:name(), squad:name())
local cl_obj = level.object_by_id(obj.id)
if cl_obj ~= nil then
cl_obj:kill(cl_obj)
else
obj:kill()
end
end
end
end
end
end
end
end

function surge_callback()
level.add_cam_effector("camera_effects\\surge_01.anm", sleep_cam_eff, false, "surge_manager.surge_callback2")
-- level.stop_weather_fx()
-- level.change_game_time(0,0,15)
-- level_weathers.get_weather_manager():forced_weather_change()
end

function surge_callback2()
xr_effects.enable_ui(db.actor, nil)
--[[
level.enable_input()
level.show_indicators()
db.actor:restore_weapon()
]]--
end

function CSurgeManager:launch_rockets()
for k,v in pairs(db.signal_light) do
if not(v:is_flying()) then
v:launch()
end
end
end

function CSurgeManager:save(packet)
set_save_marker(packet, "save", false, "SurgeHide")
packet:w_bool(self.finished)
packet:w_bool(self.started)
utils.w_CTime(packet, self.last_surge_time)
if(self.started) then
utils.w_CTime(packet, self.inited_time)

packet:w_bool(self.levels_respawn.zaton)
packet:w_bool(self.levels_respawn.jupiter)
packet:w_bool(self.levels_respawn.pripyat)
packet:w_bool(self.levels_respawn.escape)

packet:w_bool(self.task_given)
packet:w_bool(self.effector_set)
packet:w_bool(self.second_message_given)
packet:w_bool(self.ui_disabled)
packet:w_bool(self.blowout_sound)

packet:w_stringZ(self.surge_message)
packet:w_stringZ(self.surge_task_sect)
end
packet:w_u32(self._delta)
set_save_marker(packet, "save", true, "SurgeHide")
end

function CSurgeManager:load(packet)
set_save_marker(packet, "load", false, "SurgeHide")
self:initialize()
self.finished = packet:r_bool()
self.started = packet:r_bool()
self.last_surge_time = utils.r_CTime(packet)
if(self.started) then
self.inited_time = utils.r_CTime(packet)

self.levels_respawn.zaton = packet:r_bool()
self.levels_respawn.jupiter = packet:r_bool()
self.levels_respawn.pripyat = packet:r_bool()
self.levels_respawn.escape = packet:r_bool()

self.task_given = packet:r_bool()
self.effector_set = packet:r_bool()
self.second_message_given = packet:r_bool()
self.ui_disabled = packet:r_bool()
self.blowout_sound = packet:r_bool()

self.surge_message = packet:r_stringZ()
self.surge_task_sect = packet:r_stringZ()
end
self._delta = packet:r_u32()
self.loaded = true
set_save_marker(packet, "load", true, "SurgeHide")
end
--------------------------------------------------------------------------------
function get_surge_manager()
if surge_manager == nil then
surge_manager = CSurgeManager()
end
return surge_manager
end

function start_surge(p)
local m = get_surge_manager()
if(m:get_nearest_cover()) then
m:start(true)
else
printf("Error: Surge covers are not set! Can't manually start")
end
end

function actor_in_cover()
local m = get_surge_manager()
local cover_id = m:get_nearest_cover()
if (cover_id ~= nil) and (db.storage[cover_id].object:inside(db.actor:position())) then
return true
else
return false
end
end

function stop_surge()
local m = get_surge_manager()
if(m.started) then
m:end_surge(true)
end
end

function get_task_descr()
local descr = ""
if(actor_in_cover()) then
descr = game.translate_string("hide_from_surge_descr_2_a")
else
descr = game.translate_string("hide_from_surge_descr_1_a")
end
return descr
end

function get_task_target()
local m = get_surge_manager()
if(actor_in_cover()) then
return nil
end
return m:get_nearest_cover()
end

function set_surge_message(mess)
local m = get_surge_manager()
m.surge_message = mess
end

function set_surge_task(task)
local m = get_surge_manager()
m.surge_task_sect = task
end

function is_started()
local m = get_surge_manager()
return m.started
end

function is_killing_all()
local m = get_surge_manager()
if(m.started and m.ui_disabled) then
return true
end
return false
end

function is_finished()
local m = get_surge_manager()
return m.finished == true
end

function resurrect_skip_message()
local m = get_surge_manager()
m.skip_message = false
end

function sound_started()
local m = get_surge_manager()
return m.started and m.blowout_sound
end

)>

Все.Это все скрипты которые я трогал.

 

Такие огромные тексты врядли кто прокручивать станет. Лучше заливай файлики на обменник и выкладывай ссылкой.

Для менее огромных кодов, используй тег "код", дабы сохранять форматирование.

И пиши без "хз".

Cyclone

Изменено пользователем Cyclone

Поделиться этим сообщением


Ссылка на сообщение

А может из-за того,что у меня на локации несколько обычных смартов?Просто я их в заранее поставил но в конфигах не трогал.



Пойду уберу их.Просто мне в прошлый раз сказали,что пустой смарт не влияет и вылета не должно быть.

Поделиться этим сообщением


Ссылка на сообщение

Нет,они просто пустые.



Убрал смарты лишние,те которые пустые были,вообщем все работает!Они идут по свободным смартам:))
Спасибо огромное,что хоть подсказку дали про пустышки!

Поделиться этим сообщением


Ссылка на сообщение
  • Недавно просматривали   0 пользователей

    Ни один зарегистрированный пользователь не просматривает эту страницу.

AMK-Team.ru

×
×
  • Создать...