-------------------------------------------------------------------------------- -- Surge manager class --------------------------------------------------------- -- Made by Peacemaker ---------------------------------------------------------- -- 05.03.07 -------------------------------------------------------------------- -------------------------------------------------------------------------------- -- Edited for AtmosFear 3 ------------------------------------------------------ -- by Cromm Cruac -------------------------------------------------------------- -- 25.06.2011 ------------------------------------------------------------------ -------------------------------------------------------------------------------- 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 = -1 local prev_game_sec = -1 local currentPPEfactor = 0.001 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, ["alfa_force"] = true, ["zombied"] = true } class "CSurgeManager" function CSurgeManager:__init() --self.debugMessages=debug_ui.get_debug_ui():create_elements(20) self.blowout_sounds={ begin01 =sound_object("ambient\\blowout\\blowout_begin"), begin02 =sound_object("ambient\\blowout\\blowout_begin_02"), impact01 =sound_object("ambient\\blowout\\blowout_impact"), impact02 =sound_object("ambient\\blowout\\blowout_impact_02"), wave01 =sound_object("ambient\\blowout\\blowout_wave_01"), wave02 =sound_object("ambient\\blowout\\blowout_wave_02_short"), wave03 =sound_object("ambient\\blowout\\blowout_wave_03_short"), wave04 =sound_object("ambient\\blowout\\blowout_wave_04"), body_tear =sound_object("anomaly\\anomaly_body_tear_1"), siren =sound_object("ambient\\blowout\\blowout_siren") } end function CSurgeManager:initialize() self.atmosfear=atmosfear.get_atmosfear() self.ini = ini_file("misc\\surge_manager.ltx") self.game_time_factor=level.get_time_factor() self.levels_respawn = {zaton = false, jupiter = false, pripyat = 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.wave_sound = false self.blowout_waves = {} self.objects_to_kill={} self.stages={} self.body_tears={} self.hitFactor=0 self.surge_time = 222 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 self.hitFactor=0 end function CSurgeManager:start(manual) self.game_time_factor=level.get_time_factor() --self.atmosfear.debugMessages[1]:SetText("game_time_factor = "..tostring(self.game_time_factor)) 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" or self.atmosfear.opt_enable_blowout==0) then --self.atmosfear.debugMessages[12]:SetText("Surge skipped because of level") self.skip_message = true self:skip_surge() return end if(diff_sec+6>self.surge_time)then --self.atmosfear.debugMessages[12]:SetText("Surge skipped while time forwarding!") self:skip_surge() else self.started = true self.finished = false self.blowout_waves = {} self.objects_to_kill={} self.stages={} self.body_tears={} self.hitFactor=0 level.set_time_factor(10) --self.atmosfear.debugMessages[2]:SetText("level.get_time_factor() = "..tostring(level.get_time_factor())) -- 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:new_surge_time(reset) if reset then self.last_surge_time = game.get_game_time() end MIN_SURGE_TIME = math.floor(self.atmosfear.opt_blowout_freq/2)*3600 MAX_SURGE_TIME = self.atmosfear.opt_blowout_freq*3600 self._delta = math.random(MIN_SURGE_TIME, MAX_SURGE_TIME) local g_time = game.get_game_time() local psi_manager= psi_storm_manager.get_psi_storm_manager() local psi_storm_start = math.floor(psi_manager._delta - g_time:diffSec(psi_manager.last_psi_storm_time)) local psi_storm_end = math.floor(psi_manager._delta+3600 - g_time:diffSec(psi_manager.last_psi_storm_time)) local surge_start = math.floor(self._delta - g_time:diffSec(self.last_surge_time)) local surge_end = math.floor(self._delta+3600 - g_time:diffSec(self.last_surge_time)) if ((surge_end > psi_storm_start) and (surge_end < psi_storm_end)) then --1h earlier self._delta=self._delta-3600 end if ((surge_start > psi_storm_start) and (surge_start < psi_storm_end)) then --1h later self._delta=self._delta+3600 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:new_surge_time(false) self.started = false self.finished = true self.levels_respawn = {zaton = true, jupiter = true, pripyat = true} self.surge_message = "" self.surge_task_sect = "" self.task_given = false sgm_flags.bool_surge_day_is_present=false self.effector_set = false self.second_message_given = false self.ui_disabled = false self.blowout_sound = false self.wave_sound = false prev_sec = 0 self:respawn_artefacts_and_replace_anomaly_zone() xr_statistic.inc_surges_counter() if (not self.skip_message and self.atmosfear.opt_enable_blowout==1) then news_manager.send_tip(db.actor, "st_surge_while_asleep", nil, "recent_surge", nil, nil) self.skip_message = true end -- hide indicators self:displayIndicators(0) level.set_time_factor(self.game_time_factor) --self.atmosfear.debugMessages[2]:SetText("level.get_time_factor() = "..tostring(level.get_time_factor())) end function CSurgeManager:end_surge(manual) self.last_surge_time = game.get_game_time() self.started = false self.finished = true self.levels_respawn = {zaton = true, jupiter = true, pripyat = true} self:new_surge_time(false) self.surge_message = "" self.surge_task_sect = "" self.task_given = false if(self.blowout_sound) then xr_sound.stop_sound_looped(db.actor:id(), "blowout_rumble") end if(self.wave_sound) then xr_sound.stop_sound_looped(db.actor:id(), "blowout_particle_wave_looped") end for k,wave in pairs(self.blowout_waves) do if wave.effect:playing() then self:kill_wave(k) end end for k,snd in pairs(self.blowout_sounds) do if snd ~= nil and snd:playing() then snd:stop() end end if(self.second_message_given) then xr_sound.stop_sound_looped(db.actor:id(), "surge_earthquake_sound_looped") end 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 self.wave_sound = false prev_sec = 0 self.hitFactor=0 sgm_flags.bool_surge_day_is_present=false level.remove_pp_effector(surge_shock_pp_eff) level.remove_cam_effector(earthquake_cam_eff) -- hide indicators self:displayIndicators(0) level.set_time_factor(self.game_time_factor) --self.atmosfear.debugMessages[2]:SetText("level.get_time_factor() = "..tostring(level.get_time_factor())) 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: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 1) then return end if not(self.started) then local g_time = game.get_game_time() if(self.time_forwarded) then local diff = math.abs(self._delta - g_time:diffSec(self.last_surge_time)) 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 self:new_surge_time(true) return end self:start() return end local diff_sec = math.ceil(game.get_game_time():diffSec(self.inited_time)/level.get_time_factor()) local diff_game_sec = math.ceil(game.get_game_time():diffSec(self.inited_time)/2) ------------------------------------update here-------------------------------- if(prev_sec~=diff_sec) then --self.debugMessages[1]:SetText("dif_sec: "..tostring(diff_sec)) --local rnd_sound = math.random(4000) local rnd_sound=math.ceil(math.random(4000)/1000) prev_sec = diff_sec local level_name = level.name() if(level_name=="labx8" or level_name=="jupiter_underground" or self.atmosfear.opt_enable_blowout==0) then printf("Surge stopped because of level!") self:end_surge() return end local cover = self:get_nearest_cover() if(cover==nil and self.count==0) then self:init_surge_covers() return end if(diff_sec>=self.surge_time) then self:end_surge() else if(self.loaded) then self.loaded = false end -- blowout begins ----------------------------------------------------------------------------------------------------------------------------------------- if (diff_sec>=0) and (self.stages['beginning']==nil) then if (level.get_time_hours() >= 5 and level.get_time_hours() <= 20) then level.set_weather_fx("fx_blowout_day") else level.set_weather_fx("fx_blowout_night") end if (rnd_sound % 2) ~= 0 then self:play_blowout_sound("begin01") else self:play_blowout_sound("begin02") end --xr_sound.set_sound_play(db.actor:id(), "blowout_begin") self.stages['beginning']=true --self.debugMessages[2]:SetText("blowout launched at: "..tostring(diff_sec).." rnd: "..tostring(rnd_sound)) end -- siren warning ----------------------------------------------------------------------------------------------------------------------------------------- if (diff_sec>=36) and (self.stages['siren']==nil) and (self.atmosfear.opt_blowout_warning=="siren" or self.atmosfear.opt_blowout_warning=="radio_siren") then self:play_siren_sound() self.stages['siren']=true end -- blowout warning ----------------------------------------------------------------------------------------------------------------------------------------- if (diff_sec>=38) and not(self.task_given) then if (level) and (self.atmosfear.opt_blowout_warning=="radio" or self.atmosfear.opt_blowout_warning=="radio_siren") 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 self:launch_rockets() if self.atmosfear.opt_blowout_task=="give" then self:give_surge_hide_task() end self.task_given = true --self.debugMessages[2]:SetText("task given at: "..tostring(diff_sec)) end -- blowout impact ----------------------------------------------------------------------------------------------------------------------------------------- if (diff_sec>=47) and (self.stages['impact']==nil) then if (rnd_sound % 2) ~= 0 then --xr_sound.set_sound_play(db.actor:id(), "blowout_hit_1") self:play_blowout_sound("impact01") else self:play_blowout_sound("impact02") --xr_sound.set_sound_play(db.actor:id(), "blowout_hit_2") end self.stages['impact']=true sgm_flags.bool_surge_day_is_present=true --self.debugMessages[2]:SetText("impact launched at: "..tostring(diff_sec).." rnd: "..tostring(rnd_sound)) end -- start rumble ----------------------------------------------------------------------------------------------------------------------------------------- if (diff_sec>=50) and (self.stages['rumble']==nil) and not(self.blowout_sound) then xr_sound.play_sound_looped(db.actor:id(), "blowout_rumble") xr_sound.set_volume_sound_looped(db.actor:id(), "blowout_rumble", 0.25) self.stages['rumble']=true self.blowout_sound = true --self.debugMessages[2]:SetText("rumble launched at: "..tostring(diff_sec)) end -- rumble sound fade in ----------------------------------------------------------------------------------------------------------------------------------------- if (diff_sec>=50) and (diff_sec<=75) and (self.stages['rumble']~=nil) and (self.blowout_sound) then xr_sound.set_volume_sound_looped(db.actor:id(), "blowout_rumble", fade(diff_game_sec,50*5,75*5,0.25,1)) --self.debugMessages[3]:SetText("rumble vol: "..tostring(fade(diff_game_sec,50*5,75*5,0.25,1))) end -- 1st earthquake ----------------------------------------------------------------------------------------------------------------------------------------- if (diff_sec>=80) and (self.stages['quake20']==nil) then --self.debugMessages[2]:SetText("eathquake started at: "..tostring(diff_sec)) level.add_cam_effector("camera_effects\\earthquake_20.anm", earthquake_cam_eff, true, "") self.stages['quake20']=true --self.debugMessages[2]:SetText("quake20 at: "..tostring(diff_sec)) end -- second message ----------------------------------------------------------------------------------------------------------------------------------------- if(diff_sec>=90) and not(self.second_message_given) then if (level) and (self.atmosfear.opt_blowout_warning=="radio" or self.atmosfear.opt_blowout_warning=="radio_siren") 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 self.second_message_given = true --self.debugMessages[2]:SetText("second message given at: "..tostring(diff_sec)) end -- earthquakes ----------------------------------------------------------------------------------------------------------------------------------------- if (diff_sec>=100) and (self.stages['quake40']==nil) then xr_sound.play_sound_looped(db.actor:id(), "surge_earthquake_sound_looped") level.remove_cam_effector(earthquake_cam_eff) level.add_cam_effector("camera_effects\\earthquake_40.anm", earthquake_cam_eff, true, "") self.stages['quake40']=true --self.debugMessages[2]:SetText("quake40 at: "..tostring(diff_sec)) end if (diff_sec>=102) and (self.stages['quake60']==nil) then level.remove_cam_effector(earthquake_cam_eff) level.add_cam_effector("camera_effects\\earthquake_60.anm", earthquake_cam_eff, true, "") self.stages['quake60']=true --self.debugMessages[2]:SetText("quake60 at: "..tostring(diff_sec)) end if (diff_sec>=104) and (self.stages['quake80']==nil) then level.remove_cam_effector(earthquake_cam_eff) level.add_cam_effector("camera_effects\\earthquake_80.anm", earthquake_cam_eff, true, "") self.stages['quake80']=true --self.debugMessages[2]:SetText("quake80 at: "..tostring(diff_sec)) end if (diff_sec>=106) and (self.stages['quake100']==nil) then level.remove_cam_effector(earthquake_cam_eff) level.add_cam_effector("camera_effects\\earthquake.anm", earthquake_cam_eff, true, "") self.stages['quake100']=true --self.debugMessages[2]:SetText("quake100 at: "..tostring(diff_sec)) end -- 1st wave sound ----------------------------------------------------------------------------------------------------------------------------------------- if(diff_sec>=108) and (self.stages['1stwavesnd']==nil) then --xr_sound.set_sound_play(db.actor:id(), "blowout_wave_1") if rnd_sound==1 then self:play_blowout_sound("wave01") elseif rnd_sound==2 then self:play_blowout_sound("wave02") elseif rnd_sound==3 then self:play_blowout_sound("wave03") elseif rnd_sound==4 then self:play_blowout_sound("wave04") end self.stages['1stwavesnd']=true --self.debugMessages[2]:SetText("1st wave snd at: "..tostring(diff_sec).." rnd: "..tostring(rnd_sound)) end -- 1st wave ----------------------------------------------------------------------------------------------------------------------------------------- if(diff_sec>=120) and (self.stages['1stwave']==nil) then self:start_wave(1,diff_game_sec) self.stages['1stwave']=true --self.debugMessages[2]:SetText("1st wave at: "..tostring(diff_sec)) end -- 2nd wave sound ----------------------------------------------------------------------------------------------------------------------------------------- if(diff_sec>=156) and (self.stages['2ndwavesnd']==nil) then --xr_sound.set_sound_play(db.actor:id(), "blowout_wave_1") if rnd_sound==1 then self:play_blowout_sound("wave01") elseif rnd_sound==2 then self:play_blowout_sound("wave02") elseif rnd_sound==3 then self:play_blowout_sound("wave03") elseif rnd_sound==4 then self:play_blowout_sound("wave04") end self.stages['2ndwavesnd']=true --self.debugMessages[2]:SetText("2nd wave snd at: "..tostring(diff_sec)) end -- 2nd wave ----------------------------------------------------------------------------------------------------------------------------------------- --if(diff_sec>=2) and (self.stages['2ndwave']==nil) then if(diff_sec>=168) and (self.stages['2ndwave']==nil) then self:start_wave(2,diff_game_sec) self.stages['2ndwave']=true if self.atmosfear.opt_blowout_fate=="killonwave" then self:get_objects_to_kill() end --self.debugMessages[2]:SetText("2nd wave at: "..tostring(diff_sec)) end -- earthquakes fade----------------------------------------------------------------------------------------------------------------------------------------- if (diff_sec>=200) and (self.stages['quake100']==true) then level.remove_cam_effector(earthquake_cam_eff) level.add_cam_effector("camera_effects\\earthquake_80.anm", earthquake_cam_eff, true, "") self.stages['quake100']=false --self.debugMessages[2]:SetText("quake80 at: "..tostring(diff_sec)) end if (diff_sec>=202) and (self.stages['quake80']==true) then level.remove_cam_effector(earthquake_cam_eff) level.add_cam_effector("camera_effects\\earthquake_60.anm", earthquake_cam_eff, true, "") self.stages['quake80']=false --self.debugMessages[2]:SetText("quake60 at: "..tostring(diff_sec)) end if (diff_sec>=206) and (self.stages['quake60']==true) then level.remove_cam_effector(earthquake_cam_eff) level.add_cam_effector("camera_effects\\earthquake_40.anm", earthquake_cam_eff, true, "") self.stages['quake60']=false --self.debugMessages[2]:SetText("quake40 at: "..tostring(diff_sec)) end if (diff_sec>=209) and (self.stages['quake40']==true) then level.remove_cam_effector(earthquake_cam_eff) level.add_cam_effector("camera_effects\\earthquake_20.anm", earthquake_cam_eff, true, "") self.stages['quake40']=false --self.debugMessages[2]:SetText("quake20 at: "..tostring(diff_sec)) end if (diff_sec>=214) and (self.stages['quake20']==true) and (self.stages['quakeended']==nil) then level.remove_cam_effector(earthquake_cam_eff) self.stages['quakeended']=true --self.debugMessages[2]:SetText("eathquake ended at: "..tostring(diff_sec)) end -- rumble and quake sound fade out ----------------------------------------------------------------------------------------------------------------------------------------- if (diff_sec>=200) and (diff_sec<=214) and (self.stages['rumble']~=nil) and (self.blowout_sound) then xr_sound.set_volume_sound_looped(db.actor:id(), "blowout_rumble", fade(diff_game_sec,200*5,214*5,1,0)) xr_sound.set_volume_sound_looped(db.actor:id(), "surge_earthquake_sound_looped", fade(diff_game_sec,200*5,214*5,1,0)) --self.debugMessages[3]:SetText("rumble vol: "..tostring(fade(diff_game_sec,200*5,214*5,1,0))) end -- rumble and quake sound stop ----------------------------------------------------------------------------------------------------------------------------------------- if (diff_sec>=214) and (self.stages['rumble']==true) and (self.blowout_sound) then xr_sound.stop_sound_looped(db.actor:id(), "blowout_rumble") xr_sound.stop_sound_looped(db.actor:id(), "surge_earthquake_sound_looped") --self.debugMessages[2]:SetText("sounds stopped at: "..tostring(diff_sec)) self.stages['rumble']=false end -- end message ----------------------------------------------------------------------------------------------------------------------------------------- if (diff_sec>=212) and (self.stages['endmessage']==nil) then if (level) and (self.atmosfear.opt_blowout_warning=="radio" or self.atmosfear.opt_blowout_warning=="radio_siren") 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.debugMessages[2]:SetText("end message at: "..tostring(diff_sec)) self.stages['endmessage']=true end -- after sound ----------------------------------------------------------------------------------------------------------------------------------------- if(diff_sec>=220) and (self.stages['endsnd']==nil) then xr_sound.set_sound_play(db.actor:id(), "blowout_hit_3") self.stages['endsnd']=true --self.debugMessages[2]:SetText("ending snd at: "..tostring(diff_sec)) end end end --------------------------------- update every 2 game sec ----------------------------------- local actor_pos=db.actor:position() if(prev_game_sec~=diff_game_sec) then prev_game_sec = diff_game_sec if(diff_sec=8) and (diff_sec<=14) and (self.effector_set) then if (diff_sec>=108) and (diff_sec<=114) and (self.effector_set) then self.hitFactor=fade(diff_game_sec,8*5,14*5,0.001,1) end --if (diff_sec>=14) and (diff_sec<=20) and (self.effector_set) then if (diff_sec>=114) and (diff_sec<=120) and (self.effector_set) then self.hitFactor=fade(diff_game_sec,14*5,20*5,1,0.3) end if (diff_sec>=156) and (diff_sec<=162) and (self.effector_set) then self.hitFactor=fade(diff_game_sec,156*5,162*5,0.3,1) end if (diff_sec>=162) and (diff_sec<=168) and (self.effector_set) then self.hitFactor=fade(diff_game_sec,162*5,168*5,1,0.3) end if (diff_sec>=200) and (diff_sec<=210) and (self.effector_set) then self.hitFactor=fade(diff_game_sec,200*5,210*5,0.3,0.001) end if (diff_sec>=210) and (self.effector_set) then self.hitFactor=0 level.remove_pp_effector(surge_shock_pp_eff) self.effector_set=false end -- setting effector local PPEfactor local hitPower if (cover==nil or not(db.storage[cover].object:inside(db.actor:position()))) then PPEfactor = self.hitFactor hitPower = self.hitFactor/50 if PPEfactor < 0.001 then PPEfactor = 0.001 end --self.debugMessages[6]:SetText("outside") else PPEfactor = 0.002 hitPower = 0 --self.debugMessages[6]:SetText("in cover") end currentPPEfactor = currentPPEfactor+(PPEfactor - currentPPEfactor) * 0.1 if(self.effector_set) then level.set_pp_effector_factor(surge_shock_pp_eff, currentPPEfactor) self:displayIndicators(currentPPEfactor) if (not(self.ui_disabled)) then local h = hit() h.type = hit.telepatic h.power = self.atmosfear:hit_power(hitPower, h.type) 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 ]]-- if not(self.atmosfear.god_mode) then db.actor:hit(h) end end end --self.debugMessages[5]:SetText("PPE: "..tostring(currentPPEfactor)) --self.debugMessages[7]:SetText("hitPower: "..tostring(hitPower)) -- Waves local wavevol=0 for k,wave in pairs(self.blowout_waves) do if wave.effect:playing() then local wave_pos=vector():set(actor_pos.x, actor_pos.y/2, wave.inited_pos.z-(diff_game_sec-wave.inited_time)*3) wave.effect:move_to(wave_pos,vector():set(0,0,0)) local wavevoltemp=(250-math.abs(actor_pos.z-wave_pos.z))/250 if (wavevoltemp>wavevol) then wavevol=wavevoltemp end if wave_pos.z=0.8 then indik="red" elseif power>=0.6 then indik="orange" elseif power>=0.4 then indik="yellow" elseif power>=0.1 then indik="green" else indik=nil end local aspectRatio="" if self.atmosfear.aspectRatio~=1 then aspectRatio="_16" end local indikName="atm_indik_psi_"..tostring(indik)..aspectRatio local currentIndikName="atm_indik_psi_"..tostring(currentIndik)..aspectRatio --remove indik if 0 if not indik and currentIndik~=nil then local hudIndikRem = hud:GetCustomStatic(currentIndikName) if hudIndikRem then hud:RemoveCustomStatic(currentIndikName) end currentIndik=nil return end -- display different indik if currentIndik~=indik then -- first remove existing one if currentIndik~=nil then local hudIndik = hud:GetCustomStatic(currentIndikName) if hudIndik then hud:RemoveCustomStatic(currentIndikName) end end -- now display new one if indik then hud:AddCustomStatic(indikName) currentIndik=indik end end --self.debugMessages[8]:SetText("indik="..currentIndikName) end function CSurgeManager:start_wave(num,inited_time) if inited_time==nil then inited_time=prev_game_sec end local actor_pos=db.actor:position() local effect=particles_object("crommcruac\\blowout_wave_blend") local inited_pos=vector():set(actor_pos.x, actor_pos.y/2, actor_pos.z+250) self.blowout_waves[num]={effect=effect,inited_time=inited_time,inited_pos=inited_pos} self.blowout_waves[num].effect:play_at_pos(inited_pos) if not(self.wave_sound) then xr_sound.play_sound_looped(db.actor:id(), "blowout_particle_wave_looped") xr_sound.set_volume_sound_looped(db.actor:id(), "blowout_particle_wave_looped", 0) self.wave_sound=true end end function CSurgeManager:kill_wave(num) if self.blowout_waves[num] then self.blowout_waves[num].effect:stop_deffered() self.blowout_waves[num]=nil end end function fade(currentTime,startTime,endTime,startValue,endValue) local totalFadeTime=endTime-startTime local totalFadeValue=endValue-startValue local elapsedFadeTime=currentTime-startTime local currentValue=(totalFadeValue*elapsedFadeTime)/totalFadeTime+startValue if (totalFadeValue<0) then if (currentValue>startValue) then currentValue=startValue end if (currentValueendValue) then currentValue=endValue end if (currentValue pos and cl_obj:alive() then --self:turn_to_zombie(obj) cl_obj:kill(cl_obj) self.objects_to_kill[k]=nil --self.debugMessages[11]:SetText("killing obj: "..tostring(k)) return end else if obj.position.z > pos and obj:alive() then --self:turn_to_zombie(obj) obj:kill() self.objects_to_kill[k]=nil --self.debugMessages[11]:SetText("killing obj: "..tostring(k)) return end end end end function CSurgeManager:kill_obj_at_pos(pos) 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 local cl_obj = level.object_by_id(obj.id) if cl_obj ~= nil then if cl_obj:position().z>pos then if self.atmosfear.opt_blowout_fate=="turntozombie" then self:turn_to_zombie(obj) else self:explode(obj) end end else if obj.position.z>pos then if self.atmosfear.opt_blowout_fate=="turntozombie" then self:turn_to_zombie(obj) else self:explode(obj) end end end else local release = true for i = 1,#self.covers do local sr = self.covers[i] if(sr and sr:inside(obj.position)) then release = false end end if(release) then local cl_obj = level.object_by_id(obj.id) if cl_obj ~= nil then if cl_obj:position().z>pos then if self.atmosfear.opt_blowout_fate=="turntozombie" then self:turn_to_zombie(obj) else self:explode(obj) end end else if obj.position.z>pos then if self.atmosfear.opt_blowout_fate=="turntozombie" then self:turn_to_zombie(obj) else self:explode(obj) end end end end end end end end end end --self.debugMessages[10]:SetText("obj to kill:"..tostring(#self.objects_to_kill)) end function CSurgeManager:get_objects_to_kill() 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 table.insert(self.objects_to_kill, obj) else local release = true for i = 1,#self.covers do local sr = self.covers[i] if(sr and sr:inside(obj.position)) then release = false end end if(release) then table.insert(self.objects_to_kill, obj) end end end end end end end --self.debugMessages[10]:SetText("obj to kill:"..tostring(#self.objects_to_kill)) end function CSurgeManager:kill_actor_at_pos(pos) local cover = self:get_nearest_cover() if(db.actor and db.actor:alive() and db.actor:position().z>pos) then if not(cover and db.storage[cover] and db.storage[cover].object:inside(db.actor:position())) then 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) self.ui_disabled = true 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 self:end_surge(true) end end end end function CSurgeManager:turn_to_zombie(obj) local cl_obj = level.object_by_id(obj.id) local position local section local zombie_type if cl_obj ~= nil then position=cl_obj:position() section=cl_obj:section() else position=obj.position section=obj:section_name() end alife():release(alife():object(obj.id), true) local section_number = string.sub(section, -1) if section_number=="4" then zombie_type="sim_default_zombied_4" elseif section_number=="3" then zombie_type="sim_default_zombied_3" elseif section_number=="2" or section_number=="1" then zombie_type="sim_default_zombied_2" else zombie_type="sim_default_zombied_1" end alife():create(zombie_type, position, db.actor:level_vertex_id(), db.actor:game_vertex_id()) --self.debugMessages[1]:SetText("type: "..tostring(zombie_type)) end function CSurgeManager:explode(obj) local cl_obj = level.object_by_id(obj.id) local position if cl_obj ~= nil then position=cl_obj:position() else position=obj.position end alife():release(alife():object(obj.id), true) local rnd=math.ceil(math.random(3000)/1000)-1 self.body_tears[obj.id]=particles_object("anomaly2\\body_tear_0"..rnd) self.body_tears[obj.id]:play_at_pos(position) local snd_obj=self.blowout_sounds["body_tear"] if snd_obj ~= nil and snd_obj:playing() then snd_obj:stop() end if snd_obj ~= nil then snd_obj:play_at_pos(db.actor, position) snd_obj.volume = 1 end --self.debugMessages[1]:SetText("type: "..tostring(zombie_type)) 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()) if self.atmosfear.opt_blowout_fate=="turntozombie" then self:turn_to_zombie(obj) elseif self.atmosfear.opt_blowout_fate=="explode" then self:explode(obj) else local cl_obj = level.object_by_id(obj.id) if cl_obj ~= nil then cl_obj:kill(cl_obj) else obj:kill() end end else local release = true for i = 1,#self.covers do local sr = self.covers[i] 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()) if self.atmosfear.opt_blowout_fate=="turntozombie" then self:turn_to_zombie(obj) elseif self.atmosfear.opt_blowout_fate=="explode" then self:explode(obj) else 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 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 if not(self.atmosfear.god_mode) then xr_effects.disable_ui_only(db.actor, nil) end if(xr_logic.pick_section_from_condlist(get_story_object("actor"), nil, self.survive)~="true") then if not(self.atmosfear.god_mode) then self:kill_all_unhided_after_actor_death() db.actor:kill(db.actor) end 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[i] 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()) if self.atmosfear.opt_blowout_fate=="turntozombie" then self:turn_to_zombie(obj) elseif self.atmosfear.opt_blowout_fate=="explode" then self:explode(obj) else 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 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.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) packet:w_u32(self.game_time_factor) 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.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() self.game_time_factor = packet:r_u32() self.blowout_waves = {} self.objects_to_kill={} self.stages={} self.body_tears={} self.hitFactor=0 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 npc_in_cover(npc) local m = get_surge_manager() local cover_id = m:get_nearest_cover_with_npc(npc) if (cover_id ~= nil) and (db.storage[cover_id].object:inside(npc: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() --local f = fallout_manager.get_fallout_manager() --local p = psi_storm_manager.get_psi_storm_manager() return m.started --return m.started or f.fallout_in_progress or p.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() --local f = fallout_manager.get_fallout_manager() --local p = psi_storm_manager.get_psi_storm_manager() return m.finished == true --return m.finished and f.fallout_in_progress==false and p.finished 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 function CSurgeManager:get_nearest_cover_with_npc(victim_npc) 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(victim_npc:position()) for k,v in pairs(hides) do if db.storage[v:id()].object:inside(victim_npc:position()) then return v:id() end local dist = v:position():distance_to(victim_npc:position()) if(dist