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

1058 lines
39 KiB
Text
Raw Blame History

This file contains ambiguous Unicode characters

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

--'******************************************************
--'* Боевой отряд группировки. (Скриптовая версия)
--'* Наследован от обычного боевого отряда.
--'* Отличия:
--'* - Детерминированные состав отряда
--'* - Возможность жестко указать активное действие
--'******************************************************
local squad_behaviour_ini = ini_file("misc\\squad_behaviours.ltx")
local locations_ini = ini_file("misc\\smart_terrain_masks.ltx")
--function printf()
--end
class "sim_squad_scripted" (cse_alife_online_offline_group)
--***********************************************************************************************
--* INITIALIZATION *
--***********************************************************************************************
function sim_squad_scripted:__init(section) super (section)
--' смарт, в котором сейчас находится отряд.
self.smart_id = nil
self.board = sim_board.get_sim_board()
self.current_spot_id = nil --' ID объекта на который сейчас установлен мапспот.
--' Текущее действие
self.current_action = nil
self.current_target_id = nil
self.assigned_target_id = nil
--' Саундменеджер отряда
self.sound_manager = sound_manager.get_sound_manager("squad_"..self:section_name() )
self.settings_id = self:section_name()
self:init_squad()
self:set_squad_behaviour()
end
--' Инициализация
function sim_squad_scripted:init_squad()
self.player_id = utils.cfg_get_string(sim_board.squad_ltx, self.settings_id, "faction", self, true, "")
self.action_condlist = xr_logic.parse_condlist(self, "assign_action", "target_smart", utils.cfg_get_string(sim_board.squad_ltx, self.settings_id, "target_smart", self, false, "", ""))
self.death_condlist = xr_logic.parse_condlist(self, "death_condlist", "on_death", utils.cfg_get_string(sim_board.squad_ltx, self.settings_id, "on_death", self, false, "", ""))
self.invulnerability = xr_logic.parse_condlist(self, "invulnerability", "invulnerability", utils.cfg_get_string(sim_board.squad_ltx, self.settings_id, "invulnerability", self, false, "", ""))
self.relationship = self.relationship or utils.cfg_get_string(sim_board.squad_ltx, self.settings_id, "relationship", self, false, "", nil)
self.sympathy = utils.cfg_get_number(sim_board.squad_ltx, self.settings_id, "sympathy", self, false, nil)
self.show_spot = xr_logic.parse_condlist(self, "show_spot", "show_spot", utils.cfg_get_string(sim_board.squad_ltx, self.settings_id, "show_spot", self, false, "", "false"))
self.always_walk = utils.cfg_get_bool(sim_board.squad_ltx, self.settings_id, "always_walk", self, false)
self.always_arrived = utils.cfg_get_bool(sim_board.squad_ltx, self.settings_id, "always_arrived", self, false)
self:set_location_types_section("stalker_terrain")
self:set_squad_sympathy()
end
-- Инициализация отряда на загрузке
function sim_squad_scripted:init_squad_on_load()
-- Прописываем сквад в нужные смарты
printf("Init squad %s on load", self.id)
self:set_squad_sympathy()
self.board:assign_squad_to_smart(self, self.smart_id)
if self.smart_id ~= nil then
self.board:enter_smart(self, self.smart_id, true)
end
self.need_to_reset_location_masks = true
end
-- Вычитываем настройки поведения сквада.
function sim_squad_scripted:set_squad_behaviour()
self.behaviour = {}
local behaviour_section = utils.cfg_get_string(sim_board.squad_ltx, self.settings_id, "behaviour", self, false, "", self.player_id)
if not squad_behaviour_ini:section_exist(behaviour_section) then
abort("There is no section ["..behaviour_section.."] in 'misc\\squad_behaviours.ltx'")
end
local n = squad_behaviour_ini:line_count(behaviour_section)
for j=0,n-1 do
local result, prop_name, prop_condlist = squad_behaviour_ini:r_line(behaviour_section,j,"","")
self.behaviour[prop_name] = prop_condlist
end
end
--***********************************************************************************************
--* SCRIPT_TARGET_SELECTION *
--***********************************************************************************************
--' Возвращает скриптовую цель.
function sim_squad_scripted:get_script_target()
local new_target = xr_logic.pick_section_from_condlist(db.actor, self, self.action_condlist)
if new_target == nil then
-- printf("[%s] get_script_target nil_condlist", self.id)
return nil
end
if new_target ~= self.last_target then
self.last_target = new_target
--' Парсим новые задачи для отряда
self.parsed_targets = utils.parse_names(new_target)
if self.need_free_update ~= true then
self.next_target = 1
else
self.need_free_update = false
end
end
if self.parsed_targets[self.next_target] == nil then
self.next_target = 1
end
local nt = self:pick_next_target()
if nt == "nil" then
return nil
elseif nt == "loop" then
self.next_target = 1
nt = self:pick_next_target()
end
local point = self.board.smarts_by_names[nt]
if point == nil then
abort("Incorrect next point [%s] for squad [%s]", tostring(nt), tostring(self.id))
end
return point.id
end
--' Выбор следующей цели
function sim_squad_scripted:pick_next_target()
--printf("Picking next target for [%s] = %s by %s", self:section_name(), tostring(self.parsed_targets[self.next_target]), self.next_target)
return self.parsed_targets[self.next_target]
end
--' Проверка пришел ли отряд в очередной поинт
function sim_squad_scripted:check_squad_come_to_point()
--printf("[%s] check squad point", self.id)
if self.parsed_targets == nil then
return true
end
--' Если мы уже дошли до точки.
local next_target = self.next_target or 0
if self.assigned_target_id ~= nil and self.smart_id == self.assigned_target_id then
if self.parsed_targets[next_target+1] ~= nil then
self.next_target = next_target+1
return true
end
end
return false
end
--' Проверка пришел ли отряд в очередной поинт
function sim_squad_scripted:update_current_action()
local is_finished = self.current_action:update(false)
if not is_finished then
return false
end
return true
end
function sim_squad_scripted:update()
cse_alife_online_offline_group.update (self)
self:refresh()
-- Апдейт доступности для симуляции.
simulation_objects.get_sim_obj_registry():update_avaliability(self)
self:check_invulnerability()
local script_target = self:get_script_target()
--printf("[%s] SCRIPTED UPDATE. Target[%s]", self.id, tostring(script_target))
if script_target == nil then
self:generic_update()
if self.need_to_reset_location_masks then
self:set_location_types()
self.need_to_reset_location_masks = false
end
return
end
self.sound_manager:update()
local need_to_find_new_action = false
if self.assigned_target_id ~= nil and self.assigned_target_id == script_target then
if self.current_action ~= nil then
if self.current_action.name == "stay_point" then
--' Если экшн stay_point. Проверяем пришли ли до экшна.
if self:check_squad_come_to_point() then
--' Пришли в точку, перевыбрали цель
need_to_find_new_action = true
--printf("[%s] SCRIPTED need_to_find_new_action %s", self.id, tostring(need_to_find_new_action))
else
--' Не пришли в точку, апдейтимся дальше
need_to_find_new_action = self:update_current_action()
--printf("[%s] SCRIPTED need_to_find_new_action %s", self.id, tostring(need_to_find_new_action))
end
else
--' Если экшн attack_point. Проверяем пришли ли после экшна.
if self:update_current_action() then
self:check_squad_come_to_point()
need_to_find_new_action = true
--printf("[%s] SCRIPTED need_to_find_new_action %s", self.id, tostring(need_to_find_new_action))
end
end
else
--' Проверяем пришли ли
self:check_squad_come_to_point()
need_to_find_new_action = true
--printf("[%s] SCRIPTED need_to_find_new_action %s", self.id, tostring(need_to_find_new_action))
end
else
if self.current_action == nil then
need_to_find_new_action = true
--printf("[%s] SCRIPTED need_to_find_new_action %s", self.id, tostring(need_to_find_new_action))
else
if self.current_action.major == true then
if self:update_current_action() then
self:check_squad_come_to_point()
need_to_find_new_action = true
--printf("[%s] SCRIPTED need_to_find_new_action %s", self.id, tostring(need_to_find_new_action))
end
else
need_to_find_new_action = true
--printf("[%s] SCRIPTED need_to_find_new_action %s", self.id, tostring(need_to_find_new_action))
end
end
end
if need_to_find_new_action == true then
self.assigned_target_id = script_target
if self.current_action ~= nil then
self.current_action:finalize()
self.current_action = nil
end
--' Если у нас нет текущей цели - просим выдать нам задание.
self:get_next_action(false)
end
if self.need_to_reset_location_masks then
self:set_location_types()
self.need_to_reset_location_masks = false
end
end
--***********************************************************************************************
--* SIMULATION_TARGET_SELECTION *
--***********************************************************************************************
function sim_squad_scripted:clear_assigned_target()
self.assigned_target_id = nil
end
function sim_squad_scripted:assigned_target_avaliable()
local target_obj = self.assigned_target_id and alife():object(self.assigned_target_id)
if target_obj == nil then
return false
end
-- В данном случае нужно проверять попьюлейшн минус один, т.к. я уже состою в смарте.
return target_obj:target_precondition(self, true)
end
local function can_help_actor(squad)
if empty(xr_combat_ignore.fighting_with_actor_npcs) then
return false
end
if game_graph():vertex(squad.m_game_vertex_id):level_id() ~= game_graph():vertex(alife():actor().m_game_vertex_id):level_id() then
return false
end
if has_alife_info("sim_duty_help_harder") and squad:get_squad_community() == "duty" then
return true
elseif has_alife_info("sim_freedom_help_harder") and squad:get_squad_community() == "freedom" then
return true
elseif has_alife_info("sim_stalker_help_harder") and squad:get_squad_community() == "stalker" then
return true
end
return false
end
local function get_help_target_id(squad)
if not can_help_actor(squad) then
return nil
end
for k,v in pairs (xr_combat_ignore.fighting_with_actor_npcs) do
local enemy_squad_id = alife():object(k).group_id
if enemy_squad_id ~= nil then
local target_squad = alife():object(enemy_squad_id)
if target_squad and squad.position:distance_to_sqr(target_squad.position) < 150^2 and
game_relations.is_factions_enemies(squad:get_squad_community(), target_squad:get_squad_community()) then
return enemy_squad_id
end
end
end
return nil
end
--' Апдейт отряда для выбора симуляционных целей.
function sim_squad_scripted:generic_update()
--printf("Squad[%s] UPDATE", self.id)
--' Если у нас есть незавершенное действие - ждем пока оно завершится.
self.sound_manager:update()
self:refresh()
local help_target_id = get_help_target_id(self)
if help_target_id then
self.assigned_target_id = help_target_id
self.current_action = nil
self:get_next_action(false)
return
end
if self.assigned_target_id and alife():object(self.assigned_target_id) and alife():object(self.assigned_target_id):clsid() ~= clsid.online_offline_group_s then
local squad_target = self.board:get_squad_target(self)
if squad_target:clsid() == clsid.online_offline_group_s then
self.assigned_target_id = squad_target.id
self.current_action = nil
self:get_next_action(true)
return
end
end
if self.current_action ~= nil and self:assigned_target_avaliable() then
--printf("[%s] CURRENT ACTION [%s]", self.id, self.current_action.name)
local is_finished = self.current_action:update(true)
if is_finished then
self.current_action:finalize()
if self.current_action.name == "stay_point" or self.assigned_target_id == nil then
self.assigned_target_id = self.board:get_squad_target(self).id
end
self.current_action = nil
else
return
end
else
self.current_action = nil
self.current_target_id = nil
self.assigned_target_id = self.board:get_squad_target(self).id
end
self:get_next_action(true)
end
--' Получение следующего экшна на выполнение
function sim_squad_scripted:get_next_action(under_simulation)
local squad_target = alife():object(self.assigned_target_id)
--printf("assigned_target = [%s]", tostring(self.assigned_target_id))
if self.current_target_id == nil then
if squad_target == nil or squad_target:am_i_reached(self) then
if squad_target ~= nil then
squad_target:on_reach_target(self)
squad_target:on_after_reach(self)
end
self.current_action = sim_squad_actions.stay_on_target(self)
self.current_target_id = self.assigned_target_id
self.current_action:make(under_simulation)
return
end
end
if (self.assigned_target_id == self.current_target_id) or self.assigned_target_id == nil then
self.current_action = sim_squad_actions.stay_on_target(self)
self.current_target_id = self.assigned_target_id
self.current_action:make(under_simulation)
else
self.current_action = sim_squad_actions.reach_target(self)
self.current_action:make(under_simulation)
end
end
--***********************************************************************************************
--* MEMBERS_CONTROL *
--***********************************************************************************************
--' Удаление персонажей отряда
function sim_squad_scripted:remove_squad()
local squad_npcs = {}
for k in self:squad_members() do
squad_npcs[k.id] = true
end
--
for j,v in pairs(squad_npcs) do
local obj = alife():object(j)
if obj ~= nil then
self:unregister_member(j)
alife():release(obj, true)
end
end
self:hide()
-- alife():release(self, true)
end
--' Удаление конкретного персонажа отряда
function sim_squad_scripted:remove_npc(npc_id)
local npc = alife():object(npc_id)
self:on_npc_death(npc)
--printf("releasing object ["..npc:name().."]")
alife():release(npc, true)
end
--' Убийство НПС
function sim_squad_scripted:on_npc_death(npc)
printf("Squad %s. Killed member %s", tostring(self.id), npc.id)
self.sound_manager:unregister_npc(npc.id)
self:unregister_member(npc.id)
if self:npc_count() == 0 then
printf("REMOVING DEAD SQUAD %s", tostring(self.id))
if self.current_action ~= nil then
self.current_action:finalize()
self.current_action = nil
end
if self.death_condlist ~= nil then
xr_logic.pick_section_from_condlist(db.actor, self, self.death_condlist)
end
self.board:remove_squad(self)
return
end
self:refresh()
end
function sim_squad_scripted:assign_squad_member_to_smart(member_id, smart, old_smart_id)
local obj = alife():object(member_id)
if obj ~= nil then
--printf(" npc [%s] smart [%s]", obj:name(), tostring(obj.m_smart_terrain_id))
if obj.m_smart_terrain_id == self.smart_id then
return
end
if obj.m_smart_terrain_id ~= 65535 and old_smart_id ~= nil and (obj.m_smart_terrain_id == old_smart_id) and self.board.smarts[old_smart_id] ~= nil then
self.board.smarts[old_smart_id].smrt:unregister_npc(obj)
end
if smart ~= nil then
smart:register_npc(obj)
end
end
end
--' Назначение смарта
function sim_squad_scripted:assign_smart(smart)
local old_smart = self.smart_id
self.smart_id = smart and smart.id
--printf(" squad %s assign smart. old[%s] new[%s]", self.id, tostring(old_smart), tostring(self.smart_id))
--callstack()
for k in self:squad_members() do
self:assign_squad_member_to_smart(k.id, smart, old_smart)
end
end
function sim_squad_scripted:check_invulnerability()
if self.squad_online ~= true then
return
end
local invulnerability = xr_logic.pick_section_from_condlist(db.actor, self, self.invulnerability) == "true"
for k in self:squad_members() do
local npc_st = db.storage[k.id]
if npc_st ~= nil then
local npc = npc_st.object
if npc:invulnerable() ~= invulnerabilty and utils.cfg_get_string(npc_st.ini, npc_st.active_section, "invulnerable", npc, false, "", nil) == nil then
-- printf("RESET INVULNERABILITY. npc[%s] = [%s]", npc:name(), tostring(invulnerability))
npc:invulnerable(invulnerability)
end
end
end
end
function sim_squad_scripted:set_location_types_section (section)
-- printf("set_location_types_section[%s] for [%s]", tostring(section), tostring(self:name()))
if locations_ini:section_exist(section) then
local result, id, value = locations_ini:r_line(section,0,"","")
self:add_location_type(id)
end
end
function sim_squad_scripted:set_location_types(new_smart_name)
local default_location = "stalker_terrain"
printf("set_location_types for squad [%s]", self:name())
self:clear_location_types()
--[[for k,v in pairs(simulation_objects.get_sim_obj_registry().objects) do
if alife():object(k):clsid() == clsid.smart_terrain then
self:set_location_types_section(alife():object(k):name())
end
end]]--
if alife():object(self.assigned_target_id):clsid() == clsid.smart_terrain then
self:set_location_types_section(default_location)
local old_smart_name = self.smart_id and alife():object(self.smart_id) and alife():object(self.smart_id):name()
--printf("old_smart_name = [%s]!", tostring(old_smart_name))
if old_smart_name then
self:set_location_types_section(old_smart_name)
end
--printf("new_smart_name = [%s]!", tostring(new_smart_name))
if new_smart_name then
self:set_location_types_section(new_smart_name)
end
else
--printf("target is squad or actor setting [squad_terrain]!")
self:set_location_types_section("squad_terrain")
for k,v in pairs(simulation_objects.get_sim_obj_registry().objects) do
if alife():object(k):clsid() == clsid.smart_terrain then
local props_base = alife():object(k).props and alife():object(k).props["base"]
if props_base and tonumber(props_base) == 0 then
self:set_location_types_section(alife():object(k):name())
end
end
end
end
end
function sim_squad_scripted:add_squad_member(spawn_section, spawn_position, lv_id, gv_id, sect_number)
local spawn_sections_ltx = system_ini()
local custom_data = utils.cfg_get_string(spawn_sections_ltx, spawn_section, "custom_data", self, false, "", "default_custom_data.ltx")
if custom_data ~= "default_custom_data.ltx" then
printf("INCORRECT npc_spawn_section USED [%s]. You cannot use npc with custom_data in squads", spawn_section)
end
local position = spawn_position
local obj = alife():create(spawn_section,
position,
lv_id,
gv_id)
self:register_member(obj.id)
self.sound_manager:register_npc(obj.id)
if simulation_objects.is_on_the_same_level(obj, alife():actor()) and position:distance_to_sqr(alife():actor().position) <= alife():switch_distance()^2 then
db.spawned_vertex_by_id[obj.id] = lv_id
end
return obj.id
end
--' Создание чуваков в отряд
function sim_squad_scripted:create_npc(spawn_smart)
local ini = system_ini()
local spawn_sections = utils.parse_names(utils.cfg_get_string(ini, self.settings_id, "npc", self, false, "", ""))
local spawn_point = utils.cfg_get_string(ini, self.settings_id, "spawn_point", self, false, "","self") or
utils.cfg_get_string(spawn_smart.ini, smart_terrain.SMART_TERRAIN_SECT, "spawn_point", self, false,"","self")
spawn_point = xr_logic.parse_condlist(self, "spawn_point", "spawn_point", spawn_point)
spawn_point = xr_logic.pick_section_from_condlist(db.actor, self, spawn_point)
--print_table(debug.getinfo(1))
printf("SPAWN SMART %s", spawn_smart:name())
--' Высчитываем базовую позицию спауна
local base_spawn_position = spawn_smart.position
local base_lvi = spawn_smart.m_level_vertex_id
local base_gvi = spawn_smart.m_game_vertex_id
if spawn_point ~= nil then
if spawn_point == "self" then
base_spawn_position = spawn_smart.position
base_lvi = spawn_smart.m_level_vertex_id
base_gvi = spawn_smart.m_game_vertex_id
else
base_spawn_position = patrol(spawn_point):point(0)
base_lvi = patrol(spawn_point):level_vertex_id(0)
base_gvi = patrol(spawn_point):game_vertex_id(0)
end
elseif spawn_smart.spawn_point ~= nil then
base_spawn_position = patrol(spawn_smart.spawn_point):point(0)
base_lvi = patrol(spawn_smart.spawn_point):level_vertex_id(0)
base_gvi = patrol(spawn_smart.spawn_point):game_vertex_id(0)
end
if #spawn_sections ~= 0 then
for k,v in pairs(spawn_sections) do
self:add_squad_member(v, base_spawn_position, base_lvi, base_gvi,k)
end
end
-- подспаун рэндомных чуваков...
local random_spawn = utils.cfg_get_string(ini, self.settings_id, "npc_random", self, false, "",nil)
if random_spawn ~= nil then
random_spawn = utils.parse_names(random_spawn)
local count_min, count_max = utils.r_2nums( ini, self.settings_id, "npc_in_squad", 1, 2 )
if count_min > count_max then
abort("min_count can't be greater then max_count [%s]!!!!!", self.settings_id)
end
local random_count = math.random(count_min, count_max)
for i = 1,random_count do
local random_id = math.random(1, #random_spawn)
self:add_squad_member(random_spawn[random_id], base_spawn_position, base_lvi, base_gvi,random_id)
end
elseif #spawn_sections == 0 then
abort("You are trying to spawn an empty squad [%s]!!!", self.settings_id)
end
self.smart_id = spawn_smart.id
self:refresh()
end
function sim_squad_scripted:set_squad_sympathy(sympathy)
local symp = sympathy or self.sympathy
if(symp~=nil) then
for k in self:squad_members() do
local npc = db.storage[k.id] and db.storage[k.id].object
if(npc) then
game_relations.set_npc_sympathy(npc, symp)
else
if(db.goodwill.sympathy==nil) then
db.goodwill.sympathy = {}
end
db.goodwill.sympathy[k.id] = symp
end
end
end
end
local function set_relation(npc1, npc2, new_relation)
local goodwill = 0
if(new_relation=="enemy") then
goodwill = -1000
elseif(new_relation=="friend") then
goodwill = 1000
end
if npc1 and npc2 then
npc1:force_set_goodwill(goodwill, npc2.id)
else
abort("Npc not set in goodwill function!!!")
end
end
function sim_squad_scripted:set_squad_relation(relation)
local rel = relation or self.relationship
if(rel~=nil) then
for k in self:squad_members() do
local npc = db.storage[k.id] and db.storage[k.id].object
if(npc) then
game_relations.set_npcs_relation(npc, db.actor, rel)
else
set_relation(alife():object(k.id), alife():actor(),rel)
end
end
end
end
local function reset_animation(npc)
local state_mgr = db.storage[npc:id()].state_mgr
if state_mgr == nil then
return
end
local planner = npc:motivation_action_manager()
state_mgr.animation:set_state(nil, true)
state_mgr.animation:set_control()
state_mgr.animstate:set_state(nil, true)
state_mgr.animstate:set_control()
state_mgr:set_state("idle", nil, nil, nil, {fast_set = true})
-- planner:update()
-- planner:update()
-- planner:update()
state_mgr:update()
state_mgr:update()
state_mgr:update()
state_mgr:update()
state_mgr:update()
state_mgr:update()
state_mgr:update()
npc:set_body_state(move.standing)
npc:set_mental_state(anim.free)
end
function sim_squad_scripted:set_squad_position(position)
if self.online == false then
self:force_change_position(position)
end
for k in self:squad_members() do
local cl_object = level.object_by_id(k.id)
db.offline_objects[k.id].level_vertex_id = level.vertex_id(position)
if cl_object then
reset_animation(cl_object)
printf("teleporting npc [%s]", k.id)
cl_object:set_npc_position(position)
printf("end of teleporting npc [%s]", k.id)
else
k.object.position = position
end
end
end
function sim_squad_scripted:has_detector()
for k in self:squad_members() do
if alife():object(k.id) and alife():object(k.id):has_detector() then
return true
end
end
return false
end
function sim_squad_scripted:get_squad_community()
local squad_community = squad_community_by_behaviour[self.player_id]
if squad_community == nil then
abort("squad community is 'nil' for player_id [%s]", self.player_id)
end
return squad_community
end
--***********************************************************************************************
--* SAVE\LOAD *
--***********************************************************************************************
function sim_squad_scripted:STATE_Write(packet)
cse_alife_online_offline_group.STATE_Write (self, packet)
set_save_marker(packet, "save", false, "sim_squad_scripted")
packet:w_stringZ(tostring(self.current_target_id))
packet:w_stringZ(tostring(self.respawn_point_id))
packet:w_stringZ(tostring(self.respawn_point_prop_section))
packet:w_stringZ(tostring(self.smart_id))
set_save_marker(packet, "save", true, "sim_squad_scripted")
end
function sim_squad_scripted:STATE_Read(packet, size)
cse_alife_online_offline_group.STATE_Read (self, packet, size)
set_save_marker(packet, "load", false, "sim_squad_scripted")
self.current_target_id = packet:r_stringZ()
if self.current_target_id == "nil" then
self.current_target_id = nil
else
self.current_target_id = tonumber(self.current_target_id)
end
self.respawn_point_id = packet:r_stringZ()
if self.respawn_point_id == "nil" then
self.respawn_point_id = nil
else
self.respawn_point_id = tonumber(self.respawn_point_id)
end
self.respawn_point_prop_section = packet:r_stringZ()
if self.respawn_point_prop_section == "nil" then
self.respawn_point_prop_section = nil
end
self.smart_id = packet:r_stringZ()
if self.smart_id == "nil" then
self.smart_id = nil
else
self.smart_id = tonumber(self.smart_id)
end
self:init_squad_on_load()
set_save_marker(packet, "load", true, "sim_squad_scripted")
end
--***********************************************************************************************
--* SERVER_OBJECT *
--***********************************************************************************************
function sim_squad_scripted:on_register()
cse_alife_online_offline_group.on_register( self )
self.board.squads[self.id] = self
-- Проверяем кастомдату обьекта на наличие стори айди.
story_objects.check_spawn_ini_for_story_id(self)
simulation_objects.get_sim_obj_registry():register(self)
end
function sim_squad_scripted:on_unregister()
--' Отрегистрация в таскменеджере
unregister_story_object_by_id(self.id)
--' Удалить отряд
self.board.squads[self.id] = nil
self.board:assign_squad_to_smart(self, nil)
cse_alife_online_offline_group.on_unregister( self )
simulation_objects.get_sim_obj_registry():unregister(self)
if self.respawn_point_id ~= nil then
local smart = alife():object(self.respawn_point_id)
-- затычка для дестроя левела(смарты дестроятся раньше сквадов)
if smart == nil then
return
end
smart.already_spawned[self.respawn_point_prop_section].num = smart.already_spawned[self.respawn_point_prop_section].num - 1
end
end
function sim_squad_scripted:can_switch_offline()
return cse_alife_online_offline_group.can_switch_offline(self)
end
function sim_squad_scripted:can_switch_online()
return cse_alife_online_offline_group.can_switch_online(self)
end
--***********************************************************************************************
--* MAP LOCATION *
--***********************************************************************************************
--[[
monster_predatory_day
monster_predatory_night
monster_vegetarian
monster_zombied_day
monster_zombied_night
monster_special
]]--
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,
["monster"] = true
}
function sim_squad_scripted:refresh()
if(self:commander_id()==nil) then
self:hide()
return
end
self:show()
end
function sim_squad_scripted:hide()
if(self.current_spot_id==nil) or (self.spot_section==nil) then
return
end
level.map_remove_object_spot(self.current_spot_id, self.spot_section)
self.current_spot_id = nil
self.spot_section = nil
end
--' Показать отряд на карте
function sim_squad_scripted:show()
if self.show_disabled then
self:hide()
return
end
if(level.map_has_object_spot(self:commander_id(), "ui_pda2_trader_location")~=0) or
(level.map_has_object_spot(self:commander_id(), "ui_pda2_mechanic_location")~=0) or
(level.map_has_object_spot(self:commander_id(), "ui_pda2_scout_location")~=0) or
(level.map_has_object_spot(self:commander_id(), "ui_pda2_quest_npc_location")~=0) or
(level.map_has_object_spot(self:commander_id(), "ui_pda2_medic_location")~=0) then
self.show_disabled = true
return
end
if self.current_spot_id ~= self:commander_id() then
self:hide()
self.current_spot_id = self:commander_id()
self:show()
return
end
local spot = ""
if dev_debug then -- IX-Ray: Fixed PDA squad rendering in Lua devmode
if not(is_squad_monster[self.player_id]) then
local relation = game_relations.get_squad_goodwill_to_actor_by_id(self.id)
if(relation=="friends") then
spot = "alife_presentation_squad_friend_debug"
elseif(relation=="neutral") then
spot = "alife_presentation_squad_neutral_debug"
else
spot = "alife_presentation_squad_enemy_debug"
end
else
spot = "alife_presentation_squad_monster_debug"
end
else
if not(is_squad_monster[self.player_id]) then
local relation = game_relations.get_squad_relation_to_actor_by_id(self.id)
if(relation=="friends") then
spot = "alife_presentation_squad_friend"
elseif(relation=="neutral") then
spot = "alife_presentation_squad_neutral"
end
end
end
if(spot~="") then
if spot == self.spot_section then
level.map_change_spot_hint(self.current_spot_id, self.spot_section, self:get_squad_props())
return
end
if self.spot_section == nil then
level.map_add_object_spot(self.current_spot_id, spot, self:get_squad_props())
else
level.map_remove_object_spot(self.current_spot_id, self.spot_section)
level.map_add_object_spot(self.current_spot_id, spot, self:get_squad_props())
end
self.spot_section = spot
elseif(self.spot_section~=nil) then
level.map_remove_object_spot(self.current_spot_id, self.spot_section)
self.spot_section = nil
end
end
function sim_squad_scripted:get_squad_props()
if dev_debug then
local t = "["..tostring(self:name()).."]\\n"..
"current_target = ["..tostring(self.current_target_id and alife():object(self.current_target_id) and alife():object(self.current_target_id):name()).."]\\n"..
"assigned_target = ["..tostring(self.assigned_target_id and alife():object(self.assigned_target_id) and alife():object(self.assigned_target_id):name()).."]\\n"
if self.current_action and self.current_action.name == "stay_point" then
t = t.."stay_on_point = ["..tostring(self.current_action.idle_time - game.get_game_time():diffSec(self.current_action.start_time)).."]"
end
return t
else
return ""
end
end
--***********************************************************************************************
--* SIMULATION_TARGET_SQUAD *
--***********************************************************************************************
-- Получить позицию, левел вертекс, гейм вертекс обьекта.
function sim_squad_scripted:get_location()
return self.position, self.m_level_vertex_id, self.m_game_vertex_id
end
function sim_squad_scripted:get_current_task()
if self.assigned_target_id ~= nil and alife():object(self.assigned_target_id) ~= nil then
local smart_terrain = alife():object(self.assigned_target_id)
if smart_terrain.arriving_npc ~= nil and smart_terrain.arriving_npc[self:commander_id()] == nil
and smart_terrain.npc_info and smart_terrain.npc_info[self:commander_id()]
and smart_terrain.npc_info[self:commander_id()].job_id and smart_terrain.job_data[smart_terrain.npc_info[self:commander_id()].job_id] then
return smart_terrain.job_data[smart_terrain.npc_info[self:commander_id()].job_id].alife_task
end
return alife():object(self.assigned_target_id):get_alife_task()
end
return self:get_alife_task()
end
-- Достигнут ли я отрядом выбравшим меня как цель.
function sim_squad_scripted:am_i_reached(squad)
return self:npc_count() == 0
end
-- Вызывается 1 раз после достижения меня отрядом выбравшим меня как цель.
function sim_squad_scripted:on_after_reach(squad)
end
-- Вызывается 1 раз в момент выбора меня как цели.
function sim_squad_scripted:on_reach_target(squad)
squad:set_location_types()
for k in squad:squad_members() do
if db.offline_objects[k.id] ~= nil then
db.offline_objects[k.id] = {}
end
end
self.board:assign_squad_to_smart(squad, nil)
end
-- Возвращает CALifeSmartTerrainTask на меня, вызывается из smart_terrain:task()
function sim_squad_scripted:get_alife_task()
--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))
return CALifeSmartTerrainTask(self.m_game_vertex_id, self.m_level_vertex_id)
end
local smarts_by_no_assault_zones = {
["zat_a2_sr_no_assault"] = "zat_stalker_base_smart",
["jup_a6_sr_no_assault"] = "jup_a6",
["jup_b41_sr_no_assault"] = "jup_b41"
}
function sim_squad_scripted:sim_available()
for k,v in pairs (smarts_by_no_assault_zones) do
local zone = db.zone_by_name[k]
if zone and zone:inside(self.position) then
local smart = sim_board.get_sim_board():get_smart_by_name(v)
if smart and smart.base_on_actor_control ~= nil and smart.base_on_actor_control.status ~= smart_terrain_control.ALARM then
return false
end
end
end
if self.smart_id == nil then
return true
end
-- Удалять из регистра сим обьектов если мы идем на базу.
local props_base = alife():object(self.smart_id).props and alife():object(self.smart_id).props["base"]
if props_base and tonumber(props_base) > 0 then
return false
end
local smart = alife():object(self.smart_id)
if smart.base_on_actor_control ~= nil and smart.base_on_actor_control.status ~= smart_terrain_control.NORMAL then
if db.zone_by_name[smart.base_on_actor_control.noweap_zone] == nil or not db.zone_by_name[smart.base_on_actor_control.noweap_zone]:inside(self.position) then
return false
end
end
return true
end
-- Мой прекондишн.
function sim_squad_scripted:target_precondition(squad)
local squad_params = sim_board.simulation_activities[squad.player_id]
if squad_params == nil or squad_params.squad == nil then
return false
end
local self_params = squad_params.squad[self.player_id]
if self_params == nil or self_params.prec(squad, self) == false then
return false
end
return true
--[[
if squad.player_id == "dolg" and
(is_squad_monster[self.player_id] or self.player_id == "freedom") and
in_time_interval(8,22) then
return true
end
if squad.player_id == "bandit" and self.player_id == "stalker" then
return true
end
if squad.player_id == "freedom" and self.player_id == "dolg" and in_time_interval(8,22) then
return true
end
-- Травоядные днем атакуют проходящих мимо сталкеров.(плоть, кабан)
if squad.player_id == "monster_vegetarian" and in_time_interval(8,22) and not is_squad_monster[self.player_id] then
return true
end
-- Хищники днем атакуют сталкеров и травоядных(собаки, псевдособаки, пси собаки)
if squad.player_id == "monster_predatory_day" and
in_time_interval(8,22) and
(self.player_id == "monster_vegetarian" or not is_squad_monster[self.player_id]) then
return true
end
-- Хищники ночью атакуют сталкеров и травоядных(тушканы,кровосос, химера)
if squad.player_id == "monster_predatory_night" and
in_time_interval( 22 , 8) and
(self.player_id == "monster_vegetarian" or not is_squad_monster[self.player_id]) then
return true
end
-- Зомбиобразные днем атакуют проходящих мимо сталкеров.
if squad.player_id == "monster_zombied_day" and
in_time_interval(8,22) and
(not is_squad_monster[self.player_id]) then
return true
end
-- Зомбиобразные днем атакуют проходящих мимо сталкеров.
if squad.player_id == "monster_zombied_night" and
in_time_interval(22,8) and
(not is_squad_monster[self.player_id]) then
return true
end
-- Особенные днем атакуют проходящих мимо сталкеров.
if squad.player_id == "monster_special" and
in_time_interval(8,22) and
(not is_squad_monster[self.player_id]) then
return true
end
return false
]]
end
-- Посчитать мой приоритет для отряда.
function sim_squad_scripted:evaluate_prior(squad)
return simulation_objects.evaluate_prior(self, squad)
end