--[[ Heavily modified by Utjan Kits are seperated from the normal spawn system and has it's own more customisable system Pulls min/max kit spawns for each map from barry_kit_spawns.ltx ]]-- --[[ - Created by tdef - Updated by Tronex - Randomized world items on new game - Released blacklisted objects on new game - Created: 2018/10/27 - 2019/31/3 script now read from config to set up - 2019/4/25 objects to release are now handled by another config - 2019/5/20 improved the way suffled consumables uses are set used ini: items\settings\dynamic_item_spawn.ltx plugins\new_game_setup.ltx set enable_debug to true, for debugging and map markers --]] -- these vehicles are supposed to shoot at you but call of misery broke them so they don't -- also you can board them, turn them on and drive around so should remove them? local ini_dyn local enable_debug = false local inited = false local sfind = string.find local world_itm_info = {} -- [name] = {} local world_itm_off = {} -- [name] = true local world_itm_num = {} -- [name] = num local world_itm_on = {} -- [id] = name local ini_kits -- barry_kit_spawns.ltx local world_kit_off = {} -- Kit spawn points with no kit local world_kit_on = {} -- Kit spawn points with a kit local world_upg_kit_on = {} -- Kit spawn points with an upgrade kit local min_kit_dist -- Minimum distance between kit spawns local dist_exclude_table = {} -- Table used to temporarily store spawn points excluded by the minimum distance mechanic local level_exclude_table = {} -- Used to exclude certain maps from having kits respawned unto local itm_list = {} local limited_uses = {} function get_itm_type(name) if sfind(name,"kolbasa") or sfind(name,"conserva") or sfind(name,"bread") then return "food" end if sfind(name,"energy") or sfind(name,"vodka") or sfind(name,"drink") then return "drink" end if sfind(name,"drug") or sfind(name,"antirad") or sfind(name,"bandage") or sfind(name,"medkit") then return "medical" end --if sfind(name,"repair") then --return "tool" --end if sfind(name,"ammo") then return "ammo" end if sfind(name,"misc") then return "misc" end return "NA" end function print_debug(...) if enable_debug then printf(...) end end local marker_by_type = { ["kit"] = "item_kit", ["medical"] = "item_medical", ["food"] = "item_food", ["drink"] = "item_drink", ["ammo"] = "item_ammo", ["misc"] = "item_misc", } function add_marker(name, section, id, typ) if enable_debug then local spot = marker_by_type[typ] or marker_by_type["misc"] level.map_add_object_spot_ser(id, spot, "Name: " .. name .. " \\nType: " .. typ .. " \\nSection: " .. section) end end function remove_marker(id, typ) if enable_debug then local spot = marker_by_type[typ] or marker_by_type["misc"] if (level.map_has_object_spot(id, spot) ~= 0) then level.map_remove_object_spot(id, spot) end end end function init_settings() if (inited) then return end inited = true ini_dyn = ini_file("items\\settings\\dynamic_item_spawn.ltx") ini_kits = ini_file("items\\settings\\barry_kit_spawns.ltx") local n,m = 0,0 local result, id, value = "","","" local name, info = "","","" -- Gather items list n = ini_dyn:line_count("categories") or 0 for i=0,n-1 do result, id, value = ini_dyn:r_line_ex("categories",i,"","") itm_list[id] = {} m = ini_dyn:line_count(id) or 0 for ii=0,m-1 do result, name, info = ini_dyn:r_line_ex(id,ii,"","") if name and info then for j=1,tonumber(info) do local size = #itm_list[id] + 1 itm_list[id][size] = name print_debug("- Game Setup | itm_list[%s][%s] = %s", id, size, name) end end end end -- Gather recorded items pos n = ini_dyn:line_count("levels") or 0 for i=0,n-1 do result, id, value = ini_dyn:r_line_ex("levels",i,"","") world_kit_off[id] = {} -- make table of levels if not world_kit_on[id] then world_kit_on[id] = {} -- make table of levels if it's not loaded from save end if not world_upg_kit_on[id] then world_upg_kit_on[id] = {} end m = ini_dyn:line_count(id) or 0 for ii=0,m-1 do result, name, info = ini_dyn:r_line_ex(id,ii,"","") if name and info then local t = str_explode(info,",") if (#t == 6) and (t[1] ~= "NA") then world_itm_info[name] = { typ = t[1], x = tonumber(t[2]), y = tonumber(t[3]), z = tonumber(t[4]), lvl_id = tonumber(t[5]), gm_id = tonumber(t[6]), } if sfind(t[1], "kit") then -- if item is kit world_kit_off[id][name] = true -- add kit to world kit list else world_itm_off[name] = true end end end end end -- Gather uses n = ini_dyn:line_count("possible_uses") or 0 for i=0,n-1 do result, id, value = ini_dyn:r_line_ex("possible_uses",i,"","") if id and value then local t = str_explode(value,",") limited_uses[id] = { tonumber(t[1]) or 1 , tonumber(t[2]) or 1 } end end -- Gather respawn exclude list n = ini_kits:line_count("kit_respawn_exclude") or 0 for i=0,n-1 do result, id, value = ini_kits:r_line_ex("kit_respawn_exclude",i,"","") level_exclude_table[id] = true end for id,name in pairs(world_itm_on) do world_itm_off[name] = nil end for level, kit_table in pairs(world_kit_on) do for spawn_name, v in pairs(kit_table) do world_kit_off[level][spawn_name] = nil end end for level, kit_table in pairs(world_upg_kit_on) do for spawn_name, v in pairs(kit_table) do world_kit_off[level][spawn_name] = nil end end print_debug("- Game Setup | world_itm_info: %s - world_itm_on: %s - world_itm_off: %s", size_table(world_itm_info), size_table(world_itm_on), size_table(world_itm_off)) --print_debug("- Game Setup KITS | world_kit_on: %s - world_kit_off: %s", size_table(world_kit_on), size_table(world_kit_off)) end function try_spawn_world_item(ignore) -- Get spawn place name local _name if ignore then if not (world_itm_off and size_table(world_itm_off) > 0) then print_debug("! Game Setup | world_itm_off is nil or empty") return end _name = random_key_table(world_itm_off) else local lvl_short = txr_routes.get_map(level.name()) local t = {} -- Gather validated item places to spawn at for name,_ in pairs(world_itm_off) do if (not sfind(name,lvl_short)) then t[#t+1] = name end end _name = (#t > 0) and t[math.random(#t)] if _name then printf("Respawning non-kit item: " .. _name) end end -- Return if not available place has been found if (not _name) then print_debug("! Game Setup | can't find available item place", _name) return end -- Return if place already has spawned item for id,name in pairs(world_itm_on) do if (name == _name) then print_debug("! Game Setup | place {%s} is already occupied", _name) return end end -- Get info local info = world_itm_info[_name] if (not info) then print_debug("! Game Setup | no info is found for {%s}", _name) return end -- Get section local itm_type = info.typ and itm_list[info.typ] local section = itm_type and itm_type[math.random(#itm_type)] if (not section) then print_debug("! Game Setup | couldn't get section [%s] for type (%s)", section, info.typ) return end if (not ini_sys:section_exist(section)) then print_debug("! Game Setup | section [%s] doesn't exist", section) return end -- Info check if not (info.x and info.y and info.z and info.lvl_id and info.gm_id and true) then print_debug("! Game Setup | item {%s} has wrong or incomplete info", _name) return end -- Spawn and adjust uses/condition/ammo size if IsItem("ammo",section) then local pos = vector():set(info.x, info.y, info.z) local se_obj = alife_create_item(section, {pos, info.lvl_id, info.gm_id}) if se_obj then add_marker(_name, section, se_obj.id, info.typ) world_itm_on[se_obj.id] = _name world_itm_off[_name] = nil local box_size = ini_sys:r_u32(section, "box_size") world_itm_num[_name] = math.random( math.ceil(box_size * 0.25) , math.ceil(box_size * 0.75) ) print_debug("/ Game Setup | created ammo [%s](%s) - place: %s - size = %s", section, se_obj.id, _name, world_itm_num[_name]) else print_debug("! Game Setup | ammo [%s] couldn't be created", section) end else local pos = vector():set(info.x, info.y, info.z) local se_obj = alife_create_item(section, {pos, info.lvl_id, info.gm_id}) if se_obj then add_marker(_name, section, se_obj.id, info.typ) world_itm_on[se_obj.id] = _name world_itm_off[_name] = nil -- Multi-use if limited_uses[section] then world_itm_num[_name] = math.random(limited_uses[section][1], limited_uses[section][2]) print_debug("/ Game Setup | created multiuse item [%s](%s) - place: %s - uses = %s", section, se_obj.id, _name, world_itm_num[_name]) else local is_using_con = utils_item.is_degradable(nil, section) if is_using_con then -- Parts if IsItem("part",section) then world_itm_num[_name] = random_choice(0.5,0.75,1) print_debug("/ Game Setup | created degraded item [%s](%s) - place: %s - con = %s", section, se_obj.id, _name, world_itm_num[_name]) -- Degradable items else world_itm_num[_name] = (math.random(30,70)/100) print_debug("/ Game Setup | created degraded item [%s](%s) - place: %s - con = %s", section, se_obj.id, _name, world_itm_num[_name]) end else print_debug("/ Game Setup | created item [%s](%s)", section, se_obj.id) end end else print_debug("! Game Setup | item [%s] couldn't be created", section) end end end function try_spawn_world_item_kit(level_name, ignore) -- Get spawn place name local _name if ignore then if not (world_kit_off[level_name] and size_table(world_kit_off[level_name]) > 0) then print_debug("! Game Setup | world_itm_off is nil or empty") return end _name = random_key_table(world_kit_off[level_name]) else _name = find_kit_respawn_name(level_name) end -- Return if not available place has been found if (not _name) then print_debug("! Game Setup | can't find available item place", _name) return end -- Return if place already has spawned item if world_kit_on[level_name] then for id,name in pairs(world_kit_on[level_name]) do if (name == _name) then print_debug("! Game Setup | place {%s} is already occupied", _name) return end end end -- Get info local info = world_itm_info[_name] if (not info) then print_debug("! Game Setup | no info is found for {%s}", _name) return end -- Get section local itm_type = info.typ and itm_list[info.typ] local section = itm_type and itm_type[math.random(#itm_type)] if (not section) then print_debug("! Game Setup | couldn't get section [%s] for type (%s)", section, info.typ) return end if (not ini_sys:section_exist(section)) then print_debug("! Game Setup | section [%s] doesn't exist", section) return end -- Info check if not (info.x and info.y and info.z and info.lvl_id and info.gm_id and true) then print_debug("! Game Setup | item {%s} has wrong or incomplete info", _name) return end -- Check if trying to spawn too close to other kit local pos = vector():set(info.x, info.y, info.z) if ignore then for id, kit_name in pairs(world_kit_on[level_name]) do local o_info = world_itm_info[kit_name] local o_pos = vector():set(o_info.x, o_info.y, o_info.z) if pos:distance_to(o_pos) <= min_kit_dist then dist_exclude_table[level_name][_name] = true world_kit_off[level_name][_name] = nil return "too close" end end end -- Spawn and adjust uses local se_obj = alife_create_item(section, {pos, info.lvl_id, info.gm_id}) if se_obj then add_marker(_name, section, se_obj.id, info.typ) world_kit_on[level_name][se_obj.id] = _name world_kit_off[level_name][_name] = nil -- Multi-use if limited_uses[section] then world_itm_num[_name] = math.random(limited_uses[section][1], limited_uses[section][2]) print_debug("/ Game Setup | created multiuse item [%s](%s) - place: %s - uses = %s", section, se_obj.id, _name, world_itm_num[_name]) else print_debug("/ Game Setup | created item [%s](%s) - place: %s", section, se_obj.id, _name) end else print_debug("! Game Setup | item [%s] couldn't be created", section) end end function try_spawn_world_item_kit_upg(level_name, ignore) -- Get spawn place name local _name if ignore then if not (world_kit_off[level_name] and size_table(world_kit_off[level_name]) > 0) then print_debug("! Game Setup | world_itm_off is nil or empty") return end _name = random_key_table(world_kit_off[level_name]) else _name = find_kit_respawn_name(level_name) end -- Return if not available place has been found if (not _name) then print_debug("! Game Setup | can't find available item place", _name) return end -- Return if place already has spawned item if world_upg_kit_on[level_name] then for id,name in pairs(world_upg_kit_on[level_name]) do if (name == _name) then print_debug("! Game Setup | place {%s} is already occupied", _name) return end end end -- Get info local info = world_itm_info[_name] if (not info) then print_debug("! Game Setup | no info is found for {%s}", _name) return end -- Get section local itm_type = itm_list["kit_upgrade"] if _G["kit_binder"] then itm_type = itm_list["kit_upg_streamlined"] end local section = itm_type and itm_type[math.random(#itm_type)] if (not section) then print_debug("! Game Setup | couldn't get section [%s] for type (%s)", section, info.typ) return end if (not ini_sys:section_exist(section)) then print_debug("! Game Setup | section [%s] doesn't exist", section) return end -- Info check if not (info.x and info.y and info.z and info.lvl_id and info.gm_id and true) then print_debug("! Game Setup | item {%s} has wrong or incomplete info", _name) return end -- Check if trying to spawn too close to other kit local pos = vector():set(info.x, info.y, info.z) if ignore then for id, kit_name in pairs(world_kit_on[level_name]) do local o_info = world_itm_info[kit_name] local o_pos = vector():set(o_info.x, o_info.y, o_info.z) if pos:distance_to(o_pos) <= min_kit_dist then dist_exclude_table[level_name][_name] = true world_kit_off[level_name][_name] = nil return "too close" end end for id, kit_name in pairs(world_upg_kit_on[level_name]) do local o_info = world_itm_info[kit_name] local o_pos = vector():set(o_info.x, o_info.y, o_info.z) if pos:distance_to(o_pos) <= min_kit_dist then dist_exclude_table[level_name][_name] = true world_kit_off[level_name][_name] = nil return "too close" end end end -- Spawn and adjust uses local se_obj = alife_create_item(section, {pos, info.lvl_id, info.gm_id}) if se_obj then add_marker(_name, section, se_obj.id, info.typ) world_upg_kit_on[level_name][se_obj.id] = _name world_kit_off[level_name][_name] = nil local is_using_con = utils_item.is_degradable(nil, section) -- Multi-use if limited_uses[section] and not is_using_con then world_itm_num[_name] = math.random(limited_uses[section][1], limited_uses[section][2]) print_debug("/ Game Setup | created multiuse item [%s](%s) - place: %s - uses = %s", section, se_obj.id, _name, world_itm_num[_name]) else if is_using_con and limited_uses[section] then -- Degradable items world_itm_num[_name] = math.random(limited_uses[section][1], limited_uses[section][2])/100 print_debug("/ Game Setup | created degraded item [%s](%s) - place: %s - con = %s", section, se_obj.id, _name, world_itm_num[_name]) else print_debug("/ Game Setup | created item [%s](%s) - place: %s", section, se_obj.id, _name) end end else print_debug("! Game Setup | item [%s] couldn't be created", section) end end function spawn_guaranteed_kit(level_name, _name, section) if (not _name) then print_debug("Name not found") return end -- Return if place already has spawned item if world_kit_on[level_name] then for id,name in pairs(world_kit_on[level_name]) do if (name == _name) then print_debug("Guaranteed spawn occupied") return end end end -- Get info local info = world_itm_info[_name] if (not info) then print_debug("Info not found for .. " .. _name) return end if (not section) then print_debug("Section not found for " .. _name) return end if (not ini_sys:section_exist(section)) then print_debug("Section " .. section .. " not in ini for " .. _name) return end -- Info check if not (info.x and info.y and info.z and info.lvl_id and info.gm_id and true) then print_debug("! Game Setup | item {%s} has wrong or incomplete info", _name) return end -- Spawn and adjust uses/condition/ammo size local pos = vector():set(info.x, info.y, info.z) local se_obj = alife_create_item(section, {pos, info.lvl_id, info.gm_id}) if se_obj then add_marker(_name, section, se_obj.id, info.typ) world_kit_on[level_name][se_obj.id] = _name world_kit_off[level_name][_name] = nil --[[ -- Multi-use if limited_uses[section] then world_itm_num[_name] = math.random(limited_uses[section][1], limited_uses[section][2]) --printf("Num: " .. world_itm_num[_name]) print_debug("/ Game Setup | created multiuse item [%s](%s) - place: %s - uses = %s", section, se_obj.id, _name, world_itm_num[_name]) end ]]-- else print_debug("! Game Setup | item [%s] couldn't be created", section) end end function reset() for level, kits in pairs(world_upg_kit_on) do for id, spawn_name in pairs(kits) do alife_release_id(id) end end for level, kits in pairs(world_kit_on) do for id, spawn_name in pairs(kits) do alife_release_id(id) end end for id, spawn_name in pairs(world_itm_on) do alife_release_id(id) end world_upg_kit_on = {} world_itm_num = {} world_kit_on = {} world_itm_on = {} world_kit_off = {} world_itm_off = {} inited = false init_settings() create_world_itms() --create_guaranteed_itms() create_world_kits() create_world_kits_upg() news_manager.send_tip(db.actor, string.format("Kit Spawn Rework: Kit spawn locations have been reset!"), 0, nil, 10000) end function find_kit_respawn_name(level_name) local t = {} -- Gather validated item places to spawn at for level, kits in pairs(world_kit_off) do if (size_table(kits) > 0) and not(level_name == level or level_exclude_table[level]) then t[level] = {} for name, _ in pairs(kits) do local key = size_table(t[level]) + 1 t[level][key] = name end end end _rand_level = random_key_table(t) _rand_kit = random_key_table(t[_rand_level]) return t[_rand_level][_rand_kit] end function create_world_itms() local multi = game_difficulties.get_eco_factor("random_items") or 0.5 -- ZCP compatibility code if smr_amain_mcm and smr_amain_mcm.get_config("smr_enabled") then multi = smr_loot_mcm.get_config("random_items") end -- ZCP END multi = (multi < 1) and multi or 1 local num = math.ceil(size_table(world_itm_off) * multi) for i=1,num do try_spawn_world_item(true) end end function create_guaranteed_itms() local guaranteed_tags = {} local n = ini_kits:line_count("tags_guaranteed") or 0 for i=0,n-1 do result, tag, item_section = ini_kits:r_line_ex("tags_guaranteed",i,"","") guaranteed_tags[tag] = item_section end for level_name, kit_table in pairs(world_kit_off) do for kit, v in pairs(kit_table) do for tag, section in pairs(guaranteed_tags) do if sfind(kit, tag) then spawn_guaranteed_kit(level_name, kit, section) end end end end end function create_world_kits() min_kit_dist = tonumber(ini_kits:r_string_ex("settings","min_kit_distance")) local min_kit_level_list = {} local max_kit_level_list = {} local n = ini_kits:line_count("kit_spawn_counts") or 0 for i=0,n-1 do result, level_name, value = ini_kits:r_line_ex("kit_spawn_counts",i,"","") local t = str_explode(value,",") local min_value = worldspawns_rework_mcm.get_config(level_name .. "_min") or t[1] local max_value = worldspawns_rework_mcm.get_config(level_name .. "_max") or t[2] min_kit_level_list[level_name] = math.min(min_value, max_value) max_kit_level_list[level_name] = math.max(min_value, max_value) end for level_name, v in pairs(world_kit_off) do local kit_spawn_count = math.min(math.random(min_kit_level_list[level_name], max_kit_level_list[level_name]), size_table(world_kit_off[level_name])) dist_exclude_table[level_name] = {} for i=1, kit_spawn_count do local result = try_spawn_world_item_kit(level_name, true) while result and result == "too close" and size_table(world_kit_off[level_name]) > 0 do result = try_spawn_world_item_kit(level_name, true) end if is_empty(world_kit_off[level_name]) then break end end for kit_name, v in pairs(dist_exclude_table[level_name]) do world_kit_off[level_name][kit_name] = true end dist_exclude_table[level_name] = {} end end function create_world_kits_upg() local min_upg_kit_level_list = {} local max_upg_kit_level_list = {} local n = ini_kits:line_count("upg_kit_spawn_counts") or 0 for i=0,n-1 do result, level_name, value = ini_kits:r_line_ex("upg_kit_spawn_counts",i,"","") local t = str_explode(value,",") local min_value = worldspawns_rework_mcm.get_config(level_name .. "_upg_min") or t[1] local max_value = worldspawns_rework_mcm.get_config(level_name .. "_upg_max") or t[2] min_upg_kit_level_list[level_name] = math.min(min_value, max_value) max_upg_kit_level_list[level_name] = math.max(min_value, max_value) end for level_name, v in pairs(world_kit_off) do local kit_spawn_count = math.min(math.random(min_upg_kit_level_list[level_name], max_upg_kit_level_list[level_name]), size_table(world_kit_off[level_name])) dist_exclude_table[level_name] = {} for i=1, kit_spawn_count do local result = try_spawn_world_item_kit_upg(level_name, true) while result and result == "too close" and size_table(world_kit_off[level_name]) > 0 do result = try_spawn_world_item_kit_upg(level_name, true) end if is_empty(world_kit_off[level_name]) then break end end for kit_name, v in pairs(dist_exclude_table[level_name]) do world_kit_off[level_name][kit_name] = true end dist_exclude_table[level_name] = {} end end function is_world_item(id) if id and world_itm_on[id] then --print_debug("! Game Setup | is_world_item[%s]", id) return true elseif id then for level_name, v in pairs(world_kit_on) do if world_kit_on[level_name][id] then return true end end for level_name, v in pairs(world_upg_kit_on) do if world_upg_kit_on[level_name][id] then return true end end end --print_debug("/ Game Setup | is_world_item[%s]", id) return false end -- TODO IN 1.6 OR WHENEVER WE CAN EDIT ALL.SPAWN -- remove these 2 objects because vetham is making new office for medic and they get in the way function bar_medic_remove_stuff() if not alife_storage_manager.get_state().duty_medic_fix then alife_storage_manager.get_state().duty_medic_fix = true for i=1,65534 do local se = alife():object(i) if se and (se:name() == 'bar_physic_object_mlr_0002' or se:name() == 'bar_physic_object_mlr_0003') then alife():release(se) end end end end -- TODO IN 1.6 OR WHENEVER WE CAN EDIT ALL.SPAWN -- remove these 4 objects because they're stuck in the train and physics impulse makes them jitter around at 5 fps function darkscape_remove_physics_objects() if not alife_storage_manager.get_state().darkscape_phys_fix then alife_storage_manager.get_state().darkscape_phys_fix = true for i=1,65534 do local se = alife():object(i) if se and (se:name() == 'ds_physic_destroyable_object_0046' or se:name() == 'ds_physic_object_0009' or se:name() == 'ds_physic_object_0010' or se:name() == 'ds_physic_object_0002') then alife():release(se) end end end end -- TODO IN 1.6 OR WHENEVER WE CAN EDIT ALL.SPAWN -- delete the chair and move smart cover in this new position -- OR -- make the chair part of level geometry and delete the object -- OR -- find a way to make that specific object not react to physics function freedom_medic_fix() if not alife_storage_manager.get_state().freedom_medic_fix then alife_storage_manager.get_state().freedom_medic_fix = true for i=1,65534 do local se = alife():object(i) if se then if se:name() == 'mil_physic_object_0048' then alife():release(se) elseif se:name() == 'sc_freedom_medic_mlr' then alife():teleport_object(i, 2165, 315401, vector():set(27.681089401245, -6.9381303787231, 17.38550567627)) end end end end end ------------------------------- -- CALLBACKS ------------------------------- function actor_on_first_update() init_settings() freedom_medic_fix() bar_medic_remove_stuff() darkscape_remove_physics_objects() if alife_storage_manager.get_state().item_removal_done or IsTestMode() then UnregisterScriptCallback("actor_on_first_update",actor_on_first_update) return end alife_storage_manager.get_state().item_removal_done = true print_debug("- Game Setup | create dynamic items") local ini_setup = ini_file("plugins\\new_game_setup.ltx") local enabled = true --ini_dyn:r_bool_ex("settings","enabled") or false if (not enabled) then return end -- Release static items and mines local sim = alife() local boxes = {} for i=1, 65534 do local se_obj = sim:object(i) if se_obj then local name = se_obj:name() local cls = se_obj:clsid() if cls == clsid.inventory_box_s then --print_debug('%s_%s is a box', i, name) boxes[i] = true elseif ini_dyn:line_exist("replace_items",name) then --print_debug('releasing %s', name) --sim:release(se_obj, true) alife_release(se_obj) end if ini_setup:line_exist("remove_objects",name) then print_debug('/ Game Setup | Releasing object (%s)', name) -- Clear inventory boxes from their manager if (cls == clsid.inventory_box_s) then treasure_manager.release_stash_by_id(se_obj.id) end safe_release_manager.release(se_obj) end end end -- Clear stashes for i=1, 65534 do local se_obj = sim:object(i) if se_obj then local name = se_obj:name() if boxes[se_obj.parent_id] and (not sfind(name, 'mlr_strelok_item')) then print_debug('/ Game Setup | Releasing {%s} from box', name) --sim:release(se_obj, true) alife_release(se_obj) end end end -- Setup items create_world_itms() -- Find all kit spawns with a tag for guaranteed spawn and spawn them --create_guaranteed_itms() -- Spawn kits create_world_kits() -- Upgrade kits spawning create_world_kits_upg() print_debug("- Game Setup | world_itm_info: %s - world_itm_on: %s - world_itm_off: %s", size_table(world_itm_info), size_table(world_itm_on), size_table(world_itm_off)) end local tg_stkr = 0 local function actor_on_update() if time_global() < tg_stkr then return end -- No need to process if actor is outside cordon / visited more levels / not a loner / Warfare is active if (level.name() ~= "l01_escape") or IsWarfare() or (game_statistics.get_statistic_count("level_changes") > 1) or (get_actor_true_community() ~= "stalker") then UnregisterScriptCallback("actor_on_update",actor_on_update) return end -- Remove common military or mutant squads local on_act_lvl = simulation_objects.is_on_the_actor_level for id,v in pairs( SIMBOARD.squads ) do local squad = alife_object(id) if squad and squad.common and (squad.player_id == "army") and on_act_lvl(squad) then squad:remove_squad() break end end tg_stkr = time_global() + 10000 end function actor_on_item_take(obj) local id = obj:id() local level_name = level.name() local name if id and level_name and world_kit_on[level_name] and world_kit_on[level_name][id] then name = world_kit_on[level_name][id] elseif id and level_name and world_upg_kit_on[level_name] and world_upg_kit_on[level_name][id] then name = world_upg_kit_on[level_name][id] end if name then printf("Found kit; name: %s - level: %s - section: %s - id: %s", name, level_name, obj:section(), id) else name = world_itm_on[id] end if name then local section = obj:section() local info = world_itm_info[name] if (not info) then print_debug("! Game Setup | can't get info for {%s}", name) end -- Spawn a new world item local result if world_itm_on[id] then try_spawn_world_item() elseif world_kit_on[level_name][id] then try_spawn_world_item_kit(level_name) elseif world_upg_kit_on[level_name][id] then try_spawn_world_item_kit_upg(level_name) end -- Switch state if world_itm_on[id] then world_itm_on[id] = nil world_itm_off[name] = true elseif world_kit_on[level_name][id] then world_kit_on[level_name][id] = nil world_kit_off[level_name][name] = true elseif world_upg_kit_on[level_name][id] then world_upg_kit_on[level_name][id] = nil world_kit_off[level_name][name] = true end -- Read info local num = world_itm_num[name] if num then --printf("Got num") --printf("section: " .. section) -- Ammo if IsItem("ammo",section) then obj:ammo_set_count(num) print_debug("- Game Setup | taken world ammo [%s](%s) is set to %s ammo - info name: %s", section, id, num, name) world_itm_num[name] = nil -- Multi-use elseif limited_uses[section] and not utils_item.is_degradable(nil, section) then alife_process_item( section, id , {uses = num} ) print_debug("- Game Setup | taken world consumable [%s](%s) is set to %s uses - info name: %s", section, id, num, name) world_itm_num[name] = nil -- Condition elseif utils_item.is_degradable(nil, section) then alife_process_item( section, id , {cond = num} ) print_debug("- Game Setup | taken world degraded item [%s](%s) is set to %s condition - info name: %s", section, id, num, name) world_itm_num[name] = nil end -- Normal else print_debug("- Game Setup | taken world item [%s](%s) - info name: %s", section, id, uses, name) end -- Send message itms_manager.send_itm_msg(section) if info then remove_marker(id, info.typ) end else print_debug("! Game Setup | can't get name for id {%s} level %s", id, level_name) end -- Ammo aggregation (it's important to start ammo aggregation after sorting taken world ammo size first, to prevent issues) if IsAmmo(obj) then item_weapon.ammo_aggregation(obj) end end local get_config = worldspawns_rework_mcm.get_config function on_option_change() if get_config("reset_kits") and level.present() and db.actor then reset() ui_mcm.set("kit_rework/reset_kits", false) end end local function save_state(m_data) m_data.world_itm_on = world_itm_on m_data.world_kit_on = world_kit_on m_data.world_itm_num = world_itm_num m_data.world_upg_kit_on = world_upg_kit_on print_debug("# SAVING: world_itm_on [%s] - world_itm_num [%s]", size_table(world_itm_on), size_table(world_itm_num)) end local function load_state(m_data) world_itm_on = m_data.world_itm_on or {} world_itm_num = m_data.world_itm_num or {} world_kit_on = m_data.world_kit_on or {} world_upg_kit_on = m_data.world_upg_kit_on or {} print_debug("# LOADING: world_itm_on [%s] - world_itm_num [%s]", size_table(world_itm_on), size_table(world_itm_num)) end function on_game_start() RegisterScriptCallback("actor_on_first_update",actor_on_first_update) RegisterScriptCallback("actor_on_update",actor_on_update) RegisterScriptCallback("actor_on_item_take",actor_on_item_take) RegisterScriptCallback("save_state",save_state) RegisterScriptCallback("load_state",load_state) RegisterScriptCallback("on_option_change", on_option_change) end