-- Adapted the debugger code function spawn_at_position(section, position_vector, lvid, gvid, is_squad, angle, is_anomaly) local se_obj = alife_create(section, position_vector, lvid, gvid) if is_squad then se_obj:create_npc(nil, position_vector, lvid, gvid) local sim = alife() for k in se_obj:squad_members() do local se_npc = k.object or k.id and sim:object(k.id) if (se_npc) then SIMBOARD:setup_squad_and_group(se_npc) SendScriptCallback("squad_on_npc_creation",se_obj,se_npc) end end end if angle then se_obj.angle = angle end if is_anomaly then local data = utils_stpk.get_object_data(se_obj) if (data) then data.object_flags = 31 data.restrictor_type = 0 data.shapes = {} data.shapes[1] = {} data.shapes[1].shtype = 0 data.shapes[1].offset = VEC_ZERO data.shapes[1].radius = 10 utils_stpk.set_object_data(data,se_obj) end end return se_obj.id end -- TODO: remove second param - it's cancer -- Second param is mainly used for loop spawning to not have same sections defined in configs function spawn_helper(spawn_config, section_override) return spawn_at_position( spawn_config.section or section_override, spawn_config.vector, spawn_config.lvid, spawn_config.gvid, spawn_config.is_squad, spawn_config.angle, spawn_config.is_anomaly ) end function is_dark_night () return level.get_time_hours() <= 3 or level.get_time_hours() >= 22 end function spawn_helicopter(is_strong, pos, lvid, gvid) local heli = "new_tasks_addon_heli_" .. (is_strong and "strong" or "weak") local se_obj = alife_create(heli, pos, lvid, gvid) local visual = utils_data.cfg_get_string(ini_sys, heli,"visual", se_obj, false) local data = utils_stpk.get_heli_data(se_obj) if (data) then data.visual_name = visual and visual ~= "" and visual or [[dynamics\vehicles\mi2\veh_mi2_01]] data.motion_name = [[helicopter\aaa.anm]] data.startup_animation = "idle" data.skeleton_name = "idle" data.engine_sound = [[vehicles\helicopter\helicopter]] utils_stpk.set_heli_data(data, se_obj) else safe_release_manager.release(se_obj) end return se_obj.id end function immediate_explosion(actor,obj) if (obj) then obj:explode(0) end end function noop() end function find_index(tab, val) for index, value in ipairs(tab) do if value == val then return index end end return -1 end function has_value(tab, val) for index, value in ipairs(tab) do if value == val then return true end end return false end function shallow_copy(t) local res = {} for k,v in pairs(t) do res[k] = v end return res end -- No invalid range check - expect to receive the right input function rand_with_exclusion(min, max, exclude) local t = {} for i = min, max do if i ~= exclude then table.insert(t, i) end end local rand_i = math.random(#t) return t[rand_i] end function is_strike(shit) -- IDK why but for some reason hit.strike comes back as 7 sometimes. Something's really fucked up return shit.type == 5 end function is_axe() local item = db.actor:active_item() return item and string.find(item:section(), "axe") end function is_melee(item) return string.find(item:section(), "axe") or string.find(item:section(), "knife") end function teleport_visual() level.add_pp_effector ("teleport.ppe", 2006, false) local snd_obj = sound_object("affects\\tinnitus3a") snd_obj:play_no_feedback(db.actor, sound_object.s2d, 0, VEC_ZERO, 1.0, 1.0) end -- Used to push dead bodies that should disappear below the textures to avoid errors caused by on_death callbacks from other mods function hide_through_teleport(id) CreateTimeEvent(0,"nta_hide_body_teleport_" .. id,0, function () local obj = level.object_by_id(id) local pos = obj:position() pos.y = pos.y - 40 obj:force_set_position(pos, false) return true end) end function spawn_companion_squad(sq_section, vector, lvid, gvid) local id = spawn_at_position(sq_section, vector, lvid, gvid, true) local squad = alife_object(id) axr_companions.companion_squads[squad.id] = squad for k in squad:squad_members() do local se_obj = k.object or k.id and sim:object(k.id) if (se_obj) then se_save_var(se_obj.id,se_obj:name(),"companion",true) se_save_var(se_obj.id,se_obj:name(),"companion_cannot_dismiss",true) SIMBOARD:setup_squad_and_group(se_obj) end end -- Add to ignore offline combat simulation list sim_offline_combat.task_squads[squad.id] = true return id end function squad_alive(id) local sim = alife() local squad = sim:object(id) local alive = false for k in squad:squad_members() do local se_npc = k.object or k.id and sim:object(k.id) if (se_npc:alive()) then alive = true end end return alive end -- Excluded Bar southern_maps = { "k00_marsh", "k01_darkscape", "k02_trucks_cemetery", "l01_escape", "l02_garbage", "l03_agroprom", "l04_darkvalley", "l06_rostok", "l07_military", "l08_yantar", "l09_deadcity", "y04_pole", } nothern_maps = { "l10_red_forest", "jupiter", "pripyat", "zaton", "l13_generators", "l12_stancia_2", "l12_stancia", "l11_pripyat", "l10_radar", } sim_stalkers = nil function prefetch_sim_stalkers() sim_stalkers = {} for i = 1, 65534 do local se_obj = alife_object(i) if se_obj and (IsStalker(nil,se_obj:clsid()) and se_obj:alive() and string.find(se_obj:section_name(),"sim_default") and get_object_story_id(id) == nil) and (se_obj.group_id ~= 65535 and get_object_story_id(se_obj.group_id) == nil) then local comm = alife_character_community(se_obj) if not sim_stalkers[comm] then sim_stalkers[comm] = {} end table.insert(sim_stalkers[comm], se_obj.id) end end end function find_random_stalker(factions, maps) local limit = 60 -- Check 60 random stalkers at most and make it completely random for i = 1, limit do local faction = factions[math.random(1, #factions)] local faction_stalkers = sim_stalkers[faction] -- It might happen that there's no stalker of a given faction on the map and the entry for that faction won't be created if faction_stalkers then local stalker_id = faction_stalkers[math.random(1, #faction_stalkers)] local se_obj = alife_object(stalker_id) if se_obj then local level = get_object_level_id(se_obj) if (not maps or has_value(maps, level)) and IsStalker(nil,se_obj:clsid()) and se_obj:alive() and alife_character_community(se_obj) == faction then return { id = stalker_id, level = level, faction = faction, name = se_obj:character_name() } end end end end end function get_object_level_id(se_obj) local gg = game_graph() local sim = alife() return sim:level_name(gg:vertex(se_obj.m_game_vertex_id):level_id()) end local earthquake_cam_eff = 3 function earthquake_screen_effect_gradual(duration_multiplier) local phase_duration_multiplier = duration_multiplier or 2 local effector_names = { "camera_effects\\earthquake_20.anm", "camera_effects\\earthquake_40.anm", "camera_effects\\earthquake_60.anm", "camera_effects\\earthquake_80.anm", "camera_effects\\earthquake.anm", "camera_effects\\earthquake_80.anm", "camera_effects\\earthquake_60.anm", "camera_effects\\earthquake_40.anm", "camera_effects\\earthquake_20.anm" } for index, name in ipairs(effector_names) do CreateTimeEvent(0,"nta_earthquake_screen_" .. index, (index - 1) * phase_duration_multiplier, function () level.remove_cam_effector(earthquake_cam_eff) level.add_cam_effector(name, earthquake_cam_eff, true, "", 0, false) return true end) end CreateTimeEvent(0,"nta_earthquake_screen_remove", #effector_names * phase_duration_multiplier, function () level.remove_cam_effector(earthquake_cam_eff) return true end) end function earthquake_screen_effect_strong(duration) level.add_cam_effector("camera_effects\\earthquake.anm", earthquake_cam_eff, true, "", 0, false) CreateTimeEvent(0,"nta_earthquake_screen_remove", duration or 6, function () level.remove_cam_effector(earthquake_cam_eff) return true end) end function actor_in_range(vector, dist) return db.actor:position():distance_to(vector) < dist end function actor_icon() return db.actor:character_icon() end function actor_name() return db.actor:character_name() end function obj_position_to_spawn_config_partial(obj) return { vector = obj:position(), lvid = obj:level_vertex_id(), gvid = obj:game_vertex_id() } end levels = { swamp = "k00_marsh", darkscape = "k01_darkscape", truck_cemetery = "k02_trucks_cemetery", cordon = "l01_escape", garbage = "l02_garbage", agroprom = "l03_agroprom", dark_valley = "l04_darkvalley", wild_territory = "l06_rostok", army_warehouses = "l07_military", yantar = "l08_yantar", dead_city = "l09_deadcity", meadow = "y04_pole", x16 = 'l08u_brainlab', x18 = 'l04u_labx18', red_forest = 'l10_red_forest', outskirts = 'pripyat' } -- TODO: Remove separate functions from task files and use this one instead function actor_on_level(lvl) return level.name() == lvl end local function load_defaults() local t = {} local op = new_tasks_addon_mcm.op for _, v in ipairs(op.gr) do if v.def ~= nil then t[v.id] = v.def end end return t end mcm_config = load_defaults() local function load_settings() mcm_config = load_defaults() if ui_mcm then for k, v in pairs(mcm_config) do mcm_config[k] = ui_mcm.get("new_tasks_addon/" .. k) end end end xr_effects.dispatch_nta_task_details = function(actor, npc, p) CreateTimeEvent(0,"nta_task_details",0, function () local task_id = p[1] -- Build News local news_caption = game.translate_string(task_manager.task_ini:r_string_ex(task_id, "title")) or "error" local news_text = game.translate_string(task_manager.task_ini:r_string_ex(task_id, "nta_task_details")) or "" local news_ico = task_manager.task_ini:r_string_ex(task_id, "icon") db.actor:give_talk_message2(news_caption, news_text, news_ico, "iconed_answer_item") return true end) end xr_conditions.check_nta_replayability = function(actor, npc, p) local task_id = p[1] if not db.actor:has_info(task_id .. '_completed') then return true else return mcm_config["repl_" .. task_id] end end function check_nta_auto_assignment(task_id) return mcm_config["auto_assignment_" .. task_id] end function actor_on_first_update() prefetch_sim_stalkers() end add_console_command("chopper", function() se_id = spawn_helicopter(true, vector():set(-178.07975769043,5.3180623054504,-181.78283691406)) end) function change_level(configs) change_level_now(configs.vector, configs.lvid, configs.gvid, configs.angle or vector():set(0, 0, 0)) end function on_game_start() RegisterScriptCallback("on_game_load", load_settings) RegisterScriptCallback("on_option_change", load_settings) RegisterScriptCallback("actor_on_first_update",actor_on_first_update) end