198 lines
7.1 KiB
Text
198 lines
7.1 KiB
Text
--[[------------------------------------------------------------------------------------------------------------------
|
||
Игнорирование врагов
|
||
Чугай Александр
|
||
--------------------------------------------------------------------------------------------------------------------]]
|
||
local ignored_smart = {
|
||
zat_stalker_base_smart = true,
|
||
jup_b41 = true,
|
||
jup_a6 = true,
|
||
pri_a16 = true
|
||
}
|
||
|
||
fighting_with_actor_npcs = {
|
||
}
|
||
|
||
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 is_enemy(obj, enemy, st, not_check_sim)
|
||
if not obj:alive() then
|
||
return false
|
||
end
|
||
|
||
if obj:critically_wounded() then
|
||
return true
|
||
end
|
||
|
||
if st.enabled == false then
|
||
return true
|
||
end
|
||
|
||
local overrides = st.overrides
|
||
local obj_id = obj:id()
|
||
local storage = db.storage[obj_id]
|
||
if storage == nil then
|
||
return true
|
||
end
|
||
storage.enemy_id = enemy:id()
|
||
|
||
--' Отсеиваем по зоне
|
||
local active_sector = storage.active_sector
|
||
if active_sector ~= nil then
|
||
if sr_danger.check_danger_position(enemy:position(), active_sector) == false then
|
||
-- obj:enable_memory_object( enemy, false )
|
||
return false
|
||
end
|
||
end
|
||
|
||
-- Проверка на зоны комбат игнора возле баз:
|
||
-- игнорировать если:
|
||
-- враг не актер.
|
||
-- сталкер находится в зоне.
|
||
-- смарт в котором находится сталкер не в состоянии тревоги.
|
||
if db.actor and enemy and enemy:id() ~= db.actor:id() then
|
||
for k,v in pairs (smarts_by_no_assault_zones) do
|
||
local zone = db.zone_by_name[k]
|
||
if zone and (utils.npc_in_zone(obj, zone) or utils.npc_in_zone(enemy, zone)) 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
|
||
end
|
||
|
||
local se_enemy = alife():object(enemy:id())
|
||
if se_enemy ~= nil and se_enemy.m_smart_terrain_id ~= nil and se_enemy.m_smart_terrain_id ~= 65535 then
|
||
local enemy_smart = alife():object(se_enemy.m_smart_terrain_id)
|
||
local smart_name = enemy_smart:name()
|
||
if ignored_smart[smart_name] == true then
|
||
-- obj:enable_memory_object( enemy, false )
|
||
return false
|
||
end
|
||
end
|
||
--printf("checking combat_ignore for stalker[%s] enemy name [%s] in section[%s]",obj:name(), enemy:name(),storage.active_section)
|
||
--' Если есть оверрайды, то работаем по ним.
|
||
if overrides and
|
||
overrides.combat_ignore
|
||
then
|
||
local ret_value = xr_logic.pick_section_from_condlist( enemy, obj, overrides.combat_ignore.condlist )
|
||
if ret_value == "true" then
|
||
--printf("pl:Disabling_memory_object[1] for stalker[%s] enemy name [%s] in section[%s]",obj:name(), enemy:name(),storage.active_section)
|
||
-- obj:enable_memory_object( enemy, false )
|
||
return false
|
||
end
|
||
return true
|
||
end
|
||
return true
|
||
end
|
||
----------------------------------------------------------------------------------------------------------------------
|
||
|
||
class "action_process_enemy"
|
||
|
||
function action_process_enemy:__init( obj, storage )
|
||
self.object = obj
|
||
self.st = storage
|
||
end
|
||
|
||
function action_process_enemy:enemy_callback( obj, enemy )
|
||
--' local obj_pos = self.object:position()
|
||
--' local ene_pos = enemy:position()
|
||
--' printf("FOUND ENEMY [%s](%s,%s,%s) -> [%s](%s,%s,%s)", self.object:name(), obj_pos.x, obj_pos.y, obj_pos.z,
|
||
--' enemy:name(), ene_pos.x, ene_pos.y, ene_pos.z)
|
||
if enemy:id() == db.actor:id() then
|
||
fighting_with_actor_npcs[obj:id()] = true
|
||
end
|
||
|
||
local is_obj_enemy = is_enemy( obj, enemy, self.st, false )
|
||
if is_obj_enemy == true then
|
||
local se_obj = alife():object(obj:id())
|
||
if se_obj and se_obj.m_smart_terrain_id ~= 65535 then
|
||
local smart_obj = alife():object(se_obj.m_smart_terrain_id)
|
||
smart_obj:set_alarm()
|
||
|
||
if db.actor and enemy and enemy:id() == db.actor:id() and smart_obj.base_on_actor_control ~= nil then
|
||
-- Fix start for detecting attacking of the base even when attacked npc is not near the base
|
||
local base_pos = db.zone_by_name[smart_obj.base_on_actor_control.noweap_zone]:position()
|
||
local distance = obj:position():distance_to(base_pos)
|
||
if distance < 100 then
|
||
smart_obj.base_on_actor_control:actor_attack()
|
||
end
|
||
-- Fix end for detecting attacking of the base even when attacked npc is not near the base
|
||
end
|
||
end
|
||
local se_enemy = alife():object(enemy:id())
|
||
if se_obj and se_enemy then
|
||
local sim_obj_registry = simulation_objects.get_sim_obj_registry()
|
||
if se_obj.group_id ~= 65535 and sim_obj_registry.objects[se_obj.group_id] ~= nil and
|
||
se_enemy.group_id ~= 65535 and sim_obj_registry.objects[se_enemy.group_id] == nil and
|
||
se_obj.position:distance_to_sqr(se_enemy.position) > 900 then
|
||
return false
|
||
end
|
||
end
|
||
end
|
||
|
||
return is_obj_enemy
|
||
end
|
||
|
||
function action_process_enemy:hit_callback(obj, amount, local_direction, who, bone_index)
|
||
if who == nil then
|
||
return
|
||
end
|
||
|
||
-- printf("_bp: action_process_enemy: hit_callback(): obj='%s'", obj:name())
|
||
if amount == 0 then
|
||
-- Кто-то стрельнул в воздух
|
||
return
|
||
end
|
||
|
||
if who:id() == db.actor:id() then
|
||
local overrides = self.st.overrides
|
||
if not overrides or not overrides.combat_ignore_keep_when_attacked then
|
||
--printf("_bp: action_process_enemy: hit_callback(): obj='%s': SCHEME DISABLED", obj:name())
|
||
self.st.enabled = false
|
||
end
|
||
end
|
||
end
|
||
|
||
----------------------------------------------------------------------------------------------------------------------
|
||
-- binder
|
||
----------------------------------------------------------------------------------------------------------------------
|
||
function add_to_binder( npc, ini, scheme, section, storage )
|
||
local new_action = this.action_process_enemy( npc, storage )
|
||
storage.action = new_action
|
||
end
|
||
|
||
function set_combat_ignore_checker( npc, ini, scheme)
|
||
local st = xr_logic.assign_storage_and_bind( npc, ini, scheme )
|
||
end
|
||
|
||
function reset_combat_ignore_checker(npc, scheme, st, section)
|
||
local storage = st.combat_ignore
|
||
|
||
npc:set_enemy_callback( storage.action.enemy_callback, storage.action )
|
||
|
||
-- Подписываемся на hit callback-и:
|
||
xr_logic.subscribe_action_for_events( npc, storage, storage.action )
|
||
|
||
storage.overrides = xr_logic.generic_scheme_overrides(npc)
|
||
|
||
storage.enabled = true
|
||
end
|
||
|
||
|
||
|
||
function disable_scheme( npc, scheme )
|
||
npc:set_enemy_callback()
|
||
|
||
-- Отписываемся от hit callback. Это делать обязательно, потому что иначе при переключении на другой набор
|
||
-- схем, в котором нет перехвата боя, продолжится вызываться callback в старом подписанном action-е.
|
||
local st = db.storage[npc:id()][scheme]
|
||
if st then
|
||
xr_logic.unsubscribe_action_from_events(npc, st, st.action)
|
||
end
|
||
end
|