Divergent/mods/Desmans Horror Overhaul/gamedata/scripts/sr_psy_antenna.script

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