483 lines
16 KiB
Plaintext
483 lines
16 KiB
Plaintext
--[[------------------------------------------------------------------------------------------------
|
|
Çîíû ïñè-èçëó÷åíèÿ. Îòûãðûâàþò ïîñòïðîöåññ è ôàíòîìîâ ïî íàñòðîéêàì èç custom_data
|
|
--------------------------------------------------------------------------------------------------]]
|
|
local state_outside = 0 -- àêòåð ñíàðóæè
|
|
local state_inside = 1 -- àêòåð âíóòðè
|
|
local state_void = 2 -- íåèçâåñòíûé ñòàòóñ
|
|
|
|
psy_antenna = false
|
|
|
|
class "PsyAntenna"
|
|
function PsyAntenna:__init ()
|
|
-- ----------------------------------------------------------------------------------------
|
|
-- settings
|
|
-- ----------------------------------------------------------------------------------------
|
|
-- phantom gen
|
|
-- ----------------------------------------------------------------------------------------
|
|
self.phantom_max = 3 --10 -- max phantoms
|
|
self.phantom_spawn_probability = 0.5 -- spawn probability (0..1)
|
|
self.phantom_spawn_radius = 30.0 -- average radius 30.0m +-15m
|
|
self.phantom_spawn_height = 2.5 --3 -- average height from actor pos +-1.5m
|
|
self.phantom_fov = 45 -- øèðèíà ñåêòîðà ïåðåä ãëàçàìè àêò¸ðà, â êîòîðîì ìîãóò ðîæäàòüñÿ ôàíòîìû
|
|
-- antenna
|
|
self.hit_amplitude = 1.0 -- ðàçìåð õèòà = self.hit_amplitude*self.hit_intensity
|
|
-- ----------------------------------------------------------------------------------------
|
|
-- class variables initialize
|
|
-- ----------------------------------------------------------------------------------------
|
|
self.eff_time = 0
|
|
self.hit_time = 0
|
|
self.phantom_time = 0
|
|
self.intensity_inertion = 0.05 -- ñêîðîñòü èçìåíåíèÿ èíòåíñèâíîñòè åä/ñåêóíäó
|
|
self.hit_intensity = 0
|
|
self.sound_intensity = 0
|
|
self.sound_intensity_base = 0 -- áàçîâàÿ èíòåíñèâíîñòü. ê íåé ñòðåìèòñÿ òåêóùàÿ ñî ñêîðîñòüþ self.intensity_inertion
|
|
self.postprocess_count = 0 --'ñ÷åò÷èê çàðåãèñòðèðîâàííûõ ïîñòïðîöåññîâ
|
|
self.postprocess = {} --'êîíòåéíåð ïîñòïðîöåññîâ
|
|
|
|
-- ----------------------------------------------------------------------------------------
|
|
-- sound
|
|
-- ----------------------------------------------------------------------------------------
|
|
self.sound_initialized = false
|
|
|
|
self.sound_obj_right, self.sound_obj_left = sound_object("anomaly\\brain_scorcher_r"), sound_object("anomaly\\brain_scorcher_l")
|
|
|
|
self.sound_obj_left.volume = self.sound_intensity
|
|
self.sound_obj_right.volume = self.sound_intensity
|
|
self.snd_volume = level.get_snd_volume()
|
|
self.mute_sound_threshold = 0 --' Ïðåäåë äî êîòîðîãî ìîæíî çàíèæàòü çâóê óðîâíÿ. 0 - ìîæíî çàãëóøèòü ïîëíîñòüþ
|
|
self.max_mumble_volume = 10
|
|
|
|
self.no_static = false
|
|
self.no_mumble = false
|
|
self.hit_type = "wound"
|
|
self.hit_freq = 5000
|
|
self.global_state = state_void
|
|
end
|
|
function PsyAntenna:destroy ()
|
|
self.sound_obj_right:stop()
|
|
self.sound_obj_left:stop()
|
|
level.set_snd_volume (self.snd_volume)
|
|
local hud = get_hud()
|
|
if (hud) then
|
|
hud:enable_fake_indicators(false)
|
|
end
|
|
end
|
|
function PsyAntenna:update_psy_hit(dt)
|
|
local hud = get_hud()
|
|
if not (hud) then
|
|
return
|
|
end
|
|
|
|
local custom_static = hud:GetCustomStatic("cs_psy_danger")
|
|
if self.hit_intensity > 0.0001 then
|
|
if custom_static == nil and not self.no_static then
|
|
hud:AddCustomStatic("cs_psy_danger", true)
|
|
hud:GetCustomStatic("cs_psy_danger"):wnd():TextControl():SetTextST("st_psy_danger")
|
|
end
|
|
else
|
|
if custom_static ~= nil then
|
|
hud:RemoveCustomStatic("cs_psy_danger")
|
|
end
|
|
end
|
|
|
|
if time_global() - self.hit_time > self.hit_freq then
|
|
self.hit_time = time_global()
|
|
|
|
local power = self.hit_amplitude*self.hit_intensity
|
|
|
|
|
|
|
|
--printf("HIT: power = %s", tostring(power))
|
|
|
|
if power > 0.0001 then
|
|
|
|
local psy_hit = hit()
|
|
psy_hit.power = power
|
|
psy_hit.direction = vector():set( 0, 0, 0 )
|
|
psy_hit.impulse = 0
|
|
psy_hit.draftsman = db.actor
|
|
local hit_value = ((power <= 1) and power) or 1
|
|
if self.hit_type == "chemical" then
|
|
hud:update_fake_indicators(2, hit_value)
|
|
psy_hit.type = hit.chemical_burn
|
|
else
|
|
hud:update_fake_indicators(3, hit_value)
|
|
psy_hit.type = hit.telepatic
|
|
end
|
|
|
|
--[[
|
|
if self.last_health then
|
|
printf("actor health [%s], hit taken [%s]", tostring(db.actor.health), tostring(self.last_health-db.actor.health))
|
|
end
|
|
self.last_health = db.actor.health
|
|
]]--
|
|
|
|
db.actor:hit(psy_hit)
|
|
|
|
if db.actor.health < 0.0001 and db.actor:alive() then
|
|
db.actor:kill( db.actor )
|
|
end
|
|
end
|
|
end
|
|
end
|
|
function PsyAntenna:generate_phantoms()
|
|
if (db.actor:is_talking()) then
|
|
return
|
|
end
|
|
if self.phantom_idle == nil then
|
|
self.phantom_idle = math.random(2000,5000)
|
|
end
|
|
if time_global() - self.phantom_time > self.phantom_idle then
|
|
self.phantom_time = time_global()
|
|
self.phantom_idle = math.random(5000,10000)
|
|
if (phantom_manager:phantom_count() < self.phantom_max and (math.random(1,100)/100) < self.phantom_spawn_probability) then
|
|
local radius = self.phantom_spawn_radius * ( math.random()/2.0+0.5 )
|
|
local ang = self.phantom_fov * math.random() - self.phantom_fov * 0.5
|
|
local dir = vector_rotate_y( db.actor:direction(), ang )
|
|
|
|
--printf("spawn_phantom")
|
|
phantom_manager.spawn_phantom( db.actor:position():add( dir:mul(radius) ) )
|
|
end
|
|
end
|
|
end
|
|
function PsyAntenna:update_sound()
|
|
if not self.sound_initialized then
|
|
self.sound_obj_left:play_at_pos (db.actor, vector():set(-1, 0, 1), 0, sound_object.s2d + sound_object.looped)
|
|
self.sound_obj_right:play_at_pos (db.actor, vector():set( 1, 0, 1), 0, sound_object.s2d + sound_object.looped)
|
|
|
|
self.sound_initialized = true
|
|
end
|
|
|
|
local vol = 1 - ( self.sound_intensity ^ 3 ) * 0.9
|
|
|
|
if vol < self.mute_sound_threshold then
|
|
level.set_snd_volume( self.mute_sound_threshold )
|
|
else
|
|
level.set_snd_volume( vol )
|
|
end
|
|
|
|
self.sound_obj_left.volume = 1 / vol - 1
|
|
self.sound_obj_right.volume = 1 / vol - 1
|
|
end
|
|
function PsyAntenna:update_postprocess(pp)
|
|
if pp.intensity == 0 then
|
|
self.postprocess_count = self.postprocess_count - 1
|
|
level.remove_pp_effector(pp.idx)
|
|
return false
|
|
end
|
|
|
|
level.set_pp_effector_factor(pp.idx, pp.intensity, 0.3)
|
|
return true
|
|
end
|
|
function PsyAntenna:update(dt)
|
|
if (db.actor == nil or device().precache_frame > 1) then
|
|
return
|
|
end
|
|
|
|
self.eff_time = self.eff_time + dt
|
|
|
|
local function update_intensity(intensity_base, intensity)
|
|
local di = self.intensity_inertion * dt * 0.01
|
|
local ii = intensity_base
|
|
if math.abs(intensity_base - intensity) >= di then
|
|
if intensity_base < intensity then
|
|
ii = intensity - di
|
|
else
|
|
ii = intensity + di
|
|
end
|
|
end
|
|
|
|
if ii < 0.0 then ii = 0.0
|
|
elseif ii > 1.0 then ii = 1.0 end
|
|
return ii
|
|
end
|
|
|
|
if (self.global_state == 1) then
|
|
--self:generate_phantoms() -- IMPORTANT: disabled phantoms cause they lead to game_graph crash, probably something about them spawning outside level borders?
|
|
end
|
|
|
|
if not self.no_mumble then
|
|
self.sound_intensity = update_intensity(self.sound_intensity_base, self.sound_intensity)
|
|
self:update_sound()
|
|
end
|
|
|
|
for k,v in pairs(self.postprocess) do
|
|
v.intensity = update_intensity(v.intensity_base, v.intensity)
|
|
local exist = self:update_postprocess(v)
|
|
|
|
if exist == false then
|
|
self.postprocess[k] = nil
|
|
end
|
|
end
|
|
|
|
self:update_psy_hit(dt)
|
|
end
|
|
|
|
function PsyAntenna:save_state(m_data)
|
|
--utils_data.debug_write("PsyAntenna:save_state BEFORE")
|
|
m_data.PsyAntenna = {}
|
|
m_data.PsyAntenna.hit_intensity = self.hit_intensity
|
|
m_data.PsyAntenna.sound_intensity = self.sound_intensity
|
|
m_data.PsyAntenna.sound_intensity_base = self.sound_intensity_base
|
|
m_data.PsyAntenna.mute_sound_threshold = self.mute_sound_threshold
|
|
m_data.PsyAntenna.no_static = self.no_static
|
|
m_data.PsyAntenna.no_mumble = self.no_mumble
|
|
m_data.PsyAntenna.hit_type = self.hit_type
|
|
m_data.PsyAntenna.hit_freq = self.hit_freq
|
|
m_data.PsyAntenna.postprocess = self.postprocess
|
|
--utils_data.debug_write("PsyAntenna:save_state AFTER")
|
|
end
|
|
|
|
function PsyAntenna:load_state(m_data)
|
|
if not (m_data.PsyAntenna) then
|
|
return
|
|
end
|
|
--utils_data.debug_write("PsyAntenna:load_state BEFORE")
|
|
self.hit_intensity = m_data.PsyAntenna.hit_intensity or 0
|
|
self.sound_intensity = m_data.PsyAntenna.sound_intensity or 0
|
|
self.sound_intensity_base = m_data.PsyAntenna.sound_intensity_base or 0
|
|
self.mute_sound_threshold = m_data.PsyAntenna.mute_sound_threshold or 0
|
|
self.no_static = m_data.PsyAntenna.no_static or false
|
|
self.no_mumble = m_data.PsyAntenna.no_mumble or false
|
|
self.hit_type = m_data.PsyAntenna.hit_type or "wound"
|
|
self.hit_freq = m_data.PsyAntenna.hit_freq or 5000
|
|
self.postprocess = m_data.PsyAntenna.postprocess or 0
|
|
--utils_data.debug_write("PsyAntenna:load_state AFTER")
|
|
end
|
|
|
|
function PsyAntenna:save(p)
|
|
--printf("Psy Antenna SAVE")
|
|
set_save_marker(p, "save", false, "psy_antenna_obj")
|
|
p:w_float(self.hit_intensity)
|
|
p:w_float(self.sound_intensity)
|
|
p:w_float(self.sound_intensity_base)
|
|
p:w_float(self.mute_sound_threshold)
|
|
p:w_bool(self.no_static)
|
|
p:w_bool(self.no_mumble)
|
|
p:w_stringZ(self.hit_type)
|
|
p:w_u32(self.hit_freq)
|
|
|
|
p:w_u8(self.postprocess_count)
|
|
for k,v in pairs(self.postprocess) do
|
|
p:w_stringZ(k)
|
|
p:w_float(v.intensity)
|
|
p:w_float(v.intensity_base)
|
|
p:w_u16(v.idx)
|
|
end
|
|
set_save_marker(p, "save", true, "psy_antenna_obj")
|
|
end
|
|
function PsyAntenna:load(p)
|
|
--printf("Psy Antenna LOAD")
|
|
set_save_marker(p, "load", false, "psy_antenna_obj")
|
|
self.hit_intensity = p:r_float()
|
|
self.sound_intensity = p:r_float()
|
|
self.sound_intensity_base = p:r_float()
|
|
self.mute_sound_threshold = p:r_float()
|
|
self.no_static = p:r_bool()
|
|
self.no_mumble = p:r_bool()
|
|
self.hit_type = p:r_stringZ()
|
|
self.hit_freq = p:r_u32()
|
|
|
|
self.postprocess_count = p:r_u8()
|
|
|
|
self.postprocess = {}
|
|
for i=1, self.postprocess_count do
|
|
local k = p:r_stringZ()
|
|
local ii = p:r_float()
|
|
local ib = p:r_float()
|
|
local idx = p:r_u16()
|
|
self.postprocess[k] = {intensity_base = ib, intensity = ii, idx = idx}
|
|
level.add_pp_effector(k, idx, true)
|
|
level.set_pp_effector_factor(idx, ii)
|
|
end
|
|
set_save_marker(p, "load", true, "psy_antenna_obj")
|
|
end
|
|
|
|
----------------------------------------------------------------------------------------------------
|
|
-- ëîãè÷åñêàÿ ñõåìà äëÿ space restrictor
|
|
----------------------------------------------------------------------------------------------------
|
|
|
|
|
|
|
|
|
|
|
|
class "action_psy_antenna"
|
|
function action_psy_antenna:__init( obj, storage )
|
|
self.object = obj
|
|
self.st = storage
|
|
self.state = state_void --' åùå íå ÿñíî, â çîíå îí, èëè íåò
|
|
end
|
|
function action_psy_antenna:reset_scheme( loading )
|
|
if loading then
|
|
self.state = load_var( self.object, "inside" )
|
|
end
|
|
if self.state == state_inside then
|
|
self:zone_leave()
|
|
end
|
|
|
|
self.state = state_void
|
|
|
|
self:switch_state(db.actor)
|
|
--' end
|
|
--' printf("[psy_antenna] reset_scheme %s, inside %s", tostring(loading), tostring(self.state))
|
|
end
|
|
function action_psy_antenna:deactivate()
|
|
if self.state == state_inside then
|
|
self:zone_leave()
|
|
end
|
|
end
|
|
function action_psy_antenna:update( delta )
|
|
local actor = db.actor
|
|
|
|
if xr_logic.try_switch_to_another_section( self.object, self.st, actor ) then
|
|
return
|
|
end
|
|
self:switch_state( actor )
|
|
end
|
|
function action_psy_antenna:switch_state( actor )
|
|
if self.state ~= state_inside then
|
|
if (db.actor_inside_zones[self.object:name()]) then
|
|
--if self.object:inside( actor:position() ) then
|
|
self:zone_enter()
|
|
end
|
|
elseif (self.state == state_inside) then
|
|
if not (db.actor_inside_zones[self.object:name()]) then
|
|
--if not self.object:inside( actor:position() ) then
|
|
self:zone_leave()
|
|
end
|
|
end
|
|
end
|
|
|
|
function action_psy_antenna:zone_enter()
|
|
--printf("[psy_antenna] zone_enter")
|
|
self.state = state_inside
|
|
psy_antenna.global_state = state_inside
|
|
|
|
--âêëþ÷àåì ôåéêîâûé èíäèêàòîð õèòà.
|
|
local hud = get_hud()
|
|
if (hud) then
|
|
hud:enable_fake_indicators(true)
|
|
end
|
|
|
|
psy_antenna.sound_intensity_base = psy_antenna.sound_intensity_base + self.st.intensity
|
|
psy_antenna.mute_sound_threshold = psy_antenna.mute_sound_threshold + self.st.mute_sound_threshold
|
|
psy_antenna.hit_intensity = psy_antenna.hit_intensity + self.st.hit_intensity
|
|
psy_antenna.phantom_spawn_probability = psy_antenna.phantom_spawn_probability + self.st.phantom_prob
|
|
|
|
psy_antenna.no_static = self.st.no_static
|
|
psy_antenna.no_mumble = self.st.no_mumble
|
|
psy_antenna.hit_type = self.st.hit_type
|
|
psy_antenna.hit_freq = self.st.hit_freq
|
|
|
|
--' printf("[psy_antenna] zone_enter. hit_intensity=%s", tostring(psy_antenna.hit_intensity))
|
|
|
|
if self.st.postprocess == "nil" then
|
|
return
|
|
end
|
|
|
|
if psy_antenna.postprocess[self.st.postprocess] == nil then
|
|
psy_antenna.postprocess_count = psy_antenna.postprocess_count + 1
|
|
psy_antenna.postprocess[self.st.postprocess] = { intensity_base = 0, intensity = 0, idx = 1500+psy_antenna.postprocess_count}
|
|
level.add_pp_effector(self.st.postprocess, psy_antenna.postprocess[self.st.postprocess].idx, true)
|
|
level.set_pp_effector_factor(psy_antenna.postprocess[self.st.postprocess].idx, 0.01)
|
|
end
|
|
psy_antenna.postprocess[self.st.postprocess].intensity_base = psy_antenna.postprocess[self.st.postprocess].intensity_base + self.st.intensity
|
|
end
|
|
|
|
function action_psy_antenna:zone_leave()
|
|
--printf("[psy_antenna] zone_leave. hit_intensity=%s", tostring(psy_antenna.hit_intensity))
|
|
self.state = state_outside
|
|
psy_antenna.global_state = state_outside
|
|
|
|
--âûêëþ÷àåì ôåéêîâûé èíäèêàòîð õèòà.
|
|
local hud = get_hud()
|
|
if (hud) then
|
|
hud:enable_fake_indicators(false)
|
|
end
|
|
|
|
psy_antenna.sound_intensity_base = psy_antenna.sound_intensity_base - self.st.intensity
|
|
psy_antenna.mute_sound_threshold = psy_antenna.mute_sound_threshold - self.st.mute_sound_threshold
|
|
psy_antenna.hit_intensity = psy_antenna.hit_intensity - self.st.hit_intensity
|
|
|
|
psy_antenna.phantom_spawn_probability = psy_antenna.phantom_spawn_probability - self.st.phantom_prob
|
|
|
|
--' printf("[psy_antenna] zone_leave. hit_intensity=%s, minus=%s", tostring(psy_antenna.hit_intensity), tostring(self.st.hit_intensity))
|
|
|
|
if self.st.postprocess == "nil" then
|
|
return
|
|
end
|
|
|
|
if psy_antenna.postprocess[self.st.postprocess] ~= nil then
|
|
psy_antenna.postprocess[self.st.postprocess].intensity_base = psy_antenna.postprocess[self.st.postprocess].intensity_base - self.st.intensity
|
|
end
|
|
end
|
|
function action_psy_antenna:save()
|
|
save_var( self.object, "inside", self.state )
|
|
end
|
|
|
|
---------------------------------------------------------------------------------------------------------------------
|
|
function save( p )
|
|
if (USE_MARSHAL) then
|
|
return
|
|
end
|
|
set_save_marker(p, "save", false, "sr_psy_antenna")
|
|
if psy_antenna and psy_antenna.global_state ~= state_outside and not level_changing() then
|
|
p:w_bool( true )
|
|
|
|
psy_antenna:save( p )
|
|
else
|
|
p:w_bool( false )
|
|
end
|
|
set_save_marker(p, "save", true, "sr_psy_antenna")
|
|
end
|
|
|
|
function load(p)
|
|
if (USE_MARSHAL) then
|
|
return
|
|
end
|
|
set_save_marker(p, "load", false, "sr_psy_antenna")
|
|
local b = p:r_bool()
|
|
|
|
if b then
|
|
if psy_antenna then
|
|
abort("sr_psy_antenna.psy_antenna already exists!")
|
|
end
|
|
|
|
psy_antenna = PsyAntenna()
|
|
psy_antenna:load(p)
|
|
end
|
|
set_save_marker(p, "load", true, "sr_psy_antenna")
|
|
end
|
|
|
|
function add_to_binder(npc, ini, scheme, section, storage)
|
|
--printf("DEBUG: add_to_binder: scheme='%s', section='%s'", scheme, section)
|
|
|
|
if not psy_antenna then
|
|
psy_antenna = PsyAntenna()
|
|
psy_antenna.global_state = state_void
|
|
end
|
|
|
|
local new_action = action_psy_antenna(npc, storage)
|
|
|
|
-- Çàðåãèñòðèðîâàòü âñå actions, â êîòîðûõ äîëæåí áûòü âûçâàí ìåòîä reset_scheme ïðè èçìåíåíèè íàñòðîåê ñõåìû:
|
|
xr_logic.subscribe_action_for_events(npc, storage, new_action)
|
|
end
|
|
|
|
function set_scheme(npc, ini, scheme, section, gulag_name)
|
|
local st = xr_logic.assign_storage_and_bind(npc, ini, scheme, section)
|
|
st.logic = xr_logic.cfg_get_switch_conditions(ini, section, npc)
|
|
|
|
st.intensity = (ini:r_float_ex(section,"eff_intensity") or 0) * 0.01
|
|
st.postprocess = ini:r_string_ex(section,"postprocess") or "psy_antenna.ppe"
|
|
|
|
st.hit_intensity = (ini:r_float_ex(section,"hit_intensity") or 0) * 0.01
|
|
st.phantom_prob = (ini:r_float_ex(section,"phantom_prob") or 0) * 0.01
|
|
|
|
st.mute_sound_threshold = ini:r_float_ex(section,"mute_sound_threshold") or 0
|
|
|
|
st.no_static = ini:r_bool_ex(section,"no_static",false)
|
|
st.no_mumble = ini:r_bool_ex(section,"no_mumble",false)
|
|
st.hit_type = ini:r_string_ex(section,"hit_type") or "wound"
|
|
st.hit_freq = ini:r_float_ex(section,"hit_freq") or 5000
|
|
end
|