-------------------------------------------------------------------------------- -- Surge manager class --------------------------------------------------------- -- Made by Peacemaker ---------------------------------------------------------- -- 05.03.07 -------------------------------------------------------------------- -------------------------------------------------------------------------------- -- Edited for AtmosFear 3 ------------------------------------------------------ -- by Cromm Cruac -------------------------------------------------------------- -- 25.06.2011 ------------------------------------------------------------------ -------------------------------------------------------------------------------- -- Edited by Alundaio for Call of Chernobyl --[[ Tronex 2019/9/13 Modified for Anomaly 1.5 --]] ------------------- local alife, math_random, pairs, tostring = alife, math.random, pairs, tostring ------------------- --------------------------------------------------------------------- -- class instance SurgeManager = nil function get_surge_manager() SurgeManager = SurgeManager or CSurgeManager() return SurgeManager end --------------------------------------------------------------------- local a_ini = ini_file("alife.ltx") local normal_time_factor = a_ini:r_float_ex("alife","time_factor") or 6 local surge_time_factor = 10 local surge_shock_pp_eff = 1 local earthquake_cam_eff = 2 local sleep_cam_eff = 3 local sleep_fade_pp_eff = 4 local prev_sec = -1 local prev_game_sec = -1 local currentPPEfactor = 0.001 local _tmr local snd_surge1 = sound_object('characters_voice\\scenario\\zaton\\zat_a2_stalker_barmen_surge_phase_1') local snd_surge2 = sound_object('characters_voice\\scenario\\zaton\\zat_a2_stalker_barmen_surge_phase_2') local snd_surge3 = sound_object('characters_voice\\scenario\\zaton\\zat_a2_stalker_barmen_after_surge') local presurge_played = {0, 0, 0, 0, 0, 0} --[[Amount of time before a surge in in-game seconds (6x real life seconds) Note that the script updates events only once per real life second]]-- local presurge_time = 360 local function main_loop() local tg = time_global() if (_tmr and tg < _tmr) then return false end _tmr = tg + 1000 if not (db.actor and db.actor.afterFirstUpdate) then return false end get_surge_manager():update() psi_storm_manager.get_psi_storm_manager():update() if level.get_time_factor() ~= normal_time_factor and not is_started() and not psi_storm_manager.is_started() then if is_finished() and psi_storm_manager.is_finished() then level.set_time_factor(normal_time_factor) end end return false end local function on_level_changing() local tm = task_manager.get_task_manager() local task_info = tm.task_info["faction_base_defense"] if (task_info and task_info.status ~= "completed" and task_info.status ~= "fail") then stop_surge() tm:set_task_cancelled("faction_base_defense") end end local function actor_on_sleep(hours) get_surge_manager().time_forwarded = true psi_storm_manager.get_psi_storm_manager().time_forwarded = true if(is_started() and level_weathers.get_weather_manager().weather_fx) then level.stop_weather_fx() end level_weathers.get_weather_manager():forced_weather_change() end function on_game_start() AddUniqueCall(main_loop) RegisterScriptCallback("on_level_changing",on_level_changing) RegisterScriptCallback("actor_on_sleep",actor_on_sleep) end local enable_debug = false function print_dbg(fmt,...) if enable_debug then printf("Surge manager | " .. fmt,...) end end local function file_exists(filename) local file = io.open(filename, "r") if (file) then file:close() return true end return false end -- ############################################################################################### -- SURGE MANAGER -- ############################################################################################### class "CSurgeManager" function CSurgeManager:__init() self.ini = ini_file("misc\\surge_manager.ltx") 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"), crow0 =sound_object("ambient\\blowout\\cut\\close"), crow1 =sound_object("ambient\\blowout\\cut\\closemedium"), crow2 =sound_object("ambient\\blowout\\cut\\medium"), crow3 =sound_object("ambient\\blowout\\cut\\prettyfar"), crow4 =sound_object("ambient\\blowout\\cut\\far"), crow5 =sound_object("ambient\\blowout\\cut\\veryfar") } self.blowout_waves = {} self.body_tears = {} end function CSurgeManager:initialize() --[[ self.levels_respawn = empty_table(self.levels_respawn) for level,v in pairs(level_weathers.valid_levels) do self.levels_respawn[level] = false end --]] --utils_data.debug_write("CSurgeManager:initialize() start") self.aspectRatio = 1 if(device().width/device().height>(1024/768+0.01)) then self.aspectRatio = 0.8 end if not (self._state_loaded) then -- because state_load called too early, we wait till actor_on_load to truly init and we do not want to overwrite loaded values self.last_surge_time = game.get_game_time() self.inited_time = game.get_game_time() self.started = false self.finished = true self.game_time_factor=level.get_time_factor() self.task_given = nil end if not (self._delta) then local freq = ui_options.get("alife/event/emission_frequency") self._delta = math_random(math.floor(freq/2)*3600, freq*3600) end self.hitFactor = 0 self.surge_time = 222 self:init_surge_covers() local ini = self.ini self.condlist = ini:r_string_to_condlist("settings","condlist") self.survive = ini:r_string_to_condlist("settings","survive") self.surge_message = "" self.surge_task_sect = "" --printf("level=%s artefact_respawn_levels=%s",level.name(),m_data.artefact_respawn_levels[level.name()]) --utils_data.debug_write("CSurgeManager:initialize() end") end function CSurgeManager:start(manual) -- manual is used to set inited_time to current in-game date -- sets inited_time for the surge + prepare values -- skip surge in special cases --utils_data.debug_write("CSurgeManager:start()") if not (self._state_loaded) then self:initialize() end self.game_time_factor = level.get_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 or not self.inited_time) then self.inited_time = game.get_game_time() else self.inited_time:set(Y, M, D, h, m, s + self._delta, ms) end local flags = {allow = true} SendScriptCallback("on_before_surge",flags) local level_name = level.name() if (level_weathers.valid_levels[level_name] ~= true or (not ui_options.get("alife/event/emission_state")) or flags.allow == false) then self:skip_surge() return end -- Generators is emission source and Deserted Hospital has nowhere to hide (almost all the map is inside anyway). if (level_name == "l13_generators" or level_name == "l11_hospital" or has_alife_info("bar_arena_fight")) then self.skip_message = true self:skip_surge() return end local diff_sec = math.ceil(game.get_game_time():diffSec(self.inited_time)/level.get_time_factor()) if (diff_sec+6 > self.surge_time)then self.skip_message = true self:skip_surge() else -- heli_combat flag save_var(db.actor,"heli_enemy_flag",nil) self.started = true self.finished = false self.task_given = nil self:finalize() self.blowout_waves = empty_table(self.blowout_waves) self.objects_to_kill = empty_table(self.objects_to_kill) self.stages = empty_table(self.stages) self.body_tears = empty_table(self.body_tears) self.hitFactor=0 level.set_time_factor(surge_time_factor) self.zombie_count = 0 SendScriptCallback("actor_on_interaction", "anomalies", nil, "emission_start") end end function CSurgeManager:new_surge_time(reset) if reset then self.last_surge_time = game.get_game_time() end --utils_data.debug_write("CSurgeManager:new_surge_time()") local freq = ui_options.get("alife/event/emission_frequency") self._delta = math_random(math.floor(freq/2)*3600, freq*3600) local g_time = game.get_game_time() local psi_manager = psi_storm_manager and psi_storm_manager.get_psi_storm_manager() local last_psi_storm_time = psi_manager and psi_manager.last_psi_storm_time or game.get_game_time() local psi_storm_start = psi_manager and math.floor(psi_manager._delta - g_time:diffSec(last_psi_storm_time)) or 0 local psi_storm_end = psi_manager and math.floor(psi_manager._delta+3600 - g_time:diffSec(last_psi_storm_time)) or 0 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() if not (self.inited_time) then self.inited_time = game.get_game_time() end if not (self.last_surge_time) then self.last_surge_time = game.get_game_time() end 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 = empty_table(self.levels_respawn) for level,v in pairs(level_weathers.valid_levels) do self.levels_respawn[level] = true end --]] self.surge_message = "" self.surge_task_sect = "" 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 prev_sec = 0 SendScriptCallback("actor_on_interaction", "anomalies", nil, "emission_end") if (self.skip_message and ui_options.get("alife/event/emission_state")) then news_manager.send_tip(db.actor, "st_surge_while_asleep", nil, "recent_surge", nil, nil) SendScriptCallback("actor_on_interaction", "anomalies", nil, "emissions") game_statistics.increment_statistic("emissions") self.skip_message = nil --release_body_manager.get_release_body_manager():clear(true) end -- hide indicators self:displayIndicators(0) level.set_time_factor(self.game_time_factor) end function CSurgeManager:end_surge(manual) if (self.started == true) then game_statistics.increment_statistic("emissions") self:kill_all_unhided() SendScriptCallback("actor_on_interaction", "anomalies", nil, "emissions") SendScriptCallback("actor_on_interaction", "anomalies", nil, "emission_end") end self.last_surge_time = game.get_game_time() self.started = false self.finished = true self:new_surge_time(false) self.surge_message = "" self.surge_task_sect = "" self.task_given = nil presurge_played = {0, 0, 0, 0, 0} if(self.blowout_sound) then xr_sound.stop_sound_looped(AC_ID, "blowout_rumble") end if(self.wave_sound) then xr_sound.stop_sound_looped(AC_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(AC_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 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) for k,v in pairs(db.signal_light) do v:stop_light() v:stop() end end function CSurgeManager:pos_in_cover(pos,by_name) if not (self.covers) then return end local sr for name,condlist in pairs(self.covers) do --if (db.actor_inside_zones[name]) then --return true --end sr = db.zone_by_name[name] if (sr and sr:inside(pos)) then if by_name then return name end return true end end return false end function CSurgeManager:init_surge_covers() -- collect safe zones list, if not done yet if (self.covers) then return end self.covers = {} local ini = self.ini for i = 0, ini:line_count("list")-1 do temp1, id, temp2 = ini:r_line("list", i, "", "") self.covers[id] = ini:r_string_to_condlist(id,"condlist") or xr_logic.parse_condlist(nil,"surge_manager","covers","true") end end function CSurgeManager:hit_power(power,hit_type) local hit_types={"burn", "shock", "chemical_burn", "radiation", "telepatic"} local suit_factors={10,1,5,33,10} local drug_factors={1,1,5,33,10} local artefact_factors={10,5,10,10,10} local suit_protection = db.actor:get_current_outfit_protection(hit_type)*suit_factors[hit_type+1] local helmet_protection = 0 local helmet = db.actor:item_in_slot(12) if helmet ~= nil then helmet_protection = ini_sys:r_float_ex(helmet:section(),hit_types[hit_type+1].."_protection")*suit_factors[hit_type+1] end local g_time -- DRUG PROTECTIONS CHECK local expiration = load_var(db.actor,"drug_psy_blockade_expiration") if (expiration) then g_time = utils_data.CTimeToSec(game.get_game_time()) if g_time 1 then protection = 1 end hit_power=power*(1-protection) return hit_power 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(AC_ID, "blowout_particle_wave_looped") xr_sound.set_volume_sound_looped(AC_ID, "blowout_particle_wave_looped", 0) self.wave_sound=true end end function CSurgeManager:finalize() for k,v in pairs(self.blowout_waves) do if (v.effect and v.effect:playing()) then v.effect:stop() end end for k,v in pairs(self.body_tears) do if (v:playing()) then v:stop() end 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 initialize') self:initialize() return end if not (self.first_update) then print_dbg('first update') self.first_update = true local flags = {allow = true} SendScriptCallback("on_before_surge",flags) -- end surge if level is not valid local level_name = level.name() if (level_name == "l13_generators" or level_name == "l11_hospital" or has_alife_info("bar_arena_fight") or flags.allow == false or level_weathers.valid_levels[level_name] ~= true) then print_dbg('level is not valid') if (self.started) then self:end_surge() -- else -- self:skip_surge() end return end local diff_sec = math.ceil(game.get_game_time():diffSec(self.inited_time)/level.get_time_factor()) print_dbg('diff_sec 1 = %s',diff_sec) if (diff_sec > self.surge_time)then print_dbg('diff_sec > self.surge_time') self:skip_surge() return end end SetEvent("surge", "state", self.started) if (not self.started) then --print_dbg('not started') 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 print_dbg('time forwarded') end --Plays sound before a blowout if(math.abs(self._delta - g_time:diffSec(self.last_surge_time)) < presurge_time) then if(presurge_played[1] ~= true) then --self.blowout_sounds["presurge"]:play(db.actor) play_sound_radius(self.blowout_sounds["crow5"], 1000, 140, 220) play_sound_radius(self.blowout_sounds["crow4"], 1000, 140, 220) printf("Played far crows") presurge_played[1] = true end if(math.abs(self._delta - g_time:diffSec(self.last_surge_time)) < (presurge_time - 60) and presurge_played[2] ~= true) then --self.blowout_sounds["presurge"]:play(db.actor) play_sound_radius(self.blowout_sounds["crow3"], 1000, 100, 260) play_sound_radius(self.blowout_sounds["crow2"], 1000, 100, 260) printf("Played medium crows") presurge_played[2] = true end if(math.abs(self._delta - g_time:diffSec(self.last_surge_time)) < (presurge_time - 120) and presurge_played[3] ~= true) then --self.blowout_sounds["presurge"]:play(db.actor) play_sound_radius(self.blowout_sounds["crow1"], 1000, 0, 360) play_sound_radius(self.blowout_sounds["crow0"], 1000, 0, 360) printf("Played close crows") presurge_played[3] = true end if(math.abs(self._delta - g_time:diffSec(self.last_surge_time)) < (presurge_time - 180) and presurge_played[4] ~= true) then --self.blowout_sounds["presurge"]:play(db.actor) play_sound_radius(self.blowout_sounds["crow2"], 1000, 280, 440) play_sound_radius(self.blowout_sounds["crow3"], 1000, 280, 440) printf("Played medium crows") presurge_played[4] = true end if(math.abs(self._delta - g_time:diffSec(self.last_surge_time)) < (presurge_time - 240) and presurge_played[5] ~= true) then --self.blowout_sounds["presurge"]:play(db.actor) play_sound_radius(self.blowout_sounds["crow4"], 1000, 320, 400) play_sound_radius(self.blowout_sounds["crow5"], 1000, 320, 400) printf("Played far crows") presurge_played[5] = true end end --DEBUG --printf("until blowout: %s", math.abs(self._delta - g_time:diffSec(self.last_surge_time))) -- return if next surge time hasn't been reached yet if (g_time:diffSec(self.last_surge_time) < self._delta) then --print_dbg('next surge time hasnt been reached yet') return end if (self.condlist and xr_logic.pick_section_from_condlist(db.actor, nil, self.condlist) == "false") then return end print_dbg('start') self:start() return end local diff_sec = math.ceil(game.get_game_time():diffSec(self.inited_time)/level.get_time_factor()) if (diff_sec >= self.surge_time) then print_dbg('diff_sec 2 = %s', diff_sec) if (load_var(db.actor,"surge_immuned",false) ~= true) then -- special surged immuned for tasks self:end_surge() return else print_dbg('start surge') self:start(true) end end local diff_game_sec = math.ceil(game.get_game_time():diffSec(self.inited_time)/2) print_dbg('diff_game_sec = %s', diff_game_sec) ------------------------------------update here-------------------------------- --printf("diff_sec = %s",diff_sec) if (prev_sec ~= diff_sec) then prev_sec = diff_sec SetEvent("surge", "time", diff_sec) if (not ui_options.get("alife/event/emission_state")) then --printf("Surge stopped because of level!") print_dbg('stop surge because option') self:end_surge() return end local rnd_sound= math.random(1,4) -- blowout begins ----------------------------------------------------------------------------------------------------------------------------------------- if (diff_sec>=0 and self.stages['beginning'] ~= true) then print_dbg('diff_sec>=%s | blowout begins',diff_sec) 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(AC_ID, "blowout_begin") self.stages['beginning']=true --self.debugMessages[2]:SetText("blowout launched at: "..tostring(diff_sec).." rnd: "..tostring(rnd_sound)) end -- siren warning ----------------------------------------------------------------------------------------------------------------------------------------- local warn = ui_options.get("alife/event/emission_warning") if (diff_sec>=25) and (self.stages['siren'] ~= true) and (warn == "siren" or warn == "siren_radio" or warn == "radio_siren") then print_dbg('diff_sec>=%s | siren warning',diff_sec) self:play_siren_sound() self.stages['siren']=true end -- blowout warning ----------------------------------------------------------------------------------------------------------------------------------------- if (diff_sec>=30) then print_dbg('diff_sec>=%s | blowout warning',diff_sec) if (self.task_given ~= true) then if (warn == "siren" or warn == "siren_radio" or warn == "radio_siren") then if (level.name() == "zaton") then xr_sound.set_sound_play(AC_ID, "zat_a2_stalker_barmen_surge_phase_1") elseif (level.name() == "jupiter") then xr_sound.set_sound_play(AC_ID, "jup_a6_stalker_medik_phase_1") elseif (level.name() == "l03_agroprom") then xr_sound.set_sound_play(AC_ID, "kovalsky_surge_phase_1") elseif (level.name() ~= nil) then snd_surge1:play(db.actor,0,sound_object.s2d) end end self:launch_rockets() if (load_var(db.actor,"surge_immuned",false) ~= true) then -- special surged immuned for tasks printf("opt_blowout_task",ui_options.get("alife/event/emission_task")) if ui_options.get("alife/event/emission_task") then self:give_surge_hide_task() end end self.task_given = true --self.debugMessages[2]:SetText("task given at: "..tostring(diff_sec)) end end -- blowout impact ----------------------------------------------------------------------------------------------------------------------------------------- if (diff_sec>=47) and (self.stages['impact'] ~= true) then print_dbg('diff_sec>=%s | blowout impact',diff_sec) if (rnd_sound % 2) ~= 0 then --xr_sound.set_sound_play(AC_ID, "blowout_hit_1") self:play_blowout_sound("impact01") else self:play_blowout_sound("impact02") --xr_sound.set_sound_play(AC_ID, "blowout_hit_2") end self.stages['impact']=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 print_dbg('diff_sec>=%s | blowout rumble',diff_sec) xr_sound.play_sound_looped(AC_ID, "blowout_rumble") xr_sound.set_volume_sound_looped(AC_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 print_dbg('diff_sec>=%s | blowout rumble sound fade in',diff_sec) xr_sound.set_volume_sound_looped(AC_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 print_dbg('diff_sec>=%s | 1st earthquake',diff_sec) --self.debugMessages[2]:SetText("eathquake started at: "..tostring(diff_sec)) level.add_cam_effector("camera_effects\\earthquake_20.anm", earthquake_cam_eff, true, "", 0, false) 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 print_dbg('diff_sec>=%s | second message',diff_sec) if (warn == "siren" or warn =="siren_radio" or warn =="radio_siren") then if (level.name() == "zaton") then xr_sound.set_sound_play(AC_ID, "zat_a2_stalker_barmen_surge_phase_2") elseif(level.name() == "jupiter") then xr_sound.set_sound_play(AC_ID, "jup_a6_stalker_medik_phase_2") elseif (level.name() == "l03_agroprom") then xr_sound.set_sound_play(AC_ID, "kovalsky_surge_phase_2") elseif (level.name() ~= nil) then snd_surge2:play(db.actor,0,sound_object.s2d) 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 print_dbg('diff_sec>=%s | earthquakes quake40',diff_sec) xr_sound.play_sound_looped(AC_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, "", 0, false) self.stages['quake40']=true --self.debugMessages[2]:SetText("quake40 at: "..tostring(diff_sec)) end if (diff_sec>=102) and (self.stages['quake60']==nil) then print_dbg('diff_sec>=%s | earthquakes quake60',diff_sec) level.remove_cam_effector(earthquake_cam_eff) level.add_cam_effector("camera_effects\\earthquake_60.anm", earthquake_cam_eff, true, "", 0, false) self.stages['quake60']=true --self.debugMessages[2]:SetText("quake60 at: "..tostring(diff_sec)) end if (diff_sec>=104) and (self.stages['quake80']==nil) then print_dbg('diff_sec>=%s | earthquakes quake80',diff_sec) level.remove_cam_effector(earthquake_cam_eff) level.add_cam_effector("camera_effects\\earthquake_80.anm", earthquake_cam_eff, true, "", 0, false) self.stages['quake80']=true --self.debugMessages[2]:SetText("quake80 at: "..tostring(diff_sec)) end if (diff_sec>=106) and (self.stages['quake100']==nil) then print_dbg('diff_sec>=%s | earthquakes quake100',diff_sec) level.remove_cam_effector(earthquake_cam_eff) level.add_cam_effector("camera_effects\\earthquake.anm", earthquake_cam_eff, true, "", 0, false) self.stages['quake100']=true --self.debugMessages[2]:SetText("quake100 at: "..tostring(diff_sec)) end if (load_var(db.actor,"surge_immuned",false) ~= true) then -- special surged immuned for tasks -- 1st wave sound ----------------------------------------------------------------------------------------------------------------------------------------- if(diff_sec>=108) and (self.stages['1stwavesnd']==nil) then print_dbg('diff_sec>=%s | 1st wave sound',diff_sec) --xr_sound.set_sound_play(AC_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 print_dbg('diff_sec>=%s | 1st wave',diff_sec) 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 print_dbg('diff_sec>=%s | 2nd wave sound',diff_sec) --xr_sound.set_sound_play(AC_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 print_dbg('diff_sec>=%s | 2nd wave',diff_sec) self:start_wave(2,diff_game_sec) self.stages['2ndwave']=true --self.debugMessages[2]:SetText("2nd wave at: "..tostring(diff_sec)) end end -- earthquakes fade----------------------------------------------------------------------------------------------------------------------------------------- if (diff_sec>=200) and (self.stages['quake100']==true) then print_dbg('diff_sec>=%s | earthquakes fade quake100',diff_sec) level.remove_cam_effector(earthquake_cam_eff) level.add_cam_effector("camera_effects\\earthquake_80.anm", earthquake_cam_eff, true, "", 0, false) self.stages['quake100']=false --self.debugMessages[2]:SetText("quake80 at: "..tostring(diff_sec)) end if (diff_sec>=202) and (self.stages['quake80']==true) then print_dbg('diff_sec>=%s | earthquakes fade quake80',diff_sec) level.remove_cam_effector(earthquake_cam_eff) level.add_cam_effector("camera_effects\\earthquake_60.anm", earthquake_cam_eff, true, "", 0, false) self.stages['quake80']=false --self.debugMessages[2]:SetText("quake60 at: "..tostring(diff_sec)) end if (diff_sec>=206) and (self.stages['quake60']==true) then print_dbg('diff_sec>=%s | earthquakes fade quake60',diff_sec) level.remove_cam_effector(earthquake_cam_eff) level.add_cam_effector("camera_effects\\earthquake_40.anm", earthquake_cam_eff, true, "", 0, false) self.stages['quake60']=false --self.debugMessages[2]:SetText("quake40 at: "..tostring(diff_sec)) end if (diff_sec>=209) and (self.stages['quake40']==true) then print_dbg('diff_sec>=%s | earthquakes fade quake40',diff_sec) level.remove_cam_effector(earthquake_cam_eff) level.add_cam_effector("camera_effects\\earthquake_20.anm", earthquake_cam_eff, true, "", 0, false) 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 print_dbg('diff_sec>=%s | earthquakes fade quake20',diff_sec) 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 print_dbg('diff_sec>=%s | rumble and quake sound fade out',diff_sec) xr_sound.set_volume_sound_looped(AC_ID, "blowout_rumble", fade(diff_game_sec,200*5,214*5,1,0)) xr_sound.set_volume_sound_looped(AC_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 print_dbg('diff_sec>=%s | rumble and quake sound stop',diff_sec) xr_sound.stop_sound_looped(AC_ID, "blowout_rumble") xr_sound.stop_sound_looped(AC_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 print_dbg('diff_sec>=%s | end message',diff_sec) if (level) and (warn == "siren" or warn =="siren_radio" or warn =="radio_siren") then if(level.name()=="zaton") then xr_sound.set_sound_play(AC_ID, "zat_a2_stalker_barmen_after_surge") elseif(level.name()=="jupiter") then xr_sound.set_sound_play(AC_ID, "jup_a6_stalker_medik_after_surge") elseif (level.name() == "l03_agroprom") then xr_sound.set_sound_play(AC_ID, "kovalsky_after_surge") elseif (level.name() ~= nil) then snd_surge3:play(db.actor,0,sound_object.s2d) 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 print_dbg('diff_sec>=%s | after sound',diff_sec) xr_sound.set_sound_play(AC_ID, "blowout_hit_3") self.stages['endsnd']=true --self.debugMessages[2]:SetText("ending snd at: "..tostring(diff_sec)) end end --------------------------------- update every 2 game sec ----------------------------------- if (prev_game_sec ~= diff_game_sec) then prev_game_sec = diff_game_sec if (diff_sec < self.surge_time) then print_dbg('diff_sec>=%s | effectors',diff_sec) local actor_pos = db.actor:position() -- hitFactor changes ----------------------------------------------------------------------------------------------------------------------------------------- --self.debugMessages[3]:SetText("hitFactor: "..tostring(self.hitFactor)) --self.debugMessages[4]:SetText("psy_health="..tostring(db.actor.psy_health)) --if (diff_sec>=8) and (diff_sec<210) and not(self.effector_set) then if (diff_sec>=108) and (diff_sec<210) and not(self.effector_set) then level.add_pp_effector("psychic.ppe", surge_shock_pp_eff, true) level.set_pp_effector_factor(surge_shock_pp_eff, 0.001) self.effector_set=true end --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 not (GetEvent("current_safe_cover")) 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 (load_var(db.actor,"surge_immuned",false) ~= true) then if (self.effector_set) then level.set_pp_effector_factor(surge_shock_pp_eff, currentPPEfactor) self:displayIndicators(currentPPEfactor) if (db.actor:alive() and character_community(db.actor) ~= "actor_monolith") then local h = hit() h.type = hit.telepatic h.power = self:hit_power(hitPower, h.type) h.impulse = 0.0 h.direction = VEC_Z h.draftsman = db.actor if (self.survive and xr_logic.pick_section_from_condlist(db.actor, nil, self.survive) == "true") then if(db.actor.health<=h.power) then if (db.actor.health-0.05 > 0.05) then h.power = 0.05 else h.power = 0 end end end print_dbg('diff_sec>=%s | hit actor',diff_sec) 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 local fate = ui_options.get("alife/event/emission_fate") or "kill_at_wave" 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,VEC_ZERO) local wavevoltemp = (250 - math.abs(actor_pos.z-wave_pos.z))/250 if (wavevoltemp > wavevol) then wavevol = wavevoltemp end if wave_pos.z < actor_pos.z - 250 then wave.effect:stop_deffered() if (k==2) then --kill all remaining npcs if fate == "turn_to_zombie" or fate == "explode" then print_dbg('diff_sec>=%s | turn_to_zombie',diff_sec) self:kill_objects_at_pos(-10000,fate) end end end self:kill_crows_at_pos(wave_pos.z) if fate == "kill_at_wave" then if (prev_sec == prev_game_sec/5) then print_dbg('diff_sec>=%s | kill_objects_at_pos',diff_sec) self:kill_objects_at_pos(wave_pos.z,fate) end end if (fate == "turn_to_zombie" or fate == "explode") and k==2 then print_dbg('diff_sec>=%s | turn_to_zombie',diff_sec) self:kill_objects_at_pos(wave_pos.z, fate) end if (wave_pos.z < actor_pos.z) then if k==1 and not GetEvent("current_safe_cover") and (character_community(db.actor) ~= "actor_monolith") and (character_community(db.actor) ~= "actor_zombied") then local h = hit() h.type = hit.telepatic h.power = self:hit_power(2, h.type)+0.5 h.impulse = 0.0 h.direction = VEC_Z h.draftsman = db.actor if (xr_logic.pick_section_from_condlist(db.actor, nil, self.survive)=="true") then if(db.actor.health<=h.power) then if (db.actor.health-0.05 > 0.05) then h.power = 0.05 else h.power = 0 end end end if (load_var(db.actor,"surge_immuned",false) ~= true) then print_dbg('diff_sec>=%s | hit actor 2',diff_sec) db.actor:hit(h) end self.stages['1stwavehit']=true; --self.debugMessages[2]:SetText("first wave hit at: "..tostring(diff_sec)..' with strength: '..h.power) end if (k==2 and self.stages['2ndwavehit']==nil) then if fate=="kill_at_end" then print_dbg('diff_sec>=%s | kill_at_end',diff_sec) self:kill_all_unhided() else if (load_var(db.actor,"surge_immuned",false) ~= true) then if not (level_environment.is_actor_immune()) then print_dbg('diff_sec>=%s | kill_actor_at_pos',diff_sec) self:kill_actor_at_pos(wave_pos.z) end end end self.stages['2ndwavehit']=true --self.debugMessages[2]:SetText("second wave hit at: "..tostring(diff_sec)) end end end end if (self.wave_sound) then --self.debugMessages[1]:SetText("wave vol: "..tostring(wavevol)) xr_sound.set_volume_sound_looped(AC_ID, "blowout_particle_wave_looped", wavevol) end end end end ---------------------------------- -- Effects ---------------------------------- function CSurgeManager:displayIndicators(power) local hud = get_hud() if not (hud) then return end local indik if power>=0.8 then indik=nil elseif power>=0.6 then indik=nil elseif power>=0.4 then indik=nil elseif power>=0.1 then indik=nil else indik=nil end local aspectRatio="" if self.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,true) currentIndik=indik end end --self.debugMessages[8]:SetText("indik="..currentIndikName) end function CSurgeManager:play_blowout_sound(id) local snd_obj=self.blowout_sounds[id] if snd_obj ~= nil and snd_obj:playing() then snd_obj:stop() end if snd_obj ~= nil then snd_obj:play(db.actor) snd_obj.volume = 1 --self.debugMessages[12]:SetText("playing: "..tostring(id)) end end function CSurgeManager:play_siren_sound() local snd_obj=self.blowout_sounds["siren"] if (snd_obj == nil) then return end local snd_position if snd_obj:playing() then snd_obj:stop() end if(level.name()=="zaton") then snd_position= vector():set(115,8,184) elseif(level.name()=="jupiter") then snd_position= vector():set(-50,16,198) else snd_position= vector():set(147,15,-187) end snd_obj:play_at_pos(db.actor, snd_position) snd_obj.volume = 1 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 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 ---------------------------------- -- NPC fate ---------------------------------- function make_dead_crow(id,powr) local crow = id and level.object_by_id(id) if(crow and crow:alive() and powr) then crow:hit(powr) end return true end function make_dead(id) local obj = id and db.storage[id] and db.storage[id].object --level.object_by_id(id) if (obj and obj:alive()) then obj:kill(obj) else local se_obj = id and alife_object(id) if (se_obj and se_obj:alive()) then se_obj:kill() end end return true end function CSurgeManager:kill_crows_at_pos(pos,delay) -- hit all crows if their pos is bigger than "pos" local h = hit() h.type = hit.fire_wound h.power = 0.9 h.impulse = 0.0 h.direction = VEC_Z h.draftsman = db.actor for k,id in pairs(bind_crow.crow_storage) do if delay then CreateTimeEvent("delay_kill_crow",id,math_random(1,3),make_dead_crow,id,h) else local crow = level.object_by_id(id) if (crow and crow:alive() and pos < crow:position().z) then crow:hit(h) end end end end function CSurgeManager:kill_objects_at_pos(surge_pos, fate, delay) if (load_var(db.actor,"surge_immuned",false) == true) then return end local can_kill = (fate == "kill_at_wave") or (fate == "turn_to_zombie") or (fate == "explode") or (fate == "kill_at_end") if (not can_kill) then print_dbg('kill_objects_at_pos | cant kill because fate is [%s]',fate) return end print_dbg("kill_objects_at_pos | pos: %s - fate: %s - delay: %s", surge_pos, fate, delay) local id, comm, npc_pos, se_npc, npc, squad, squad_id, smart, surge_smart local board = SIMBOARD local sim = alife() for i=1, #db.OnlineStalkers do id = db.OnlineStalkers[i] npc = db.storage[id] and db.storage[id].object or level.object_by_id(id) if npc then comm = npc:character_community() npc_pos = npc:position() if npc_pos and IsStalker(npc) -- must be stalker and npc:alive() -- must be alive and (comm ~= "monolith") -- not monolith (immune) and (comm ~= "zombied") -- not zombied (immune) and (not get_object_story_id(id)) -- not story npc and ((surge_pos == false) or (surge_pos and npc_pos.z > surge_pos)) -- npc is behind emission wave then se_npc = sim:object(id) squad_id = se_npc.group_id squad = squad_id and sim:object(squad_id) if se_npc and squad then smart = board and squad.smart_id and board.smarts[squad.smart_id] and board.smarts[squad.smart_id].smrt surge_smart = smart and smart.props and (tonumber(smart.props["surge"]) > 0) if not (surge_smart or self:pos_in_cover(npc_pos)) then -- if stalker is not in a safe smart or not inside print_dbg('kill_objects_at_pos | kill npc [%s]',se_npc:name()) if (fate == "turn_to_zombie") then self:turn_to_zombie(se_npc,squad) elseif (fate == "explode") then self:explode(se_npc,squad) elseif (fate == "kill_at_wave") or (fate == "kill_at_end") then if delay then CreateTimeEvent("delay_kill",id,math_random(1,3),make_dead,id) else npc:kill(npc) end end else print_dbg('kill_objects_at_pos | cant kill npc [%s] | surge_smart: %s - in_cover: %s',se_npc:name(), surge_smart, self:pos_in_cover(npc_pos,true)) end end else print_dbg('kill_objects_at_pos | cant kill npc [%s] | behind emission wave: %s',npc:name(), ((surge_pos == false) or (surge_pos and npc_pos and npc_pos.z > surge_pos))) end end end end function CSurgeManager:kill_actor_at_pos(pos) -- kill player at end if (load_var(db.actor,"surge_immuned",false) == true) then return end if(db.actor and db.actor:alive() and db.actor:position().z>pos) then if not (GetEvent("current_safe_cover")) 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 local fate = ui_options.get("alife/event/emission_fate") or "kill_at_wave" self:kill_objects_at_pos(false, fate, true) 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:change_health(-0.05) self:end_surge(true) end end end end function CSurgeManager:kill_all_unhided() -- called only when "kill_at_end" is active, turn to zombie + explode + kill with delay, kill actor if (load_var(db.actor,"surge_immuned",false) == true) then return end -- delay hit for crows self:kill_crows_at_pos(false,true) -- delay kill for online npcs local fate = ui_options.get("alife/event/emission_fate") or "kill_at_wave" self:kill_objects_at_pos(false, fate, true) if (level_environment.is_actor_immune()) then return end -- don't kill actor if he isn't on a valid level local sim,gg = alife(),game_graph() local actor_level = sim:level_name(gg:vertex(sim:actor().m_game_vertex_id):level_id()) if (self.indoor_levels and self.indoor_levels[actor_level] or level_weathers.valid_levels[actor_level] ~= true) then return end if (db.actor and db.actor:alive() and not GetEvent("current_safe_cover")) then --[[ if has_alife_info("anabiotic_in_process") then local counter_name = "actor_marked_by_zone_cnt" local cnt_value = load_var(db.actor, counter_name, 0) save_var(db.actor, counter_name, cnt_value + 1) end ]] xr_effects.disable_ui_only(db.actor, nil) if (xr_logic.pick_section_from_condlist(get_story_object("actor"), nil, self.survive) ~= "true") then local fate = ui_options.get("alife/event/emission_fate") or "kill_at_wave" self:kill_objects_at_pos(false, fate, true) db.actor:kill(db.actor) 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 function CSurgeManager:turn_to_zombie(se_obj,squad) if not (squad) then se_obj:kill() return end self.zombie_count = self.zombie_count and self.zombie_count + 1 or 0 if (self.zombie_count > 12) then se_obj:kill() return end local zombie_type local section_number = string.sub(se_obj:section_name(), -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 squad:remove_npc(se_obj.id, true) alife_create(zombie_type,se_obj.position,se_obj.m_level_vertex_id,se_obj.m_game_vertex_id) end function CSurgeManager:explode(se_obj,squad) if not (squad) then se_obj:kill() return end -- play body tear and scary sound self.body_tears[se_obj.id]=particles_object("anomaly2\\body_tear_0"..math.random(1,2)) self.body_tears[se_obj.id]:play_at_pos(se_obj.position) local snd_obj = self.blowout_sounds["body_tear"] if (snd_obj) then if (snd_obj:playing()) then snd_obj:stop() end snd_obj:play_at_pos(db.actor, se_obj.position) snd_obj.volume = 1 end squad:remove_npc(se_obj.id, true) end ---------------------------------- -- Task ---------------------------------- function CSurgeManager:give_surge_hide_task() if (self.surge_message ~= "empty") then local mess = "" if (self.surge_message == "") then local time = 0 mess = game.translate_string("hide_from_surge_message") else mess = game.translate_string(self.surge_message) end end if (self.surge_task_sect ~= "empty") then if (self.surge_task_sect == "") then task_manager.get_task_manager():give_task("hide_from_surge") else task_manager.get_task_manager():give_task(self.surge_task_sect) end end end function get_task_descr() if GetEvent("current_safe_cover") then return game.translate_string("hide_from_surge_descr_2_a") end return game.translate_string("hide_from_surge_descr_1_a") end function get_task_target() if GetEvent("current_safe_cover") then return nil end return GetEvent("nearest_safe_cover") end function set_surge_task(tsk) get_surge_manager().surge_task_sect = tsk end ---------------------------------- -- Data management ---------------------------------- function actor_on_save(binder,packet) if (USE_MARSHAL) then return end -- initialize to set default values if not loaded local mgr = SurgeManager if not (mgr._state_loaded) then mgr:initialize() mgr._state_loaded = true end set_save_marker(packet, "save", false, "SurgeHide") utils_data.w_stpk(packet,"bool",mgr.finished,"CSurgeManager:finished") utils_data.w_stpk(packet,"bool",mgr.started,"CSurgeManager:started") utils_data.w_stpk(packet,"CTime",mgr.last_surge_time,"CSurgeManager:last_surge_time") if(mgr.started) then utils_data.w_stpk(packet,"CTime",mgr.inited_time,"CSurgeManager:inited_time") utils_data.w_stpk(packet,"bool",mgr.task_given,"CSurgeManager:task_given") utils_data.w_stpk(packet,"bool",mgr.effector_set,"CSurgeManager:effector_set") utils_data.w_stpk(packet,"bool",mgr.second_message_given,"CSurgeManager:second_message_given") utils_data.w_stpk(packet,"bool",mgr.ui_disabled,"CSurgeManager:ui_disabled") utils_data.w_stpk(packet,"bool",mgr.blowout_sound,"CSurgeManager:blowout_sound") --utils_data.w_stpk(packet,"stringZ",mgr.surge_message,"CSurgeManager:surge_message") --utils_data.w_stpk(packet,"stringZ",mgr.surge_task_sect,"CSurgeManager:surge_task_sect") utils_data.w_stpk(packet,"u32",mgr.game_time_factor,"CSurgeManager:game_time_factor") end utils_data.w_stpk(packet,"u32",mgr._delta,"CSurgeManager:_delta") set_save_marker(packet, "save", true, "SurgeHide") end function actor_on_load(binder,packet) --printf("actor on load") local mgr = get_surge_manager() if not (mgr._state_loaded) then mgr:initialize() mgr._state_loaded = true end if (USE_MARSHAL) then return end set_save_marker(packet, "load", false, "SurgeHide") mgr.finished = packet:r_bool() mgr.started = packet:r_bool() mgr.last_surge_time = utils_data.r_CTime(packet,"surge_manager") or game.get_game_time() if(mgr.started) then mgr.inited_time = utils_data.r_CTime(packet,"surge_manager") or game.get_game_time() mgr.task_given = packet:r_bool() mgr.effector_set = packet:r_bool() mgr.second_message_given = packet:r_bool() mgr.ui_disabled = packet:r_bool() mgr.blowout_sound = packet:r_bool() --mgr.surge_message = packet:r_stringZ() --mgr.surge_task_sect = packet:r_stringZ() mgr.game_time_factor = packet:r_u32() mgr:finalize() mgr.blowout_waves = empty_table(mgr.blowout_waves) mgr.objects_to_kill = empty_table(mgr.objects_to_kill) mgr.stages = empty_table(mgr.stages) mgr.body_tears = empty_table(mgr.body_tears) end mgr._delta = packet:r_u32() set_save_marker(packet, "load", true, "SurgeHide") end function save_state(m_data) --utils_data.debug_write("SurgeManager:save_state BEFORE") m_data.SurgeManager = {} local mgr = get_surge_manager() if not (mgr._state_loaded) then mgr:initialize() mgr._state_loaded = true end m_data.SurgeManager.finished = mgr.finished == nil and true or mgr.finished m_data.SurgeManager.started = mgr.started == nil and false or mgr.started m_data.SurgeManager.last_surge_time = mgr.last_surge_time and utils_data.CTime_to_table(mgr.last_surge_time) or game.get_game_time() if(mgr.started) then m_data.SurgeManager.inited_time = utils_data.CTime_to_table(mgr.inited_time) or game.get_game_time() --m_data.SurgeManager.levels_respawn = mgr.levels_respawn m_data.SurgeManager.task_given = mgr.task_given m_data.SurgeManager.effector_set = mgr.effector_set m_data.SurgeManager.second_message_given = mgr.second_message_given m_data.SurgeManager.ui_disabled = mgr.ui_disabled m_data.SurgeManager.blowout_sound = mgr.blowout_sound m_data.SurgeManager.game_time_factor = mgr.game_time_factor end m_data.SurgeManager._delta = mgr._delta --utils_data.debug_write("SurgeManager:save_state AFTER") end function load_state(m_data) if not (m_data.SurgeManager) then return end --utils_data.debug_write("SurgeManager:load_state BEFORE") local mgr = get_surge_manager() mgr:initialize() mgr.finished = m_data.SurgeManager.finished mgr.started = m_data.SurgeManager.started mgr.last_surge_time = m_data.SurgeManager.last_surge_time and utils_data.CTime_from_table(m_data.SurgeManager.last_surge_time) or game.get_game_time() if (mgr.started == true and mgr.finished == false) then mgr.inited_time = m_data.SurgeManager.inited_time and utils_data.CTime_from_table(m_data.SurgeManager.inited_time) or game.get_game_time() mgr.task_given = m_data.SurgeManager.task_given or false mgr.effector_set = m_data.SurgeManager.effector_set or false mgr.second_message_given = m_data.SurgeManager.second_message_given or false mgr.ui_disabled = m_data.SurgeManager.ui_disabled or false mgr.blowout_sound = m_data.SurgeManager.blowout_sound or false mgr.game_time_factor = m_data.SurgeManager.game_time_factor or level.get_time_factor() mgr:finalize() mgr.blowout_waves = empty_table(mgr.blowout_waves) mgr.objects_to_kill = empty_table(mgr.objects_to_kill) mgr.stages = empty_table(mgr.stages) mgr.body_tears = empty_table(mgr.body_tears) else mgr.started = false mgr.finished = true end mgr._delta = m_data.SurgeManager._delta mgr._state_loaded = true m_data.SurgeManager = nil --utils_data.debug_write("SurgeManager:load_state BEFORE") end ---------------------------------- -- Utilities ---------------------------------- function start_surge(p) get_surge_manager():start(true) end function stop_surge() if(get_surge_manager().started) then get_surge_manager():end_surge(true) end end function is_started() return get_surge_manager().started end function is_finished() return not get_surge_manager().started end function is_loaded() return get_surge_manager()._state_loaded == true end function actor_in_cover() return GetEvent("current_safe_cover") and true or false end function npc_in_cover(npc) return get_surge_manager():pos_in_cover(npc:position()) end function job_in_surge_cover(se_obj,job) if not (job.alife_task) then return false end return get_surge_manager():pos_in_cover(job.alife_task:position()) end function set_surge_message(mess) get_surge_manager().surge_message = mess end function is_killing_all() local mgr = get_surge_manager() if(mgr.started and mgr.ui_disabled) then return true end return false end function sound_started() return get_surge_manager().started and get_surge_manager().blowout_sound end