Added, Updated and Removed Mods; Removed Backups
This commit is contained in:
@@ -0,0 +1,639 @@
|
||||
|
||||
--[[
|
||||
|
||||
Tronex
|
||||
|
||||
set enable_debug to true, for debugging and map markers
|
||||
|
||||
----------------------------------------------------------
|
||||
|
||||
- Dynamic Anomalies
|
||||
2019/6/14
|
||||
used ini:
|
||||
plugins\dynamic_anomalies.ltx
|
||||
|
||||
1. Script will read the list of anomalies and their position/types from the config (you can recorded custom pos for your anomalies)
|
||||
2. Then spawn all anomalies on new game, then disable a random number of them.
|
||||
3. When an enmission happen, anomalies will shuffle between off/on state (the dynamic factor)
|
||||
|
||||
----------------------------------------------------------
|
||||
|
||||
- The Pulse
|
||||
A concept of electro-psy anomaly that forms in the sky and discharge into the ground like a thunderbolt, killing any stalkers nearby
|
||||
|
||||
--]]
|
||||
|
||||
|
||||
local enable_debug = false
|
||||
function print_debug(...)
|
||||
if enable_debug then
|
||||
printf(...)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
-------------------------------
|
||||
-- Dynamic anomalies
|
||||
-------------------------------
|
||||
local ini_ano
|
||||
local dyn_ano_init = false
|
||||
local current_level
|
||||
|
||||
local dyn_ano_chance = 35 -- [0 - 100] chance of activating a dynamic anomaly
|
||||
local dyn_ano_safe_dist = 15 -- [m] don't activate anomalies within the safe distance to player
|
||||
local dyn_ano_type = {} -- [type] = {}
|
||||
local dyn_ano_info = {} -- [level][name] = info
|
||||
|
||||
local dyn_anomalies_dbg = {} -- [id] = name
|
||||
dyn_anomalies = {} -- [level][id] = name
|
||||
|
||||
-- ZCP
|
||||
if smr_amain_mcm.get_config("smr_enabled") then
|
||||
dyn_ano_chance = smr_anomalies_mcm.get_config("dyn_ano_chance")
|
||||
end
|
||||
-- ZCP END
|
||||
|
||||
-- Prepare
|
||||
function ini_settings()
|
||||
|
||||
if (dyn_ano_init) then return end
|
||||
dyn_ano_init = true
|
||||
|
||||
ini_ano = ini_file("plugins\\dynamic_anomalies.ltx")
|
||||
|
||||
local n,m = 0,0
|
||||
local result, id, value = "","",""
|
||||
local name, info = "","",""
|
||||
|
||||
-- Gather anomaly types
|
||||
n = ini_ano:line_count("categories") or 0
|
||||
for i=0,n-1 do
|
||||
result, id, value = ini_ano:r_line_ex("categories",i,"","")
|
||||
-- ZCP
|
||||
if smr_amain_mcm.get_config("smr_enabled") and (smr_anomalies_mcm.get_config(id) == false) then
|
||||
smr_debug.get_log().info("anomalies/types", "skipping disabled anomaly type %s", id)
|
||||
goto continue
|
||||
end
|
||||
-- ZCP END
|
||||
dyn_ano_type[id] = {}
|
||||
|
||||
m = ini_ano:line_count(id) or 0
|
||||
for ii=0,m-1 do
|
||||
result, name, info = ini_ano:r_line_ex(id,ii,"","")
|
||||
if name and info then
|
||||
for j=1,tonumber(info) do
|
||||
local size = #dyn_ano_type[id] + 1
|
||||
dyn_ano_type[id][size] = name
|
||||
print_debug("- Dynamic Anomalies | dyn_ano_type[%s][%s] = %s", id, size, name)
|
||||
end
|
||||
end
|
||||
end
|
||||
::continue::
|
||||
end
|
||||
|
||||
-- Gather anomaly coordinates in all levels
|
||||
n = ini_ano:line_count("levels") or 0
|
||||
for i=0,n-1 do
|
||||
result, id, value = ini_ano:r_line_ex("levels",i,"","")
|
||||
m = ini_ano:line_count(id) or 0
|
||||
|
||||
dyn_ano_info[id] = {}
|
||||
|
||||
for ii=0,m-1 do
|
||||
result, name, info = ini_ano:r_line_ex(id,ii,"","")
|
||||
if name and info then
|
||||
local t = str_explode(info,",")
|
||||
if (#t == 6) and (t[1] ~= "NA") then
|
||||
dyn_ano_info[id][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]),
|
||||
}
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local marker_by_type = {
|
||||
["electric"] = "anomaly_electric",
|
||||
["chemical"] = "anomaly_chemical",
|
||||
["thermal"] = "anomaly_thermal",
|
||||
["gravitational"] = "anomaly_gravitational",
|
||||
["radioactive"] = "anomaly_radioactive",
|
||||
["disabled"] = "anomaly_disabled",
|
||||
}
|
||||
function add_marker(lvl, section, id, state)
|
||||
|
||||
if enable_debug then
|
||||
ini_settings()
|
||||
|
||||
if lvl and dyn_ano_info[lvl] then
|
||||
local name = dyn_anomalies_dbg[id]
|
||||
if name then
|
||||
|
||||
local info = dyn_ano_info[lvl][name]
|
||||
if info then
|
||||
for k,v in pairs(marker_by_type) do
|
||||
if (level.map_has_object_spot(id, v) ~= 0) then
|
||||
level.map_remove_object_spot(id, v)
|
||||
end
|
||||
end
|
||||
|
||||
local typ = info.typ
|
||||
local spot = marker_by_type[typ] or marker_by_type["gravitational"]
|
||||
if (state == false) then
|
||||
spot = marker_by_type["disabled"]
|
||||
end
|
||||
level.map_add_object_spot_ser(id, spot, "Name: " .. name .. " \\nType: " .. typ .. " \\nSection: " .. section)
|
||||
else
|
||||
print_debug("! Dynamic Anomalies | Marker - no info is found for name {%s}", name)
|
||||
end
|
||||
else
|
||||
print_debug("! Dynamic Anomalies | Marker - no name is found for id (%s)", id)
|
||||
end
|
||||
else
|
||||
print_debug("! Dynamic Anomalies | Marker - level %s is not stored in dyn_ano_info table", lvl)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- Operation
|
||||
function dyn_anomalies_spawn()
|
||||
|
||||
-- Iterate through all anomalies info for all levels
|
||||
|
||||
for lvl,v in pairs(dyn_ano_info) do
|
||||
dyn_anomalies[lvl] = {}
|
||||
|
||||
for name,info in pairs(v) do
|
||||
|
||||
-- Get random anomaly section
|
||||
local anom_type = dyn_ano_type[info.typ]
|
||||
local section = anom_type and anom_type[math.random(#anom_type)]
|
||||
if (not section) then
|
||||
print_debug("! Dynamic Anomalies | Anomaly section not found for type: %s", info.typ)
|
||||
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("! Dynamic Anomalies | Anomaly {%s} has wrong or incomplete info", name)
|
||||
return
|
||||
end
|
||||
|
||||
-- Spawn
|
||||
local se_obj = alife_create( section, vector():set(info.x , info.y , info.z), info.lvl_id, info.gm_id )
|
||||
if ( not se_obj ) then
|
||||
print_debug("! Dynamic Anomalies | Unable to spawn dynamic anomaly")
|
||||
return
|
||||
end
|
||||
|
||||
-- Set anomaly properties:
|
||||
local data = utils_stpk.get_anom_zone_data( se_obj )
|
||||
if ( not data ) then
|
||||
print_debug("! Dynamic Anomalies | Unable to set dynamic anomaly properties" )
|
||||
return
|
||||
end
|
||||
data.shapes[1] = {}
|
||||
data.shapes[1].shtype = 0
|
||||
data.shapes[1].offset = vector():set( 0, 0, 0 ) -- Leave for compatibility with CoC 1.4.22, delete later
|
||||
data.shapes[1].center = vector():set( 0, 0, 0 )
|
||||
data.shapes[1].radius = 3
|
||||
utils_stpk.set_anom_zone_data( data, se_obj )
|
||||
|
||||
-- Save data
|
||||
dyn_anomalies[lvl][se_obj.id] = true
|
||||
|
||||
if enable_debug then
|
||||
dyn_anomalies_dbg[se_obj.id] = name
|
||||
end
|
||||
|
||||
print_debug("- Dynamic Anomalies | %s | Spawned anomaly [%s](%s){%s}", lvl, section, se_obj.id, name)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function dyn_anomalies_suffle()
|
||||
for lvl,v in pairs(dyn_anomalies) do
|
||||
for id, state in pairs(v) do
|
||||
if (math.random(100) < dyn_ano_chance) then
|
||||
dyn_anomalies[lvl][id] = true
|
||||
print_debug("/ Dynamic Anomalies | Shuffle - dyn_anomalies[%s][%s] = %s", lvl, id, true)
|
||||
else
|
||||
dyn_anomalies[lvl][id] = false
|
||||
print_debug("/ Dynamic Anomalies | Shuffle - dyn_anomalies[%s][%s] = %s", lvl, id, false)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function dyn_anomalies_update()
|
||||
if (not dyn_anomalies[current_level]) then
|
||||
print_debug("! Dynamic Anomalies | Can't update anomalies because current level (%s) has no anomalies recorded", current_level)
|
||||
return true
|
||||
end
|
||||
|
||||
local actor_pos = db.actor:position()
|
||||
for id,state in pairs(dyn_anomalies[current_level]) do
|
||||
local obj = level.object_by_id(id)
|
||||
if obj then
|
||||
if (actor_pos:distance_to(obj:position()) > dyn_ano_safe_dist) then
|
||||
obj:enable_anomaly()
|
||||
|
||||
if (state == false) then
|
||||
obj:disable_anomaly()
|
||||
end
|
||||
|
||||
add_marker(current_level, obj:section(), id, state)
|
||||
print_debug("- Dynamic Anomalies | %s | Anomaly (%s) is set to state: %s", current_level, id, state)
|
||||
else
|
||||
print_debug("! Dynamic Anomalies | %s | Anomaly (%s) is close to player, no process", current_level, id)
|
||||
end
|
||||
|
||||
else
|
||||
print_debug("! Dynamic Anomalies | %s | Couldn't get online object for id (%s)", current_level, id)
|
||||
end
|
||||
end
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
function dyn_anomalies_refresh(force)
|
||||
|
||||
-- Prepare anomalies for the first time
|
||||
if (not has_alife_info("dynamic_anomalies_spawned")) and is_empty(dyn_anomalies) then
|
||||
give_info("dynamic_anomalies_spawned")
|
||||
|
||||
ini_settings()
|
||||
|
||||
dyn_anomalies_spawn()
|
||||
dyn_anomalies_suffle()
|
||||
|
||||
-- shuffle state of all anomalies after emission
|
||||
elseif force then
|
||||
dyn_anomalies_suffle()
|
||||
end
|
||||
|
||||
-- enable/disable online anomalies
|
||||
-- NOTE: it's important to use timer because online objects don't register instantly after creating the server objects, so we need to wait for a bit.
|
||||
-- Guess there's a delay in engine to set things up completely
|
||||
local n = has_alife_info("dynamic_anomalies_spawned") and 1 or 10
|
||||
CreateTimeEvent(0, "update_dynamic_anomalies", n, dyn_anomalies_update)
|
||||
end
|
||||
|
||||
|
||||
-------------------------------
|
||||
-- Pulse anomalies
|
||||
-------------------------------
|
||||
local pAno_first = true
|
||||
local pAno_tg = time_global()
|
||||
local pAno_light = nil
|
||||
local pAno_pfx = particles_object("generator\\generator_accum_thunderbolt")
|
||||
local pAno_snd_close = sound_object("anomaly\\emi_blowout")
|
||||
local pAno_snd_far = sound_object("anomaly\\emi_blowout_01")
|
||||
local pAno_snd_distance = 150 -- [m] (max distance between player and anomaly where close sound effect can be heard)
|
||||
local pAno_snd_delay = 5.5 -- [sec] (time delay between anomaly's spawn and sound effect)
|
||||
local pAno_p_hit_distance = 10 -- [m] (max distance between player and anomaly to recieve psy damage)
|
||||
local pAno_e_hit_distance = 20 -- [m] (max distance between player and anomaly to recieve shock damage)
|
||||
local pAno_hit_delay = 11.5 -- [sec] (time delay between anomaly's spawn and player hit)
|
||||
local pAno_article_distance = 50 -- [m] (max distance between player and anomaly to trigger related article )
|
||||
local pAno_max_distance = 150 -- [m] (max distance between player and anomaly's spawn)
|
||||
local pAno_delay = 2 * 60 * 1000 -- [millie sec] (smallest time delay between pulse anomalies to spawn)
|
||||
local pAno_chance = {
|
||||
["clear"] = 0,
|
||||
["partly"] = 0,
|
||||
["cloudy"] = 10,
|
||||
["rain"] = 15,
|
||||
["storm"] = 25,
|
||||
["foggy"] = 0,
|
||||
}
|
||||
local pAno_maps = {
|
||||
["k00_marsh"] = 0.5,
|
||||
["k01_darkscape"] = 1,
|
||||
["k02_trucks_cemetery"] = 1,
|
||||
["l01_escape"] = 0.2,
|
||||
["l02_garbage"] = 0.7,
|
||||
["l03_agroprom"] = 0.5,
|
||||
["l04_darkvalley"] = 0.5,
|
||||
["l06_rostok"] = 1,
|
||||
["l07_military"] = 0.5,
|
||||
["l08_yantar"] = 0.7,
|
||||
["l09_deadcity"] = 0.5,
|
||||
["l10_red_forest"] = 1,
|
||||
["jupiter"] = 1,
|
||||
["pripyat"] = 1,
|
||||
["zaton"] = 1,
|
||||
["l13_generators"] = 1.5,
|
||||
["l12_stancia_2"] = 1.5,
|
||||
["l12_stancia"] = 1.5,
|
||||
["l11_pripyat"] = 0.2,
|
||||
["l10_radar"] = 1,
|
||||
["y04_pole"] = 0.7,
|
||||
}
|
||||
|
||||
local function pulse_anomaly_sound(sound_pos)
|
||||
local distance = distance_2d(db.actor:position(), sound_pos)
|
||||
local pAno_snd = (distance > pAno_snd_distance) and pAno_snd_far or pAno_snd_close
|
||||
|
||||
if pAno_snd and pAno_snd:playing() then
|
||||
pAno_snd:stop()
|
||||
end
|
||||
if pAno_snd ~= nil then
|
||||
pAno_snd:play_at_pos(db.actor, sound_pos)
|
||||
pAno_snd.volume = 1
|
||||
end
|
||||
|
||||
pAno_light:set_position(sound_pos)
|
||||
pAno_light.enabled = true
|
||||
pAno_light:update()
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
local function pulse_anomaly_hit(particle_pos)
|
||||
pAno_light.lanim_brightness = 0.2
|
||||
pAno_light.volumetric_distance = 1
|
||||
pAno_light.volumetric_intensity = 0.1
|
||||
|
||||
if GetEvent("current_safe_cover") then
|
||||
return true
|
||||
end
|
||||
|
||||
local hit_power = 0
|
||||
local distance = distance_2d(db.actor:position(), particle_pos)
|
||||
|
||||
-- Article
|
||||
if distance < pAno_article_distance then
|
||||
SendScriptCallback("actor_on_interaction", "anomalies", nil, "pulse")
|
||||
end
|
||||
|
||||
-- Psi hit
|
||||
if distance < pAno_p_hit_distance then
|
||||
hit_power = math.cos(distance * math.pi / pAno_p_hit_distance) + 1
|
||||
local h = hit()
|
||||
h.type = hit.telepatic
|
||||
if (level_environment.is_actor_immune() or dialogs_yantar.actor_has_psi_helmet()) then
|
||||
h.power = 0
|
||||
else
|
||||
h.power = surge_manager.SurgeManager:hit_power(hit_power, h.type)
|
||||
end
|
||||
h.impulse = 0
|
||||
h.direction = VEC_Z
|
||||
h.draftsman = db.actor
|
||||
|
||||
db.actor:hit(h)
|
||||
|
||||
level.remove_pp_effector(666)
|
||||
level.add_pp_effector("psi_fade.ppe", 666, false)
|
||||
level.set_pp_effector_factor(666,h.power)
|
||||
end
|
||||
|
||||
-- Electric hit
|
||||
if distance < pAno_e_hit_distance then
|
||||
hit_power = math.cos(distance * math.pi / pAno_e_hit_distance) + 1
|
||||
local h = hit()
|
||||
h.type = hit.shock
|
||||
if (level_environment.is_actor_immune()) then
|
||||
h.power = 0
|
||||
else
|
||||
h.power = surge_manager.SurgeManager:hit_power(hit_power, h.type)
|
||||
end
|
||||
h.impulse = 0
|
||||
h.direction = VEC_Z
|
||||
h.draftsman = db.actor
|
||||
db.actor:hit(h)
|
||||
level.remove_pp_effector(667)
|
||||
level.add_pp_effector("electro_fade.ppe", 667, false)
|
||||
level.set_pp_effector_factor(667,h.power)
|
||||
end
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
local function pulse_anomaly_light()
|
||||
pAno_light.lanim_brightness = 0.025
|
||||
pAno_light.volumetric_distance = 0.25
|
||||
pAno_light.volumetric_intensity = 0.05
|
||||
pAno_light.enabled = false
|
||||
return true
|
||||
end
|
||||
|
||||
function pulse_anomaly_update()
|
||||
local tg = time_global()
|
||||
if pAno_first then
|
||||
pAno_tg = tg + pAno_delay
|
||||
pAno_first = false
|
||||
return
|
||||
end
|
||||
|
||||
if (pAno_light and pAno_light.enabled) then
|
||||
pAno_light:update()
|
||||
end
|
||||
|
||||
if bLevelUnderground or (tg < pAno_tg) then
|
||||
return
|
||||
end
|
||||
pAno_tg = tg + pAno_delay
|
||||
|
||||
local lvl_factor = pAno_maps[level.name()] or 0
|
||||
local wthr = level_weathers.get_weather_manager():get_curr_weather()
|
||||
local weather_chance = pAno_chance[wthr] or 1
|
||||
if (math.random(100) > (weather_chance * lvl_factor)) then
|
||||
return
|
||||
end
|
||||
|
||||
local pos = db.actor:position()
|
||||
local angle_dec = math.random(0,359)
|
||||
local angle_rad = math.rad(angle_dec)
|
||||
local ano_distance = math.random(0,pAno_max_distance)
|
||||
local pos_x = math.cos(angle_rad)*ano_distance
|
||||
local pos_z = math.sin(angle_rad)*ano_distance
|
||||
local particle_pos = vector():set(pos.x+pos_x, pos.y+60, pos.z+pos_z)
|
||||
|
||||
pAno_pfx:play_at_pos(particle_pos)
|
||||
|
||||
if (not pAno_light) then
|
||||
--local color = fcolor()
|
||||
--color:set(0,0,100,50)
|
||||
|
||||
pAno_light = script_light()
|
||||
pAno_light.range = 100
|
||||
--pAno_light.type = 0 --light_type.Direct)
|
||||
--pAno_light:set_direction(vector():set(0,-1.5,0))
|
||||
--pAno_light.shadow = true
|
||||
pAno_light.lanim = "koster_01_electra"
|
||||
pAno_light.lanim_brightness = 0.025
|
||||
pAno_light.volumetric = true
|
||||
pAno_light.volumetric_quality = 1
|
||||
pAno_light.volumetric_distance = 0.25
|
||||
pAno_light.volumetric_intensity = 0.05
|
||||
--pAno_light.color = color
|
||||
end
|
||||
|
||||
CreateTimeEvent(0, "pulse_anomaly_sound", pAno_snd_delay, pulse_anomaly_sound, particle_pos)
|
||||
|
||||
CreateTimeEvent(0, "pulse_anomaly_hit", pAno_hit_delay, pulse_anomaly_hit, particle_pos)
|
||||
|
||||
CreateTimeEvent(0, "pulse_anomaly_light", pAno_hit_delay + 0.5, pulse_anomaly_light)
|
||||
end
|
||||
|
||||
|
||||
-------------------------------
|
||||
-- Callbacks
|
||||
-------------------------------
|
||||
local function actor_on_first_update()
|
||||
current_level = level.name()
|
||||
local enabled = ui_options.get("alife/general/dynamic_anomalies")
|
||||
if enabled and (not IsTestMode()) then
|
||||
dyn_anomalies_refresh()
|
||||
end
|
||||
end
|
||||
|
||||
local function actor_on_update()
|
||||
-- ZCP
|
||||
if smr_anomalies_mcm.get_config("pulse") then
|
||||
pulse_anomaly_update()
|
||||
end
|
||||
end
|
||||
|
||||
local function actor_on_interaction(typ, obj, name)
|
||||
if (typ == "anomalies") and (name == "emission_end") and ui_options.get("alife/general/dynamic_anomalies") then
|
||||
dyn_anomalies_refresh(true)
|
||||
end
|
||||
end
|
||||
|
||||
local function save_state(m_data)
|
||||
m_data.dyn_anomalies = dyn_anomalies
|
||||
if enable_debug then
|
||||
m_data.dyn_anomalies_dbg = dyn_anomalies_dbg
|
||||
end
|
||||
end
|
||||
|
||||
local function load_state(m_data)
|
||||
dyn_anomalies = m_data.dyn_anomalies or {}
|
||||
if enable_debug then
|
||||
dyn_anomalies_dbg = m_data.dyn_anomalies_dbg or {}
|
||||
end
|
||||
end
|
||||
|
||||
local function anomaly_on_before_activate(zone, obj, flags)
|
||||
|
||||
if (not obj or not zone) then
|
||||
return
|
||||
end
|
||||
|
||||
if (IsStalker(obj) or IsMonster(obj)) then
|
||||
if (not obj:alive()) then
|
||||
flags.ret_value = false
|
||||
end
|
||||
return
|
||||
end
|
||||
|
||||
if not (obj:clsid() == clsid.obj_bolt) then
|
||||
flags.ret_value = false
|
||||
end
|
||||
end
|
||||
|
||||
function on_game_start()
|
||||
RegisterScriptCallback("actor_on_first_update",actor_on_first_update)
|
||||
RegisterScriptCallback("actor_on_update",actor_on_update)
|
||||
RegisterScriptCallback("actor_on_interaction",actor_on_interaction)
|
||||
RegisterScriptCallback("anomaly_on_before_activate",anomaly_on_before_activate)
|
||||
RegisterScriptCallback("save_state",save_state)
|
||||
RegisterScriptCallback("load_state",load_state)
|
||||
end
|
||||
|
||||
|
||||
-------------------------------
|
||||
-- Anomaly field binder
|
||||
-------------------------------
|
||||
fields_by_names = {}
|
||||
function bind(obj)
|
||||
obj:bind_object(anomaly_field_binder(obj))
|
||||
end
|
||||
|
||||
class "anomaly_field_binder" (object_binder)
|
||||
function anomaly_field_binder:__init(obj) super(obj)
|
||||
|
||||
end
|
||||
|
||||
function anomaly_field_binder:reload(section)
|
||||
object_binder.reload(self, section)
|
||||
end
|
||||
|
||||
function anomaly_field_binder:reinit()
|
||||
object_binder.reinit(self)
|
||||
db.storage[self.object:id()] = {}
|
||||
self.st = db.storage[self.object:id()]
|
||||
end
|
||||
|
||||
function anomaly_field_binder:net_spawn(se_abstract)
|
||||
if not object_binder.net_spawn(self, se_abstract) then
|
||||
return false
|
||||
end
|
||||
db.add_zone(self.object)
|
||||
db.add_obj(self.object)
|
||||
fields_by_names[self.object:name()] = self
|
||||
|
||||
--[[
|
||||
eDefaultRestrictorTypeNone = u8(0),
|
||||
eDefaultRestrictorTypeOut = u8(1),
|
||||
eDefaultRestrictorTypeIn = u8(2),
|
||||
eRestrictorTypeNone = u8(3),
|
||||
eRestrictorTypeIn = u8(4),
|
||||
eRestrictorTypeOut = u8(5),
|
||||
--]]
|
||||
-- don't enable unless you realize that engine AI schemes to deal with anomalies is stupid and will not be supported
|
||||
-- MAY CAUSE HUGE FPS DROP ON COP MAPS
|
||||
--[[
|
||||
if (get_console_cmd(1,"ai_die_in_anomaly") == true) then
|
||||
-- It causes HUGE fps drop on COP maps which is why it was probably cut
|
||||
local ignore = {
|
||||
["zaton"] = true,
|
||||
["jupiter"] = true,
|
||||
["pripyat"] = true
|
||||
}
|
||||
if not (ignore[level.name()]) then
|
||||
self.object:set_restrictor_type(3)
|
||||
end
|
||||
end
|
||||
--]]
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
function anomaly_field_binder:net_destroy()
|
||||
db.del_zone( self.object )
|
||||
db.del_obj(self.object)
|
||||
db.storage[self.object:id()] = nil
|
||||
fields_by_names[self.object:name()] = nil
|
||||
object_binder.net_destroy(self)
|
||||
end
|
||||
|
||||
function anomaly_field_binder:set_enable(bEnable)
|
||||
if(bEnable) then
|
||||
self.object:enable_anomaly()
|
||||
else
|
||||
self.object:disable_anomaly()
|
||||
end
|
||||
end
|
||||
|
||||
function anomaly_field_binder:update(delta)
|
||||
object_binder.update(self, delta)
|
||||
--[[ testing
|
||||
local itr = function(id)
|
||||
local obj = id and alife_object(id)
|
||||
printf("%s touch_feel id=%s obj=%s",self.object:name(),id,obj and obj:name())
|
||||
end
|
||||
self.object:iterate_feel_touch(itr)
|
||||
--]]
|
||||
end
|
||||
|
||||
-- Standart function for save
|
||||
function anomaly_field_binder:net_save_relevant()
|
||||
return true
|
||||
end
|
||||
@@ -0,0 +1,501 @@
|
||||
--------------------------------------------------------------------
|
||||
-- Reworked by Tonex
|
||||
-- Last edit: 2019/5/18
|
||||
|
||||
-- Adapted new changes for the system
|
||||
-- Cleaned a lot of bloated code that was previously used for updating vice meshes
|
||||
--------------------------------------------------------------------
|
||||
|
||||
local MDATA = {}
|
||||
local settings_list = {}
|
||||
local angles_t = {}
|
||||
local mech_list_key = {}
|
||||
local debug_mode = false
|
||||
local debug_show_tables = false
|
||||
local ini_manager, settings, mesh_list, delay, ui
|
||||
|
||||
-- Cache vice and their lamps in table to reuse
|
||||
local vice_id = {}
|
||||
local lamp_id = {}
|
||||
|
||||
function access(obj) --| Access to a vice, taking into account possible death of the mechanic
|
||||
|
||||
if not (obj) then
|
||||
return
|
||||
end
|
||||
|
||||
--// You should be able to use any workshop in Warfare mode
|
||||
if _G.WARFARE or (smr_amain_mcm.get_config("smr_enabled") and smr_stalkers_mcm.get_config("base_population") == "sim_smr_none") then
|
||||
return true
|
||||
end
|
||||
|
||||
local name = obj:name()
|
||||
dout(nil, "Request access for %s", name)
|
||||
|
||||
--// Mechanic is dead - access is unlimited
|
||||
if angles_t[name] then
|
||||
if angles_t[name][3] == 'dead' then
|
||||
dout(nil, "Mechanic is dead. Full access")
|
||||
return true
|
||||
end
|
||||
end
|
||||
|
||||
--// Access was granted by a mechanic.
|
||||
if db.actor:has_info(string.format("awr_%s_access",angles_t[name][1])) then
|
||||
dout(nil, "Mechanic gave access")
|
||||
return true
|
||||
end
|
||||
|
||||
--// Debugging
|
||||
local npc = get_story_object(angles_t[name][1])
|
||||
if npc then
|
||||
if npc:alive() then
|
||||
dout(nil, "Access not granted. NPC %s by id %s is alive", angles_t[name][1], npc:id())
|
||||
else
|
||||
dout(nil, "![ERROR] NPC %s by id %s bugged, because he is online and is not alive, but function OnDeath was not called", angles_t[name][1], npc:id())
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function OnDeath(npc) --| Callback at the death of a mechanic
|
||||
dout(nil, "Called for NPC, %s", npc:section())
|
||||
if IsStalker(npc) and (not npc:alive()) then
|
||||
local npc_s = npc:section()
|
||||
dout(nil, "NPC %s exist and dead", npc:section())
|
||||
for key, val in pairs(angles_t) do
|
||||
if angles_t[key][1] == npc_s then
|
||||
|
||||
local story_obj = get_story_object(angles_t[key][1])
|
||||
if story_obj then
|
||||
level.map_remove_object_spot(story_obj:id(), "ui_pda2_mechanic_location")
|
||||
end
|
||||
|
||||
--// Add a marker
|
||||
SetMarker(key)
|
||||
|
||||
full_access(key,npc_s)
|
||||
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function SetMarker(name) --| The function of adding a marker to the map
|
||||
local id = name and vice_id[name]
|
||||
local s_obj = id and alife_object(id)
|
||||
if s_obj then
|
||||
dout(nil, "Add marker on parent object %s with ID %s", name, s_obj.id)
|
||||
level.map_add_object_spot_ser(s_obj.id, "ui_pda2_mechanic_location", "st_mech_tiski")
|
||||
end
|
||||
end
|
||||
|
||||
function CloseDl() -- The closing function of the UI AWR at the end of time (provided that the UI is called and the actor is within 2 meters of the mesh)
|
||||
if (ui) and ui:IsShown() then
|
||||
dout(nil, "UI exist and already open")
|
||||
ui:Close()
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
--=======================================< Callbacks >=======================================--
|
||||
|
||||
function physic_object_on_use_callback(_obj,who) -- Binder function using vise mesh
|
||||
if not (_obj) or not (string.match(_obj:name(), "awr")) then
|
||||
return
|
||||
end
|
||||
|
||||
--// The condition for the "parent" vise, spawn through all.spawn
|
||||
if access(_obj) and string.match(_obj:name(), "awr_tiski") and _obj:position():distance_to(db.actor:position()) < 1.5 then
|
||||
|
||||
--// Checking the table for "empty"
|
||||
r_unused()
|
||||
|
||||
--// Gather mechanic info
|
||||
local flag_1,flag_2,flag_3,flag_4 = false,false,false,false
|
||||
local name = _obj:name()
|
||||
local mechanic = name and angles_t[name] and angles_t[name][1]
|
||||
if mechanic then
|
||||
flag_1 = db.actor:has_info(mechanic .. "_upgrade_tier_1")
|
||||
flag_2 = db.actor:has_info(mechanic .. "_upgrade_tier_2")
|
||||
flag_3 = db.actor:has_info(mechanic .. "_upgrade_tier_3")
|
||||
|
||||
local drugkit_done = ini_manager:r_string_ex("drugkit_access",mechanic)
|
||||
if drugkit_done and db.actor:has_info(drugkit_done) then
|
||||
flag_4 = true
|
||||
end
|
||||
end
|
||||
|
||||
local function start_ui()
|
||||
--// Call UI
|
||||
local hud = get_hud()
|
||||
--if ui then
|
||||
--ui:HideDialog()
|
||||
--end
|
||||
ui = ui_workshop and ui_workshop.get_workshop_ui(hud, mechanic, {flag_1,flag_2,flag_3,flag_4,false})
|
||||
if (ui) then
|
||||
dout(nil, "call UI")
|
||||
ui:ShowDialog(true)
|
||||
end
|
||||
return true
|
||||
end
|
||||
|
||||
local delay = actor_effects.is_animations_on() and 2 or 0
|
||||
actor_effects.play_item_fx("workshop_dummy")
|
||||
CreateTimeEvent(0,"delay_workshop",delay,start_ui)
|
||||
end
|
||||
end
|
||||
|
||||
function actor_on_first_update() --| Callback of the first Update actor. It is executed one-time after loading, _after_ spawn of all objects from all.spawn, unlike on_game_load
|
||||
local smatch = string.match
|
||||
local sim = alife()
|
||||
for i=1, 65534 do
|
||||
local s_obj = sim:object(i)
|
||||
if s_obj then
|
||||
local name = s_obj:name()
|
||||
|
||||
--// If the vise is spawned all.spawn - save their values in the store
|
||||
if smatch(name, '%w+%_awr%_tiski%_%d+') then
|
||||
--// Cache vice id
|
||||
vice_id[name] = i
|
||||
angles_t[name] = l_v(name, angles_t[name])
|
||||
|
||||
if debug_mode then
|
||||
printf("/ Registered vice [%s] = %s", name, i)
|
||||
end
|
||||
|
||||
--// Cache vice lamps IDs
|
||||
elseif smatch(name, '_awr_lamp') then
|
||||
lamp_id[name] = i
|
||||
|
||||
if debug_mode then
|
||||
printf("/ Registered vice lamp [%s] = %s", name, i)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
--// Turn on lamps for all mechanics with a dead flag, otherwise it should be off
|
||||
for key, val in pairs(angles_t) do
|
||||
|
||||
--// Mechanic is dead -> grant full acces + turn on lamp
|
||||
if angles_t[key][3] == 'dead' then
|
||||
dout('actor_on_first_update', "%s is dead. Enable lamp(s) which assigned for %s", angles_t[key][1], key)
|
||||
Lamp(angles_t[key][1], true)
|
||||
full_access(key,npc_s)
|
||||
|
||||
--// Mechanic is unmarked for death -> turn off lamp
|
||||
else
|
||||
dout('actor_on_first_update', "%s is alive. Disable lamp(s) which assigned for %s", angles_t[key][1], key)
|
||||
Lamp(angles_t[key][1], false)
|
||||
|
||||
--[[
|
||||
// If Mechanic isn't around, grant unlimited access
|
||||
local npc_s = angles_t[key][1]
|
||||
local se_npc = get_story_se_object(npc_s)
|
||||
if (not se_npc) then
|
||||
full_access(key,npc_s)
|
||||
end
|
||||
--]]
|
||||
end
|
||||
|
||||
if db.actor:has_info(string.format('awr_%s_access', angles_t[key][1])) then
|
||||
dout('actor_on_first_update', "%s gave access. Enable lamp(s) which assigned for %s", angles_t[key][1], key)
|
||||
Lamp(angles_t[key][1], true)
|
||||
end
|
||||
end
|
||||
|
||||
--// Remove extra tables for weapons whose parts have not been replaced.
|
||||
r_unused()
|
||||
end
|
||||
|
||||
function npc_on_death_callback(victim, who) -- Callback, NPC caused by death
|
||||
if not (victim and who) then
|
||||
return
|
||||
end
|
||||
|
||||
local name = victim:section()
|
||||
local killer_name
|
||||
|
||||
if mech_list_key[name] then
|
||||
|
||||
dout('npc_on_death_callback', "NPC %s was killed by %s", victim:name(), who:name())
|
||||
OnDeath(victim)
|
||||
|
||||
if IsStalker(who) then
|
||||
killer_name = who:character_name()
|
||||
else
|
||||
killer_name = nil
|
||||
end
|
||||
|
||||
if who:id() == AC_ID then
|
||||
local alife = alife()
|
||||
local se_actor = alife:actor()
|
||||
killer_name = se_actor:character_name()
|
||||
end
|
||||
actor_menu.set_item_news('success', 'npc', "st_awr_dead_mechanic", victim:character_name(), killer_name or game.translate_string("st_by_unknown"))
|
||||
else
|
||||
-- if IsStalker(victim) then
|
||||
-- awr_sf.dout('npc_on_death_callback', "NPC %s is not in list -> return", victim:name()) -- Отрабатывает для всех смертей, включать при необходимости
|
||||
-- end
|
||||
return
|
||||
end
|
||||
end
|
||||
|
||||
function save_state(m_data)
|
||||
m_data.workshop = MDATA
|
||||
end
|
||||
|
||||
function load_state(m_data)
|
||||
MDATA = m_data.workshop or {}
|
||||
end
|
||||
|
||||
function on_game_start()
|
||||
ini_manager = itms_manager.ini_manager
|
||||
settings = utils_data.collect_section(ini_manager,"workshop_settings")
|
||||
mesh_list = utils_data.collect_section(ini_manager,"workshop_angles")
|
||||
|
||||
--for _, k in ipairs(settings) do
|
||||
--settings_list[k] = ini_manager:r_float_ex("workshop_settings", k)
|
||||
--end
|
||||
|
||||
for _, k in ipairs(mesh_list) do
|
||||
local t = parse_list(ini_manager,"workshop_angles", k)
|
||||
angles_t[k] = {}
|
||||
for _, v in ipairs(t) do
|
||||
table.insert(angles_t[k], v)
|
||||
end
|
||||
end
|
||||
|
||||
--// We enter data into the table keys for quick indexing by key, without using a loop
|
||||
for key, val in pairs(angles_t) do
|
||||
mech_list_key[val[1]] = 0
|
||||
end
|
||||
|
||||
RegisterScriptCallback("physic_object_on_use_callback", physic_object_on_use_callback)
|
||||
RegisterScriptCallback("actor_on_first_update", actor_on_first_update)
|
||||
RegisterScriptCallback("npc_on_death_callback", npc_on_death_callback)
|
||||
RegisterScriptCallback("save_state", save_state)
|
||||
RegisterScriptCallback("load_state", load_state)
|
||||
end
|
||||
|
||||
|
||||
--=======================================< Utility >=======================================--
|
||||
function Lamp(npc_name, state) --| Toggle online workshop lamps on/off
|
||||
for lamp_name,id in pairs(lamp_id) do
|
||||
if string.match(lamp_name, string.format('_awr_lamp_%s', npc_name)) then
|
||||
local se_lamp = alife_object(id)
|
||||
if se_lamp then
|
||||
local lamp = level.object_by_id(id)
|
||||
if lamp then
|
||||
if (state == true) then
|
||||
lamp:get_hanging_lamp():turn_on()
|
||||
dout(nil, "Lamp %s was turned on", lamp_name)
|
||||
elseif (state == false) then
|
||||
lamp:get_hanging_lamp():turn_off()
|
||||
dout(nil, "Lamp %s was turned off", lamp_name)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function full_access(vice,npc_s) --| Give unlimited access to a workshop
|
||||
--// 'Dead' flag in the table
|
||||
angles_t[vice][3] = 'dead'
|
||||
|
||||
--// Delete information if, before the death of a mechanic, he had access
|
||||
if db.actor:has_info(string.format('awr_%s_access', npc_s)) then
|
||||
db.actor:disable_info_portion(string.format('awr_%s_access', npc_s))
|
||||
dout(nil, 'NPC is dead. Infoportion awr_%s_access has been removed', npc_s)
|
||||
end
|
||||
|
||||
--// Issuance of information
|
||||
db.actor:give_info_portion(string.format("awr_%s_dead", npc_s))
|
||||
|
||||
--// Turn on the lamps
|
||||
Lamp(npc_s, true)
|
||||
|
||||
--// Store data
|
||||
s_v(vice, angles_t[vice])
|
||||
end
|
||||
|
||||
function s_v(name,val) --|
|
||||
--// Функция сохранения данных в Store
|
||||
dout(nil, "Save data to Store, table %s on value %s", name, val)
|
||||
|
||||
MDATA[name] = val
|
||||
if debug_show_tables then print_table(MDATA, 'On Save') end
|
||||
end
|
||||
|
||||
function l_v(name, def) --|
|
||||
--// Функция загрузки данных из Store
|
||||
local function len(t)
|
||||
local i = 0
|
||||
for _ in pairs(t) do i = i + 1 end
|
||||
return i
|
||||
end
|
||||
|
||||
dout(nil, 'Trying to load %s from Store', name)
|
||||
local m_data = alife_storage_manager.get_state()
|
||||
if MDATA[name] and len(MDATA[name]) > 0 then
|
||||
dout(nil, "Table %s with %s keys was loaded", name, len(MDATA[name]))
|
||||
if debug_show_tables then print_table(MDATA, 'On Load') end
|
||||
return MDATA[name] or def
|
||||
else
|
||||
dout(nil, 'Table %s does not exist or is empty. Skipped', name)
|
||||
end
|
||||
return def or nil
|
||||
end
|
||||
|
||||
function r_unused() --|
|
||||
--// Функция удаления "пустых" таблиц с замененными деталями для оружия и флагами
|
||||
local chk = 0
|
||||
dout(nil, 'Searching unused tables in AWR Store table...')
|
||||
if MDATA then
|
||||
for k, _ in pairs(MDATA) do
|
||||
if k:match('_upg') then
|
||||
dout(nil, 'Checking %s table...', k)
|
||||
local count = 0
|
||||
for key, val in pairs(MDATA[k]) do
|
||||
count = count + val
|
||||
end
|
||||
if count == 5 then
|
||||
local flags = string.format('%s%s', k:gsub('[^%d+]', ''), '_flags')
|
||||
dout(nil, '%s table have default values, tables %s and %s will be removed', k, k, flags)
|
||||
MDATA[k] = nil
|
||||
MDATA[flags] = nil
|
||||
chk = chk + 2
|
||||
else
|
||||
dout(nil, 'Data in table %s is used. Skipped', k)
|
||||
end
|
||||
end
|
||||
end
|
||||
if chk == 0 then
|
||||
dout(nil, 'AWR Store table have no unused tables')
|
||||
else
|
||||
dout(nil, 'Removed %s tables', chk)
|
||||
end
|
||||
else
|
||||
dout(nil, 'AWR table does not exist')
|
||||
end
|
||||
if debug_show_tables then print_table(MDATA, 'On Remove Unused') end
|
||||
end
|
||||
|
||||
function dout(call,fmt,...) --|
|
||||
--// Функция отладочного вывода (включен при debug_mode = true в awr_settings.ltx)
|
||||
if not (debug_mode) then return end
|
||||
if not (fmt) then return end
|
||||
local fmt = tostring(fmt)
|
||||
|
||||
--// Пытаемся определить из какой функции произошел вызов целевой функции
|
||||
local caller_n = debug.getinfo(3, "n") and debug.getinfo(3, "n").name or "not specified"
|
||||
local f_name = debug.getinfo(2, "n") and debug.getinfo(2, "n").name or "not specified"
|
||||
|
||||
if call then
|
||||
caller_n = tostring(call)
|
||||
end
|
||||
|
||||
if (select('#',...) >= 1) then
|
||||
local i = 0
|
||||
local p = {...}
|
||||
local function sr(a)
|
||||
i = i + 1
|
||||
if (type(p[i]) == 'userdata') then
|
||||
if (p[i].x and p[i].y) then
|
||||
return vec_to_str(p[i])
|
||||
end
|
||||
return 'userdata'
|
||||
end
|
||||
return tostring(p[i])
|
||||
end
|
||||
fmt = string.gsub(fmt,"%%s",sr)
|
||||
end
|
||||
if (log) then
|
||||
local str = string.format('[AWR]{%s->%s} %s', caller_n, f_name, fmt)
|
||||
log(str)
|
||||
--exec_console_cmd("flush")
|
||||
else
|
||||
exec_console_cmd("load ~#debug msg:"..str)
|
||||
end
|
||||
end
|
||||
|
||||
function print_table(tbl,header,format_only) --|
|
||||
--// Функция для вывода содержимого таблицы в строковом виде
|
||||
local txt = header and ("-- " .. tostring(header) .. "\n{\n\n") or "{\n\n"
|
||||
local depth = 1
|
||||
|
||||
local function tab(amt)
|
||||
local str = ""
|
||||
for i=1,amt, 1 do
|
||||
str = str .. "\t"
|
||||
end
|
||||
return str
|
||||
end
|
||||
|
||||
local function table_to_string(tbl)
|
||||
local size = 0
|
||||
for k,v in pairs(tbl) do
|
||||
size = size + 1
|
||||
end
|
||||
|
||||
local key
|
||||
local i = 1
|
||||
|
||||
for k,v in pairs(tbl) do
|
||||
if (type(k) == "number") then
|
||||
key = "[" .. k .. "]"
|
||||
elseif (type(k) == "function" or type(k) == "string" or type(k) == "boolean" or type(k) == "table") then
|
||||
key = "[\""..tostring(k) .. "\"]"
|
||||
else
|
||||
key = "[____unknown_type]"
|
||||
end
|
||||
|
||||
if (type(v) == "table") then
|
||||
txt = txt .. tab(depth) .. key .. " =\n"..tab(depth).."{\n"
|
||||
depth = depth + 1
|
||||
table_to_string(v,tab(depth))
|
||||
depth = depth - 1
|
||||
txt = txt .. tab(depth) .. "}"
|
||||
elseif (type(v) == "number" or type(v) == "boolean") then
|
||||
txt = txt .. tab(depth) .. key .. " = " .. tostring(v)
|
||||
elseif (type(v) == "userdata") then
|
||||
if (v.diffSec) then
|
||||
local Y, M, D, h, m, s, ms = 0,0,0,0,0,0,0
|
||||
Y, M, D, h, m, s, ms = v:get(Y, M, D, h, m, s, ms)
|
||||
txt = strformat("%s%s%s = { Y=%s, M=%s, D=%s, h=%s, m=%s, s=%s, ms=%s } ",txt,tab(depth),key,Y, M, D, h, m, s, ms)
|
||||
else
|
||||
txt = txt .. tab(depth) .. key .. " = \"userdata\""
|
||||
end
|
||||
elseif (type(v) == "function") then
|
||||
txt = txt .. tab(depth) .. key .. " = \"" .. tostring(v) .. "\""
|
||||
elseif (type(v) == "string") then
|
||||
txt = txt .. tab(depth) .. key .. " = '" .. v .. "'"
|
||||
else
|
||||
txt = txt .. tab(depth) .. key
|
||||
end
|
||||
|
||||
if (i == size) then
|
||||
txt = txt .. "\n"
|
||||
else
|
||||
txt = txt .. ",\n"
|
||||
end
|
||||
|
||||
i = i + 1
|
||||
end
|
||||
end
|
||||
|
||||
table_to_string(tbl)
|
||||
|
||||
txt = txt .. "\n}"
|
||||
|
||||
if (format_only) then
|
||||
return txt
|
||||
end
|
||||
|
||||
printf(txt)
|
||||
local file = io.open("gamedata\\awr_table.txt","a+")
|
||||
file:write(txt.."\n\n")
|
||||
file:close()
|
||||
end
|
||||
@@ -0,0 +1,187 @@
|
||||
--[[
|
||||
------------------------------------------------------------
|
||||
-- DPHs debug logger
|
||||
------------------------------------------------------------
|
||||
-- You may distribute this together with your addon as long as you keep this header intact.
|
||||
-- Latest version available from: https://www.moddb.com/mods/stalker-anomaly/addons/dphs-debug-logger
|
||||
--
|
||||
-- by dph-hcl
|
||||
------------------------------------------------------------
|
||||
]]--
|
||||
|
||||
LOG_LEVEL_INFO = 1
|
||||
LOG_LEVEL_WARNING = 2
|
||||
LOG_LEVEL_ERROR = 3
|
||||
|
||||
log_levels = {
|
||||
[LOG_LEVEL_INFO] = "INFO",
|
||||
[LOG_LEVEL_WARNING] = "WARNING",
|
||||
[LOG_LEVEL_ERROR] = "ERROR"
|
||||
}
|
||||
|
||||
local default_cfg = {
|
||||
["file"] = "dph.log",
|
||||
["targets"] = {
|
||||
["log"] = 1,
|
||||
["gamelog"] = 2,
|
||||
["pda"] = 3,
|
||||
}
|
||||
}
|
||||
|
||||
function new(cfg, mods)
|
||||
-- setup private properties
|
||||
local private = {}
|
||||
private.modules = {}
|
||||
private.enabled = false
|
||||
|
||||
local public = {}
|
||||
|
||||
public.config = default_cfg
|
||||
for k, v in pairs(cfg) do
|
||||
public.config[k] = v
|
||||
end
|
||||
|
||||
private.targets = {
|
||||
["log"] = function(mod, level, entry, ...)
|
||||
local ln = public.format_entry(mod, level, entry, ...)
|
||||
local file = io.open(public.config.file,"a+")
|
||||
if not file then
|
||||
printe(public.format_entry("dph_debug_log/log", LOG_LEVEL_ERROR, "Unable to open logfile %s! Entry logged on the following line.", public.config.file))
|
||||
printf(public.format_entry(mod, level, entry, ...))
|
||||
end
|
||||
file:write(ln .. "\n")
|
||||
file:close()
|
||||
end,
|
||||
["gamelog"] = function (mod, level, entry, ...)
|
||||
local ln = public.format_entry(mod, level, entry, ...)
|
||||
if level >= 3 then
|
||||
printe(ln)
|
||||
else
|
||||
printf(ln)
|
||||
end
|
||||
end,
|
||||
["pda"] = function (mod, level, entry, ...)
|
||||
local ln = entry
|
||||
if (select('#',...) >= 1) then
|
||||
ln = string.format(entry, ...)
|
||||
end
|
||||
if (db) and (db.actor) then
|
||||
db.actor:give_game_news("[" .. log_levels[level] .. "] " .. mod, ln, "", 5000, 10000)
|
||||
else
|
||||
printe(public.format_entry("dph_debug_log/pda", LOG_LEVEL_ERROR, "Could not send message to PDA: Actor does not exist! Entry logged on the following line."))
|
||||
printf(public.format_entry(mod, level, entry, ...))
|
||||
end
|
||||
end,
|
||||
}
|
||||
|
||||
private.compare_paths = function(pt, mt)
|
||||
m = tostring(mt)
|
||||
p = tostring(pt)
|
||||
if (not m) or (not p) then
|
||||
return false
|
||||
end
|
||||
local mm = str_explode(m, "/")
|
||||
local pp = str_explode(p, "/")
|
||||
for i, seg in ipairs(mm) do
|
||||
if (not pp[i]) or (seg ~= pp[i]) then
|
||||
return false
|
||||
end
|
||||
end
|
||||
return true
|
||||
end
|
||||
|
||||
private.module_enabled = function(mod)
|
||||
for i, m in ipairs(private.modules) do
|
||||
if private.compare_paths(mod, m) then
|
||||
return true
|
||||
end
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
private.log_entry = function(mod, level, entry, ...)
|
||||
if (private.enabled) and private.module_enabled(mod) then
|
||||
for t, l in pairs(public.config.targets) do
|
||||
if level >= l then public.log_to_target(t, mod, level, entry, ...) end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- public interface
|
||||
public.enable = function()
|
||||
private.enabled = true
|
||||
public.info("dph_debug_log", "DPHs DEBUG LOGGER VERSION %s | Log instance started", public.version())
|
||||
return private.enabled
|
||||
end
|
||||
|
||||
public.disable = function()
|
||||
private.enabled = false
|
||||
return private.enabled
|
||||
end
|
||||
|
||||
public.register_module = function(m)
|
||||
table.insert(private.modules, m)
|
||||
end
|
||||
|
||||
public.unregister_module = function(mod)
|
||||
for i, m in ipairs(private.modules) do
|
||||
if mod == m then private.modules[i] = nil end
|
||||
end
|
||||
end
|
||||
|
||||
public.define_target = function(name, log_function)
|
||||
private.targets[name] = log_function
|
||||
end
|
||||
|
||||
public.log_to_target = function(target, mod, level, entry, ...)
|
||||
local status, err = pcall(private.targets[target], mod, level, entry, ...)
|
||||
if err then
|
||||
printe(public.format_entry("dph_debug_log", LOG_LEVEL_ERROR, "Target %s threw an exception while logging <%s> %s", target, mod, entry))
|
||||
printe("ERROR: %s", err)
|
||||
printf(public.format_entry(mod, level, entry, ...))
|
||||
end
|
||||
end
|
||||
|
||||
public.format_entry = function(mod, level, entry, ...)
|
||||
local strf = entry
|
||||
if (select('#',...) >= 1) then
|
||||
strf = string.format(entry, ...)
|
||||
end
|
||||
local n1 = "[" .. log_levels[level] .. "]" .. string.rep(" ", 8 - #log_levels[level])
|
||||
local n2 = "<" .. mod .. ">" .. string.rep(" ", 28 - #mod)
|
||||
return (n1 .. n2 .. strf)
|
||||
end
|
||||
|
||||
public.info = function(mod, entry, ...)
|
||||
return private.log_entry(mod, LOG_LEVEL_INFO, entry, ...)
|
||||
end
|
||||
|
||||
public.warn = function(mod, entry, ...)
|
||||
return private.log_entry(mod, LOG_LEVEL_WARNING, entry, ...)
|
||||
end
|
||||
|
||||
public.error = function(mod, entry, ...)
|
||||
return private.log_entry(mod, LOG_LEVEL_ERROR, entry, ...)
|
||||
end
|
||||
|
||||
public.pda = function(mod, entry, ...)
|
||||
return public.log_to_target("pda", mod, LOG_LEVEL_INFO, entry, ...)
|
||||
end
|
||||
|
||||
public.log_table = function(mod, name, tbl)
|
||||
local ts = utils_data.print_table(tbl, false, true)
|
||||
public.info(mod, "TABLE %s \n%s", name, ts)
|
||||
end
|
||||
|
||||
public.version = function()
|
||||
return 1
|
||||
end
|
||||
|
||||
-- constructor
|
||||
for i, m in ipairs(mods) do
|
||||
public.register_module(m)
|
||||
end
|
||||
public.register_module("dph_debug_log")
|
||||
|
||||
return public
|
||||
end
|
||||
@@ -0,0 +1,242 @@
|
||||
--[[
|
||||
Made by werejew for Warfare
|
||||
Modified by Tronex for factions profiles
|
||||
Last edit: 2019/5/15
|
||||
--]]
|
||||
|
||||
-- Profiles
|
||||
faction = {}
|
||||
level = {}
|
||||
mutant = {}
|
||||
mutant_tier_by_clsid = {
|
||||
[clsid.bloodsucker_s] = 2,
|
||||
[clsid.boar_s] = 1,
|
||||
[clsid.burer_s] = 4,
|
||||
[clsid.cat_s] = 1,
|
||||
[clsid.chimera_s] = 3,
|
||||
[clsid.controller_s] = 4,
|
||||
[clsid.dog_s] = 1,
|
||||
[clsid.flesh_s] = 1,
|
||||
[clsid.fracture_s] = 2,
|
||||
[clsid.gigant_s] = 3,
|
||||
[clsid.poltergeist_s] = 4,
|
||||
[clsid.pseudodog_s] = 1,
|
||||
[clsid.psy_dog_phantom_s] = 4,
|
||||
[clsid.psy_dog_s] = 4,
|
||||
[clsid.rat_s] = 0,
|
||||
[clsid.snork_s] = 2,
|
||||
[clsid.tushkano_s] = 0,
|
||||
[clsid.zombie_s] = 1
|
||||
}
|
||||
|
||||
-- Warfare
|
||||
local faction_list = { -- List of factions to get correct squad section from
|
||||
["stalker"] = "stalker",
|
||||
["monolith"] = "monolith",
|
||||
["csky"] = "csky",
|
||||
["army"] = "army",
|
||||
["killer"] = "merc",
|
||||
["ecolog"] = "ecolog",
|
||||
["dolg"] = "duty",
|
||||
["freedom"] = "freedom",
|
||||
["bandit"] = "bandit",
|
||||
["greh"] = "greh",
|
||||
["isg"] = "isg",
|
||||
["renegade"] = "renegade",
|
||||
["zombied"] = "zombied",
|
||||
}
|
||||
|
||||
local random_mutants = {
|
||||
"simulation_bloodsucker",
|
||||
"simulation_bloodsucker",
|
||||
"simulation_boar",
|
||||
"simulation_boar",
|
||||
"simulation_boar",
|
||||
"simulation_dog",
|
||||
"simulation_dog",
|
||||
"simulation_dog",
|
||||
"simulation_pseudodog",
|
||||
"simulation_pseudodog",
|
||||
"simulation_flesh",
|
||||
"simulation_flesh",
|
||||
"simulation_flesh",
|
||||
"simulation_snork",
|
||||
"simulation_snork",
|
||||
"simulation_mix_dogs",
|
||||
"simulation_mix_dogs",
|
||||
"simulation_mix_dogs",
|
||||
"simulation_mix_boar_flesh",
|
||||
"simulation_mix_boar_flesh",
|
||||
"simulation_tushkano",
|
||||
"simulation_tushkano",
|
||||
"simulation_tushkano",
|
||||
"simulation_cat",
|
||||
"simulation_cat",
|
||||
"simulation_zombie",
|
||||
}
|
||||
|
||||
local random_rare = {
|
||||
"simulation_gigant",
|
||||
"simulation_controller",
|
||||
"simulation_controller",
|
||||
"simulation_burer",
|
||||
"simulation_burer",
|
||||
"simulation_chimera",
|
||||
"simulation_chimera",
|
||||
"simulation_bloodsucker",
|
||||
"simulation_bloodsucker",
|
||||
"simulation_bloodsucker",
|
||||
"simulation_snork",
|
||||
"simulation_snork",
|
||||
"simulation_snork",
|
||||
}
|
||||
|
||||
local random_zombies = {
|
||||
"simulation_zombie",
|
||||
"simulation_zombie",
|
||||
"simulation_zombie",
|
||||
"simulation_zombie",
|
||||
"simulation_zombie",
|
||||
"simulation_zombie",
|
||||
"simulation_zombie",
|
||||
"simulation_snork",
|
||||
"simulation_snork",
|
||||
"simulation_zombie",
|
||||
"simulation_zombie",
|
||||
"simulation_zombie",
|
||||
"simulation_zombie",
|
||||
"simulation_zombie",
|
||||
"simulation_zombie",
|
||||
"simulation_bloodsucker",
|
||||
"simulation_chimera",
|
||||
}
|
||||
|
||||
function get_advanced_chance(resource)
|
||||
return -1 * (100 * (1 / math.pow(warfare.resource_count / 2, 2))) * math.pow((resource - (warfare.resource_count / 2)), 2) + 100
|
||||
end
|
||||
|
||||
function get_veteran_chance(resource)
|
||||
return -100 + (100 / (warfare.resource_count / 2)) * resource
|
||||
end
|
||||
|
||||
function get_spawn_section(faction, resource)
|
||||
local advanced = get_advanced_chance(resource)
|
||||
local veteran = get_veteran_chance(resource)
|
||||
return get_section(faction, advanced, veteran)
|
||||
end
|
||||
|
||||
function get_section(faction, advanced_chance, veteran_chance)
|
||||
local r = math.random(100)
|
||||
local name = faction_list[faction]
|
||||
if name then
|
||||
if r <= veteran_chance then
|
||||
return (name .. "_sim_squad_veteran")
|
||||
elseif r <= advanced_chance then
|
||||
return (name .. "_sim_squad_advanced")
|
||||
else
|
||||
return (name .. "_sim_squad_novice")
|
||||
end
|
||||
elseif faction == "monster" then
|
||||
if math.random(100) >= 98 then
|
||||
return random_rare[math.random(#random_rare)]
|
||||
else
|
||||
return random_mutants[math.random(#random_mutants)]
|
||||
end
|
||||
else
|
||||
return random_zombies[math.random(#random_zombies)]
|
||||
end
|
||||
|
||||
return nil
|
||||
end
|
||||
|
||||
function get_faction_squad(faction, typ)
|
||||
local name = faction_list[faction]
|
||||
|
||||
if (typ == "novice") then
|
||||
return name.."_sim_squad_novice"
|
||||
elseif (typ == "advanced") then
|
||||
return name.."_sim_squad_advanced"
|
||||
elseif (typ == "veteran") then
|
||||
return name.."_sim_squad_veteran"
|
||||
elseif (typ == "sniper") then
|
||||
if (name == "monolith" or name == "army") then
|
||||
return name.."_sim_squad_sniper"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-----------------------
|
||||
function on_game_start()
|
||||
|
||||
local ini_fact = ini_file("plugins\\faction_profile.ltx")
|
||||
|
||||
-- Collect faction profiles
|
||||
local factions_list = {
|
||||
["stalker"] = true,
|
||||
["dolg"] = true,
|
||||
["freedom"] = true,
|
||||
["csky"] = true,
|
||||
["ecolog"] = true,
|
||||
["killer"] = true,
|
||||
["army"] = true,
|
||||
["bandit"] = true,
|
||||
["monolith"] = true,
|
||||
}
|
||||
|
||||
|
||||
for k,v in pairs(factions_list) do
|
||||
faction[k] = {}
|
||||
faction[k]["type"] = ini_fact:r_string_ex(k,"type") or "group"
|
||||
local color = parse_list(ini_fact,k,"color")
|
||||
faction[k]["color"] = strformat("%c[%s,%s,%s,%s]",color[1],color[2],color[3],color[4])
|
||||
faction[k]["territory"] = ini_fact:r_string_ex(k,"territory")
|
||||
|
||||
faction[k]["level_presence"] = parse_list(ini_fact,k,"level_presence",true)
|
||||
faction[k]["pda_topic"] = {}
|
||||
local pda_topics = parse_list(ini_fact,k,"pda_topic")
|
||||
for i=1,#pda_topics do
|
||||
for k1,v1 in string.gmatch(pda_topics[i], "([%w_%-%s%.]+)=([%w_%-%s%.]+)") do
|
||||
faction[k]["pda_topic"][k1] = tonumber(v1)
|
||||
end
|
||||
end
|
||||
faction[k]["pda_topic_mission"] = parse_list(ini_fact,k,"pda_topic_mission")
|
||||
faction[k]["weapon"] = ini_fact:r_string_ex(k,"weapon")
|
||||
|
||||
faction[k]["leader"] = ini_fact:r_string_ex(k,"leader")
|
||||
faction[k]["trader"] = ini_fact:r_string_ex(k,"trader")
|
||||
faction[k]["mechanic"] = ini_fact:r_string_ex(k,"mechanic")
|
||||
faction[k]["medic"] = ini_fact:r_string_ex(k,"medic")
|
||||
faction[k]["barman"] = ini_fact:r_string_ex(k,"barman")
|
||||
faction[k]["guide"] = ini_fact:r_string_ex(k,"guide")
|
||||
|
||||
faction[k]["leader_name"] = ini_fact:r_string_ex(k,"leader_name")
|
||||
faction[k]["trader_name"] = ini_fact:r_string_ex(k,"trader_name")
|
||||
faction[k]["mechanic_name"] = ini_fact:r_string_ex(k,"mechanic_name")
|
||||
faction[k]["medic_name"] = ini_fact:r_string_ex(k,"medic_name")
|
||||
faction[k]["barman_name"] = ini_fact:r_string_ex(k,"barman_name")
|
||||
faction[k]["guide_name"] = ini_fact:r_string_ex(k,"guide_name")
|
||||
end
|
||||
|
||||
local n = 0
|
||||
|
||||
n = ini_fact:line_count("news_levels")
|
||||
for i=0,n-1 do
|
||||
local result, id, value = ini_fact:r_line_ex("news_levels",i,"","")
|
||||
if level[id] == nil then
|
||||
level[id] = true
|
||||
end
|
||||
end
|
||||
|
||||
n = ini_fact:line_count("mutant_tier")
|
||||
for i=0,n-1 do
|
||||
local result, id, value = ini_fact:r_line_ex("mutant_tier",i,"","")
|
||||
if mutant[id] == nil then
|
||||
mutant[id] = {}
|
||||
mutant[id]["tier"] = tonumber(value)
|
||||
end
|
||||
end
|
||||
|
||||
--utils_data.print_table(faction,"faction_profiles")
|
||||
--utils_data.print_table(level,"news_levels")
|
||||
--utils_data.print_table(mutant,"mutant_tiers")
|
||||
end
|
||||
@@ -0,0 +1,557 @@
|
||||
--[[
|
||||
|
||||
- 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 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")
|
||||
|
||||
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,"","")
|
||||
|
||||
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]),
|
||||
}
|
||||
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
|
||||
|
||||
-- Make list of non-spawned items
|
||||
for name,info in pairs(world_itm_info) do
|
||||
world_itm_off[name] = true
|
||||
end
|
||||
|
||||
for id,name in pairs(world_itm_on) do
|
||||
world_itm_off[name] = nil
|
||||
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))
|
||||
end
|
||||
|
||||
function try_spawn_world_item(ignore)
|
||||
|
||||
-- Get spawn place name
|
||||
local _name
|
||||
if ignore then
|
||||
_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)]
|
||||
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 is_world_item(id)
|
||||
if id and world_itm_on[id] then
|
||||
--print_debug("! Game Setup | is_world_item[%s]", id)
|
||||
return true
|
||||
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
|
||||
-------------------------------
|
||||
local 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
|
||||
local multi = game_difficulties.get_eco_factor("random_items") or 0.5
|
||||
-- ZCP
|
||||
if 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
|
||||
|
||||
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
|
||||
|
||||
local function actor_on_item_take(obj)
|
||||
local id = obj:id()
|
||||
|
||||
if world_itm_on[id] then
|
||||
local name = world_itm_on[id]
|
||||
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
|
||||
try_spawn_world_item()
|
||||
|
||||
-- Switch state
|
||||
world_itm_on[id] = nil
|
||||
world_itm_off[name] = true
|
||||
|
||||
-- Read info
|
||||
local num = world_itm_num[name]
|
||||
if num then
|
||||
|
||||
-- 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] 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)
|
||||
|
||||
remove_marker(id, info.typ)
|
||||
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 function save_state(m_data)
|
||||
m_data.world_itm_on = world_itm_on
|
||||
m_data.world_itm_num = world_itm_num
|
||||
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 {}
|
||||
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)
|
||||
end
|
||||
@@ -0,0 +1,662 @@
|
||||
local coc_ranking_array_size = 100 -- Top100
|
||||
local coc_ranking_list = {}
|
||||
local actor_rank_place
|
||||
dialog_closed = true
|
||||
|
||||
----------------------------------------------------------------------------
|
||||
-- Engine->lua function calls
|
||||
----------------------------------------------------------------------------
|
||||
|
||||
-- PDA Tabs
|
||||
-- It's now possible to add new button tabs to pda*.xml.
|
||||
-- You can use ActorMenu.get_pda_menu():GetActiveSection() to find out active pda tab
|
||||
-- UI returned must be CUIScriptWnd
|
||||
function set_active_subdialog(section)
|
||||
--printf("set_active_subdialog | section=%s",section)
|
||||
|
||||
-- SMR
|
||||
if smr_amain_mcm.get_config("smr_enabled") and smr_amain_mcm.get_config("glitched_pda") then
|
||||
return ui_pda_glitched_tab.get_ui()
|
||||
end
|
||||
|
||||
-- For NPCs PDA
|
||||
local obj = db.actor:item_in_slot(8)
|
||||
local sec = obj and obj:section()
|
||||
if item_device.device_npc_pda[sec] then
|
||||
return ui_pda_npc_tab.get_ui( se_load_var(obj:id(), obj:name(), "info") )
|
||||
end
|
||||
|
||||
-- For Actor PDA
|
||||
if (section == "eptTasks") then
|
||||
|
||||
elseif (section == "eptRanking") then
|
||||
|
||||
elseif (section == "eptLogs") then
|
||||
|
||||
elseif (section == "eptRelations") then
|
||||
return ui_pda_relations_tab.get_ui()
|
||||
|
||||
elseif (section == "eptContacts") then
|
||||
if _G.WARFARE then
|
||||
return ui_pda_warfare_tab.get_ui()
|
||||
else
|
||||
return ui_pda_contacts_tab.get_ui()
|
||||
end
|
||||
|
||||
elseif (section == "eptEncyclopedia") then
|
||||
return ui_pda_encyclopedia_tab.get_ui()
|
||||
|
||||
elseif (section == "eptRadio") then
|
||||
return ui_pda_radio_tab.get_ui()
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
function pda_use() -- from engine?
|
||||
return item_device.is_pda_charged()
|
||||
end
|
||||
|
||||
function on_low_battery() -- from engine
|
||||
|
||||
end
|
||||
|
||||
local map_spot_property = {}
|
||||
function property_box_clicked(property_ui)
|
||||
local list_item = property_ui:GetSelectedItem()
|
||||
if not (list_item) then
|
||||
return
|
||||
end
|
||||
local textControl = list_item:GetTextItem()
|
||||
local prop = textControl:GetText()
|
||||
--printf("prop=%s",prop)
|
||||
SendScriptCallback("map_spot_menu_property_clicked",property_ui,map_spot_property.id,map_spot_property.level_name,prop)
|
||||
end
|
||||
|
||||
function property_box_add_properties(property_ui,id,level_name,hint)
|
||||
map_spot_property.id = id
|
||||
map_spot_property.level_name = level_name
|
||||
-- if (hint and hint ~= "") then
|
||||
-- property_ui:AddItem(hint)
|
||||
-- end
|
||||
SendScriptCallback("map_spot_menu_add_property",property_ui,id,level_name,hint)
|
||||
end
|
||||
|
||||
-- use actor_menu for other modes
|
||||
-- 10 = Talk dialog show
|
||||
-- 11 = Talk dialog hide
|
||||
function actor_menu_mode(mode)
|
||||
if(mode==10) then
|
||||
dialog_closed = false
|
||||
for k,st in pairs(db.storage) do
|
||||
if (st.object and st.object:is_talking() and st.object:id() ~= AC_ID) then
|
||||
local id = st.object:id()
|
||||
SetEvent("used_npc_id", id) -- stupid hack since sidorovich and forester don't have use_callback
|
||||
local sound_theme = xr_sound.sound_table[id]
|
||||
if sound_theme and sound_theme.reset then
|
||||
sound_theme:reset(id)
|
||||
end
|
||||
local m_data = alife_storage_manager.get_state()
|
||||
if not (m_data.actor_contacts) then
|
||||
m_data.actor_contacts = {}
|
||||
end
|
||||
m_data.actor_contacts[id] = true
|
||||
break
|
||||
end
|
||||
end
|
||||
Register_UI("Dialog")
|
||||
--printf("---:>Talk Dialog show")
|
||||
elseif(mode==11) then
|
||||
--printf("---:>Talk Dialog hide")
|
||||
SendScriptCallback("actor_on_leave_dialog",GetEvent("used_npc_id"))
|
||||
SetEvent("used_npc_id", nil)
|
||||
dialog_closed = true
|
||||
Unregister_UI("Dialog")
|
||||
end
|
||||
end
|
||||
|
||||
function get_time_elapsed()
|
||||
local s_time = level.get_start_time()
|
||||
local seconds = tonumber(game.get_game_time():diffSec(s_time))
|
||||
|
||||
if (seconds < 60) then
|
||||
return string.format("%d %s",seconds,game.translate_string("ui_st_secs"))
|
||||
elseif (seconds < 3600) then
|
||||
return string.format("%d %s",seconds/60,game.translate_string("ui_st_mins"))
|
||||
elseif (seconds < 86400) then
|
||||
return string.format("%d %s",seconds/60/60,game.translate_string("ui_st_hours"))
|
||||
end
|
||||
|
||||
return string.format("%d %s",seconds/60/60/24,game.translate_string("ui_st_days"))
|
||||
end
|
||||
|
||||
function get_stat(index) -- index= int return string
|
||||
if(index==0) then
|
||||
return get_time_elapsed()
|
||||
elseif(index==1) then
|
||||
return tostring(game_statistics.get_statistic_count("emissions"))
|
||||
elseif(index==2) then
|
||||
return tostring(game_statistics.get_statistic_count("tasks_completed"))
|
||||
elseif(index==3) then
|
||||
return tostring(game_statistics.get_statistic_count("killed_monsters"))
|
||||
elseif(index==4) then
|
||||
return tostring(game_statistics.get_statistic_count("killed_stalkers"))
|
||||
elseif(index==5) then
|
||||
return tostring(game_statistics.get_statistic_count("boxes_smashed"))
|
||||
elseif(index==6) then
|
||||
return tostring(game_statistics.get_statistic_count("stashes_found"))
|
||||
elseif(index==7) then
|
||||
return tostring(game_statistics.get_statistic_count("psi_storms"))
|
||||
elseif(index==8) then
|
||||
return tostring(game_statistics.get_statistic_count("pdas_delivered"))
|
||||
elseif(index==9) then
|
||||
return tostring(game_statistics.get_statistic_count("helicopters_downed"))
|
||||
elseif(index==10) then
|
||||
return tostring(game_statistics.get_statistic_count("artefacts_detected"))
|
||||
elseif(index==11) then
|
||||
return tostring(game_statistics.get_statistic_count("wounded_helped"))
|
||||
elseif(index==12) then
|
||||
return tostring(game_statistics.get_statistic_count("level_changes"))
|
||||
elseif(index==13) then
|
||||
return tostring(game_statistics.get_statistic_count("enemies_surrendered"))
|
||||
elseif(index==14) then
|
||||
return tostring(game_statistics.get_statistic_count("field_dressings"))
|
||||
elseif(index==15) then
|
||||
return (ui_pda_encyclopedia_tab.get_articles_unlocked_count() .. "/" .. ui_pda_encyclopedia_tab.get_articles_count())
|
||||
elseif(index==16) then
|
||||
return (game_achievements.get_achievements_unlocked_count() .. "/" .. game_achievements.get_achievements_count())
|
||||
elseif(index==17) then
|
||||
return (game_statistics.get_actor_visited_levels_count() .. "/33")
|
||||
elseif(index==18) then
|
||||
return (db.actor:money() .. " RU")
|
||||
end
|
||||
return ""
|
||||
end
|
||||
|
||||
----------------------------------------------------------------------------
|
||||
-- Engine->lua function calls
|
||||
----------------------------------------------------------------------------
|
||||
local primary_objects_tbl = {
|
||||
{target="mar_2c_01_anomaly_spot", hint="st_mar_2c_01_anomaly_spot_name"},
|
||||
{target="mar_2c_02_anomaly_spot", hint="st_mar_2c_02_anomaly_spot_name"},
|
||||
{target="ds_2c_01_anomaly_spot", hint="st_ds_2c_01_anomaly_spot_name"},
|
||||
{target="ds_2c_02_anomaly_spot", hint="st_ds_2c_02_anomaly_spot_name"},
|
||||
{target="ds_2c_03_anomaly_spot", hint="st_ds_2c_03_anomaly_spot_name"},
|
||||
{target="ds_2c_04_anomaly_spot", hint="st_ds_2c_04_anomaly_spot_name"},
|
||||
{target="trc_2c_01_rift_anom_spot", hint="st_trc_2c_01_rift_anom_spot_name"},
|
||||
{target="trc_2c_02_chem_anom_spot", hint="st_trc_2c_02_chem_anom_spot_name"},
|
||||
{target="trc_2c_03_desolation_anom_spot", hint="st_trc_2c_03_desolation_anom_spot_name"},
|
||||
{target="esc_2c_01_high_hopes_anomaly_spot", hint="st_esc_2c_01_high_hopes_anomaly_spot_name"},
|
||||
{target="gar_2c_01_nwi_anomaly_spot", hint="st_gar_2c_01_nwi_anomaly_spot_name"},
|
||||
{target="gar_2c_02_toaster_anomaly_spot", hint="st_gar_2c_02_toaster_anomaly_spot_name"},
|
||||
{target="agr_2c_01_hg_anomaly_spot", hint="st_agr_2c_01_hg_anomaly_spot_name"},
|
||||
-- Undergound anomalies are commented out until we can have underground minimaps.
|
||||
--{target="labx18_2c_01_deep_burn_anomaly_spot", hint="st_labx18_2c_01_deep_burn_anomaly_spot_name"},
|
||||
--{target="labx18_2c_02_ff_anomaly_spot", hint="st_labx18_2c_02_ff_anomaly_spot_name"},
|
||||
--{target="labx18_2c_03_elders_anomaly_spot", hint="st_labx18_2c_03_elders_anomaly_spot_name"},
|
||||
--{target="labx18_2c_04_bioh_anomaly_spot", hint="st_labx18_2c_04_bioh_anomaly_spot_name"},
|
||||
{target="bar_2c_01_grant_anomaly_spot", hint="st_bar_2c_01_grant_anomaly_spot_name"},
|
||||
{target="ros_2c_01_tunnel_anomaly_spot", hint="st_ros_2c_01_tunnel_anomaly_spot_name"},
|
||||
{target="ros_2c_02_crispy_train_anomaly_spot", hint="st_ros_2c_02_crispy_train_anomaly_spot_name"},
|
||||
{target="ros_2c_03_yc_anomaly_spot", hint="st_ros_2c_03_yc_anomaly_spot_name"},
|
||||
{target="mil_2c_01_hw_anomaly_spot", hint="st_mil_2c_01_hw_anomaly_spot_name"},
|
||||
{target="yan_2c_01_cd_anomaly_spot", hint="st_yan_2c_01_cd_anomaly_spot_name"},
|
||||
--{target="x16_lab_2c_01_fb_anomy_spot", hint="st_x16_lab_2c_01_fb_anomy_spot_name"},
|
||||
{target="cit_2c_01_ch_anomaly_spot", hint="st_cit_2c_01_ch_anomaly_spot_name"},
|
||||
{target="cit_2c_02_pg_anomaly_spot", hint="st_cit_2c_02_pg_anomaly_spot_name"},
|
||||
{target="lim_2c_01_ls_anomaly_spot", hint="st_lim_2c_01_ls_anomaly_spot_name"},
|
||||
{target="lim_2c_02_ib_anomaly_spot", hint="st_lim_2c_02_ib_anomaly_spot_name"},
|
||||
{target="rad_2c_01_bl_anomaly_spot", hint="st_rad_2c_01_bl_anomaly_spot_name"},
|
||||
{target="rad_2c_02_pp_anomaly_spot", hint="st_rad_2c_02_pp_anomaly_spot_name"},
|
||||
--{target="bun_2c_01_f_anomaly_spot", hint="st_bun_2c_01_f_anomaly_spot_name"},
|
||||
--{target="bun_2c_02_gp_anomaly_spot", hint="st_bun_2c_02_gp_anomaly_spot_name"},
|
||||
{target="pri_2c_01_pp_anomaly_spot", hint="st_pri_2c_01_pp_anomaly_spot_name"},
|
||||
{target="pri_2c_02_gt_anomaly_spot", hint="st_pri_2c_02_gt_anomaly_spot_name"},
|
||||
{target="pri_2c_03_wr_anomaly_spot", hint="st_pri_2c_03_wr_anomaly_spot_name"},
|
||||
{target="pri_2c_04_o_anomaly_spot", hint="st_pri_2c_04_o_anomaly_spot_name"},
|
||||
{target="aes_2c_01_ce_anomaly_spot", hint="st_aes_2c_01_ce_anomaly_spot_name"},
|
||||
{target="aes_2c_02_p_anomaly_spot", hint="st_aes_2c_02_p_anomaly_spot_name"},
|
||||
{target="aes2_2c_01_bo_anomaly_spot", hint="st_aes2_2c_01_bo_anomaly_spot_name"},
|
||||
{target="aes2_2c_02_at_anomaly_spot", hint="st_aes2_2c_02_at_anomaly_spot_name"},
|
||||
--{target="sar_2c_01_r_anomaly_spot", hint="st_sar_2c_01_r_anomaly_spot_name"},
|
||||
{target="gen_2c_01_ss_anomaly_spot", hint="st_gen_2c_01_ss_anomaly_spot_name"},
|
||||
{target="mar_smart_terrain_11_3_anomaly_spot", hint="st_mar_smart_terrain_11_3_anomaly_spot_name"},
|
||||
{target="mar_smart_terrain_10_10_anomaly_spot", hint="st_mar_smart_terrain_10_10_anomaly_spot_name"},
|
||||
{target="mar_smart_terrain_base_anomaly_spot", hint="st_mar_smart_terrain_base_anomaly_spot_name"},
|
||||
{target="mar_smart_terrain_8_8_anomaly_spot", hint="st_mar_smart_terrain_8_8_anomaly_spot_name"},
|
||||
{target="mar_smart_terrain_12_2_anomaly_spot", hint="st_mar_smart_terrain_12_2_anomaly_spot_name"},
|
||||
{target="mar_smart_terrain_3_7_anomaly_spot", hint="st_mar_smart_terrain_3_7_anomaly_spot_name"},
|
||||
{target="mar_smart_terrain_3_3_anomaly_spot", hint="st_mar_smart_terrain_3_3_anomaly_spot_name"},
|
||||
{target="esc_smart_terrain_1_11_anomaly_spot", hint="st_esc_smart_terrain_1_11_anomaly_spot_name"},
|
||||
{target="esc_smart_terrain_8_9_anomaly_spot", hint="st_esc_smart_terrain_8_9_anomaly_spot_name"},
|
||||
{target="esc_smart_terrain_5_4_anomaly_spot", hint="st_esc_smart_terrain_5_4_anomaly_spot_name"},
|
||||
{target="gar_smart_terrain_3_7_anomaly_spot", hint="st_gar_smart_terrain_3_7_anomaly_spot_name"},
|
||||
{target="gar_smart_terrain_3_7_anomaly_spot_2", hint="st_gar_smart_terrain_3_7_anomaly_spot_2_name"},
|
||||
{target="gar_smart_terrain_2_4_anomaly_spot", hint="st_gar_smart_terrain_2_4_anomaly_spot_name"},
|
||||
{target="gar_smart_terrain_6_7_anomaly_spot", hint="st_gar_smart_terrain_6_7_anomaly_spot_name"},
|
||||
{target="gar_smart_terrain_5_6_anomaly_spot", hint="st_gar_smart_terrain_5_6_anomaly_spot_name"},
|
||||
{target="gar_smart_terrain_1_7_anomaly_spot", hint="st_gar_smart_terrain_1_7_anomaly_spot_name"},
|
||||
{target="agr_smart_terrain_1_3_anomaly_spot", hint="st_agr_smart_terrain_1_3_anomaly_spot_name"},
|
||||
{target="agr_smart_terrain_4_4_near_3_anomaly_spot", hint="st_agr_smart_terrain_4_4_near_3_anomaly_spot_name"},
|
||||
{target="agr_smart_terrain_5_7_anomaly_spot", hint="st_agr_smart_terrain_5_7_anomaly_spot_name"},
|
||||
{target="agr_smart_terrain_5_2_anomaly_spot", hint="st_agr_smart_terrain_5_2_anomaly_spot_name"},
|
||||
{target="agr_smart_terrain_1_2_anomaly_spot", hint="st_agr_smart_terrain_1_2_anomaly_spot_name"},
|
||||
{target="val_smart_terrain_9_10_anomaly_spot", hint="st_val_smart_terrain_9_10_anomaly_spot_name"},
|
||||
{target="val_smart_terrain_6_4_anomaly_spot", hint="st_val_smart_terrain_6_4_anomaly_spot_name"},
|
||||
{target="val_smart_terrain_8_6_anomaly_spot", hint="st_val_smart_terrain_8_6_anomaly_spot_name"},
|
||||
{target="val_smart_terrain_9_4_anomaly_spot", hint="st_val_smart_terrain_9_4_anomaly_spot_name"},
|
||||
{target="val_smart_terrain_8_9_anomaly_spot", hint="st_val_smart_terrain_8_9_anomaly_spot_name"},
|
||||
{target="mil_smart_terrain_4_7_anomaly_spot", hint="st_mil_smart_terrain_4_7_anomaly_spot_name"},
|
||||
{target="mil_smart_terrain_2_1_anomaly_spot", hint="st_mil_smart_terrain_2_1_anomaly_spot_name"},
|
||||
{target="mil_smart_terrain_2_6_anomaly_spot", hint="st_mil_smart_terrain_2_6_anomaly_spot_name"},
|
||||
{target="mil_smart_terrain_7_4_anomaly_spot", hint="st_mil_smart_terrain_7_4_anomaly_spot_name"},
|
||||
{target="mil_smart_terrain_8_3_anomaly_spot", hint="st_mil_smart_terrain_8_3_anomaly_spot_name"},
|
||||
{target="yan_smart_terrain_2_5_anomaly_spot", hint="st_yan_smart_terrain_2_5_anomaly_spot_name"},
|
||||
{target="yan_smart_terrain_zombi_spawn_anomaly_spot", hint="st_yan_smart_terrain_zombi_spawn_anomaly_spot_name"},
|
||||
{target="yan_smart_terrain_5_3_anomaly_spot", hint="st_yan_smart_terrain_5_3_anomaly_spot_name"},
|
||||
{target="yan_smart_terrain_4_2_anomaly_spot", hint="st_yan_smart_terrain_4_2_anomaly_spot_name"},
|
||||
{target="red_smart_terrain_6_3_anomaly_spot", hint="st_red_smart_terrain_6_3_anomaly_spot_name"},
|
||||
{target="red_smart_terrain_4_5_anomaly_spot", hint="st_red_smart_terrain_4_5_anomaly_spot_name"},
|
||||
{target="red_smart_terrain_monsters_anomaly_spot", hint="st_red_smart_terrain_monsters_anomaly_spot_name"},
|
||||
{target="red_smart_terrain_3_2_anomaly_spot", hint="st_red_smart_terrain_3_2_anomaly_spot_name"},
|
||||
{target="red_smart_terrain_6_6_anomaly_spot", hint="st_red_smart_terrain_6_6_anomaly_spot_name"},
|
||||
{target="red_smart_terrain_3_1_anomaly_spot", hint="st_red_smart_terrain_3_1_anomaly_spot_name"},
|
||||
{target="gen_smart_terrain_urod_anomaly_spot", hint="st_gen_smart_terrain_urod_anomaly_spot_name"},
|
||||
{target="trc_sim_13_anomal_zone_spot", hint="st_trc_sim_13_anomal_zone_spot_name"},
|
||||
|
||||
-- POLE
|
||||
{target="pol_smart_terrain_1_2_anomaly_spot", hint="st_pol_smart_terrain_1_2_anomaly_spot_name"},
|
||||
|
||||
-- MLR
|
||||
{target="dasc_treesucker_state_spot", hint="st_dasc_treesucker_state_name"},
|
||||
{target="tc_smart_terrain_bandit_base_spot", hint="st_tc_bandit_base_name"},
|
||||
{target="rad_smart_terrain_kpp_spot", hint="st_tc_kpp_name"},
|
||||
{target="rad_smart_terrain_vert_spot", hint="st_tc_vert_name"},
|
||||
{target="radar_smart_terrain_first_zastava_spot", hint="st_radar_first_zastava_name"},
|
||||
{target="rad_smart_terrain_bunker_spot", hint="st_rad_bunker_name"},
|
||||
{target="red_smart_terrain_dark_yar_spot", hint="st_red_dark_yar_name"},
|
||||
{target="red_smart_terrain_central_mine_spot", hint="st_red_central_mine_name"},
|
||||
{target="red_smart_terrain_crap_spot", hint="st_red_crap_name"},
|
||||
{target="agr_smart_terrai_SRI_spot", hint="st_agr_SRI_name"},
|
||||
{target="mar_smart_terrain_post_spot", hint="st_lim_post_vishka_name"},
|
||||
{target="mar_smart_terrain_old_church_spot", hint="st_lim_old_church_name"},
|
||||
{target="mar_smart_terrain_village_csky_spot", hint="st_lim_village_csky_name"},
|
||||
{target="mar_smart_terrain_water_pump_station_spot", hint="st_lim_water_pump_station_name"},
|
||||
{target="mar_smart_terrain_mechanic_yard_spot", hint="st_lim_mechanic_yard_name"},
|
||||
{target="red_smart_terrain_bridge_spot", hint="st_lim_bridge_name"},
|
||||
{target="red_smart_terrain_house_lesnik_spot", hint="st_lim_house_lesnik_name"},
|
||||
{target="lim_smart_first_zastava_spot", hint="st_lim_zastava_name"},
|
||||
{target="lim_smart_bubbles_spot", hint="st_lim_bubbles_name"},
|
||||
{target="lim_smart_nonbuild_spot", hint="st_lim_nonbuild_name"},
|
||||
{target="lim_smart_dyga_spot", hint="st_lim_dyga_name"},
|
||||
{target="ds_smart_administration_spot", hint="st_ds_administration_name"},
|
||||
{target="ds_smart_market_spot", hint="st_ds_market_name"},
|
||||
{target="ds_smart_house_of_culture_spot", hint="st_ds_HoC_name"},
|
||||
{target="esc_smart_terrain_novice_village_spot", hint="st_novice_village_name"},
|
||||
{target="esc_smart_terrain_south_blokpost_spot", hint="st_south_blokpost_name"},
|
||||
{target="esc_smart_terrain_ATP_spot", hint="st_ATP_name"},
|
||||
{target="esc_smart_terrain_elevator_spot", hint="st_elevator_name"},
|
||||
{target="esc_smart_terrain_tunnel_electr_spot", hint="st_tunnel_electr_name"},
|
||||
{target="esc_smart_terrain_neut_base_spot", hint="st_neut_base_name"},
|
||||
{target="esc_smart_terrain_north_blockpost_spot", hint="st_north_blockpost_name"},
|
||||
{target="dar_smart_terrain_farm_spot", hint="st_dar_farm_name"},
|
||||
{target="dar_smart_terrain_complex_proizv_spot", hint="st_dar_complex_name"},
|
||||
{target="mil_smart_terrain_bs_village_spot", hint="st_bs_village_name"},
|
||||
{target="mil_smart_terrain_base_freedom_spot", hint="st_base_freedom_name"},
|
||||
{target="mil_smart_terrain_border_spot", hint="st_border_name"},
|
||||
{target="pri_smart_terrain_mon_base_spot", hint="st_mon_base_name"},
|
||||
{target="pri_smart_terrain_hotel_poless_spot", hint="st_hotel_poless_name"},
|
||||
{target="pri_smart_terrain_big_bus_station_spot", hint="st_big_bus_station_name"},
|
||||
{target="gar_smart_terrain_6_3_baraholka_spot", hint="st_gar_baraholka_name"},
|
||||
{target="gar_smart_terrain_dolg_outpost_spot", hint="st_gar_outpost_name"},
|
||||
{target="gar_smart_terrain_3_5_angar_spot", hint="st_gar_angar_name"},
|
||||
{target="bar_smart_terrain_bar100rent_spot", hint="st_bar100rent_name"},
|
||||
{target="yan_smart_terrain_6_4_bunker_spot", hint="st_yanbunker_name"},
|
||||
{target="yan_smart_terrain_proizvcomplex_spot", hint="st_yancomplex_name"},
|
||||
|
||||
{target="zat_b55_spot", hint="st_zat_b55_name_land"},
|
||||
{target="zat_b100_spot", hint="st_zat_b100_name_land"},
|
||||
{target="zat_b104_spot", hint="st_zat_b104_name_land"},
|
||||
{target="zat_b38_spot", hint="st_zat_b38_name_land"},
|
||||
{target="zat_b40_spot", hint="st_zat_b40_name_land"},
|
||||
{target="zat_b56_spot", hint="st_zat_b56_name_land"},
|
||||
{target="zat_b5_spot", hint="st_zat_b5_name_land"},
|
||||
{target="zat_a2_spot", hint="st_zat_a2_name_land"},
|
||||
{target="zat_b20_spot", hint="st_zat_b20_name_land"},
|
||||
{target="zat_b20_spot", hint="st_zat_fire_name_land"},
|
||||
{target="zat_b53_spot", hint="st_zat_b53_name_land"},
|
||||
{target="zat_b101_spot", hint="st_zat_b101_name_land"},
|
||||
{target="zat_b101_spot", hint="st_zat_waste_name_land"},
|
||||
{target="zat_b106_spot", hint="st_zat_b106_name_land"},
|
||||
{target="zat_b7_spot", hint="st_zat_b7_name_land"},
|
||||
{target="zat_b14_spot", hint="st_zat_b14_name_land"},
|
||||
{target="zat_b14_spot", hint="st_zat_tide_name_land"},
|
||||
{target="zat_b52_spot", hint="st_zat_b52_name_land"},
|
||||
{target="zat_b39_spot", hint="st_zat_b39_name_land"},
|
||||
{target="zat_b33_spot", hint="st_zat_b33_name_land"},
|
||||
{target="zat_b18_spot", hint="st_zat_b18_name_land"},
|
||||
{target="zat_b54_spot", hint="st_zat_b54_name_land"},
|
||||
{target="zat_b12_spot", hint="st_zat_b12_name_land"},
|
||||
{target="zat_b28_spot", hint="st_zat_b28_name_land"},
|
||||
{target="zat_b103_spot", hint="st_zat_b103_name_land"},
|
||||
{target="jup_b1_spot", hint="st_jup_b1_name_land"},
|
||||
{target="jup_b46_spot", hint="st_jup_b46_name_land"},
|
||||
{target="jup_b202_spot", hint="st_jup_b202_name_land"},
|
||||
{target="jup_b211_spot", hint="st_jup_b211_name_land"},
|
||||
{target="jup_b200_spot", hint="st_jup_b200_name_land"},
|
||||
{target="jup_b19_spot", hint="st_jup_b19_name_land"},
|
||||
{target="jup_a6_spot", hint="st_jup_a6_name_land"},
|
||||
{target="jup_b25_spot", hint="st_jup_b25_name_land"},
|
||||
{target="jup_b25_spot", hint="st_jup_earth_name_land"},
|
||||
{target="jup_b6_spot", hint="st_jup_b6_name_land"},
|
||||
{target="jup_b205_spot", hint="st_jup_b205_name_land"},
|
||||
{target="jup_b206_spot", hint="st_jup_b206_name_land"},
|
||||
{target="jup_b206_spot", hint="st_jup_grove_name_land"},
|
||||
{target="jup_b32_spot", hint="st_jup_b32_name_land"},
|
||||
{target="jup_a10_spot", hint="st_jup_a10_name_land"},
|
||||
{target="jup_b209_spot", hint="st_jup_b209_name_land"},
|
||||
{target="jup_b208_spot", hint="st_jup_b208_name_land"},
|
||||
{target="jup_a12_spot", hint="st_jup_a12_name_land"},
|
||||
{target="jup_b212_spot", hint="st_jup_b212_name_land"},
|
||||
{target="jup_b9_spot", hint="st_jup_b9_name_land"},
|
||||
{target="jup_b201_spot", hint="st_jup_b201_name_land"},
|
||||
{target="jup_a9_spot", hint="st_jup_a9_name_land"},
|
||||
|
||||
{target="pri_a28_spot", hint="st_pri_a28_name_land"},
|
||||
{target="pri_b36_spot", hint="st_pri_b36_name_land"},
|
||||
{target="pri_b303_spot", hint="st_pri_b303_name_land"},
|
||||
{target="pri_b301_spot", hint="st_pri_b301_name_land"},
|
||||
{target="pri_a17_spot", hint="st_pri_a17_name_land"},
|
||||
{target="pri_b306_spot", hint="st_pri_b306_name_land"},
|
||||
{target="pri_b306_spot", hint="st_pri_plug_name_land"},
|
||||
{target="pri_a16_spot", hint="st_pri_a16_name_land"},
|
||||
{target="pri_a25_spot", hint="st_pri_a25_name_land"},
|
||||
{target="pri_b35_spot", hint="st_pri_b35_name_land"},
|
||||
{target="pri_a21_spot", hint="st_pri_a21_name_land"},
|
||||
{target="pri_b304_spot", hint="st_pri_b304_name_land"},
|
||||
{target="pri_b304_spot", hint="st_pri_bath_name_land"},
|
||||
{target="pri_a18_spot", hint="st_pri_a18_name_land"},
|
||||
{target="pri_anomal_vulkan_spot", hint="st_pri_b307_name_land"},
|
||||
{target="pri_anomal_loza_spot", hint="st_pri_b302_name_land"}
|
||||
}
|
||||
|
||||
function fill_primary_objects()
|
||||
for k,v in pairs(primary_objects_tbl) do
|
||||
local obj_id = get_story_object_id(v.target)
|
||||
--/ SGM in
|
||||
if obj_id and (level.map_has_object_spot(obj_id,"primary_object") == 0) and has_alife_info(v.target) then
|
||||
level.map_add_object_spot(obj_id, "primary_object", v.hint)
|
||||
end
|
||||
--/ SGM out
|
||||
end
|
||||
|
||||
local sleep_zones_tbl =
|
||||
{ "mar_a3_sr_sleep_id",
|
||||
"agr_sr_sleep_wagon_id",
|
||||
"agr_sr_sleep_tunnel_id",
|
||||
"agr_army_sleep_id",
|
||||
"esc_basement_sleep_area_id",
|
||||
"esc_secret_sleep_id",
|
||||
"ds_farmhouse_sleep_id",
|
||||
"val_abandoned_house_sleep_id",
|
||||
"val_vagon_sleep_id",
|
||||
"gar_dolg_sleep_id",
|
||||
"gar_angar_sleep_id",
|
||||
"bar_actor_sleep_zone_id",
|
||||
"yan_bunker_sleep_restrictor_id",
|
||||
"ros_vagon_sleep_id",
|
||||
"mil_freedom_sleep_id",
|
||||
"mil_smart_terran_2_4_sleep_id",
|
||||
"rad_sleep_room_id",
|
||||
"cit_merc_sleep_id",
|
||||
"pri_monolith_sleep_id",
|
||||
"pri_room27_sleep_id",
|
||||
"zat_a2_sr_sleep_id",
|
||||
"jup_a6_sr_sleep_id",
|
||||
"pri_a16_sr_sleep_id",
|
||||
"pol_secret_sleep_id"
|
||||
}
|
||||
for i=1,#sleep_zones_tbl do
|
||||
local obj_id = get_story_object_id(sleep_zones_tbl[i])
|
||||
if (level.map_has_object_spot(obj_id, "ui_pda2_actor_sleep_location")==0) then
|
||||
level.map_add_object_spot_ser(obj_id, "ui_pda2_actor_sleep_location", "st_ui_pda_sleep_place")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function add_quick_slot_items_on_game_start()
|
||||
for i=0,3 do
|
||||
exec_console_cmd( strformat("slot_%s %s",i, ini_sys:r_string_ex("actor","quick_item_"..tostring(i+1)) or "") )
|
||||
end
|
||||
end
|
||||
|
||||
----------------------------------------------------------------------------
|
||||
-- Scripted Callback Register
|
||||
----------------------------------------------------------------------------
|
||||
local function npc_on_net_spawn(npc,se_obj)
|
||||
se_save_var(se_obj.id,se_obj:name(),"last_seen_level",level.name())
|
||||
se_save_var(se_obj.id,se_obj:name(),"last_seen_time",game.get_game_time())
|
||||
end
|
||||
|
||||
function on_game_start()
|
||||
local function on_game_load()
|
||||
if (not alife_storage_manager.get_state().enable_warfare_mode) then
|
||||
CreateTimeEvent(0, "ScanForSpots", 2, discover_spots)
|
||||
end
|
||||
end
|
||||
|
||||
RegisterScriptCallback("npc_on_net_spawn",npc_on_net_spawn)
|
||||
RegisterScriptCallback("on_game_load",on_game_load)
|
||||
end
|
||||
|
||||
-- mlr
|
||||
----------------------------------------------------------------------------
|
||||
-- Character Ranking
|
||||
----------------------------------------------------------------------------
|
||||
function get_coc_ranking_list()
|
||||
for i=1,10 do
|
||||
printf("- get_coc_ranking_list | id [%s] = %s", i , coc_ranking_list[i])
|
||||
end
|
||||
return coc_ranking_list
|
||||
end
|
||||
|
||||
-- called from info_portions.script
|
||||
function calculate_rankings()
|
||||
local t = {}
|
||||
local sim = alife()
|
||||
-- add actor to list
|
||||
t[0] = sim:actor():rank()
|
||||
|
||||
-- check all stalker server objects
|
||||
for i=1,65534 do
|
||||
local se_obj = sim:object(i)
|
||||
if (se_obj and IsStalker(nil,se_obj:clsid()) and se_obj:alive() and se_obj:community() ~= "zombied" and se_obj:community() ~= "trader") then
|
||||
-- Check if object has a story id, if it does they are probably unique
|
||||
local sid = story_objects.story_id_by_object_id[se_obj.id]
|
||||
if not (sid) then
|
||||
t[se_obj.id] = se_obj:rank()
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
coc_ranking_list = iempty_table(coc_ranking_list)
|
||||
local size_t = 0
|
||||
-- sort by highest rank first
|
||||
for id,rank in spairs(t, function(t,a,b) return t[a] > t[b] end) do
|
||||
size_t = size_t + 1
|
||||
coc_ranking_list[size_t] = id
|
||||
if (id == AC_ID) then
|
||||
actor_rank_place = size_t
|
||||
end
|
||||
end
|
||||
|
||||
-- force actor into last visible slot + 1 on ranking list
|
||||
coc_ranking_list[coc_ranking_array_size+1] = 0
|
||||
end
|
||||
|
||||
-- called from engine! It's how many character rankings to display! u8 (max 255)
|
||||
function get_rankings_array_size()
|
||||
return coc_ranking_array_size
|
||||
end
|
||||
|
||||
-- called from engine! must return bool!
|
||||
function coc_rankings_can_show(index)
|
||||
if (has_alife_info("ui_pda_hide")) then
|
||||
return false
|
||||
end
|
||||
local se_obj = coc_ranking_list[index] ~= nil and alife_object(coc_ranking_list[index])
|
||||
if (se_obj) then
|
||||
return true
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
-- called from engine! must return string!
|
||||
function coc_rankings_set_name(index)
|
||||
local se_obj = coc_ranking_list[index] ~= nil and alife_object(coc_ranking_list[index])
|
||||
if (se_obj) then
|
||||
return strformat("%s. %s",se_obj.id == AC_ID and actor_rank_place or index,se_obj:character_name())
|
||||
end
|
||||
return ""
|
||||
end
|
||||
|
||||
-- called from engine! must return string!
|
||||
function coc_rankings_set_hint(index)
|
||||
local se_obj = coc_ranking_list[index] ~= nil and alife_object(coc_ranking_list[index])
|
||||
if (se_obj) then
|
||||
if (se_obj.id == AC_ID) then
|
||||
--TODO: Maybe some stats for player, like rank points per minute; if such a thing is possible.
|
||||
return ""
|
||||
else
|
||||
local return_str = ""
|
||||
|
||||
-- DEBUG REMOVE ME LATER
|
||||
if(DEV_DEBUG and ui_options.get("other/debug_hud") == true) then
|
||||
return_str = se_obj:profile_name() .. [[ \n]] .. se_obj:character_icon() .. [[ \n]]
|
||||
end
|
||||
|
||||
-- stalker stats
|
||||
local m_data = alife_storage_manager.get_se_obj_state(se_obj)
|
||||
if (m_data) then
|
||||
local last_seen_level = m_data.last_seen_level
|
||||
local last_seen_time = m_data.last_seen_time and m_data.last_seen_time.dateToString and m_data.last_seen_time:dateToString(game.CTime.DateToDay)
|
||||
|
||||
if (last_seen_level and last_seen_time) then
|
||||
return_str = return_str .. game.translate_string("st_last_seen") .. ": " .. game.translate_string(last_seen_level) .. " (" .. last_seen_time .. ")"
|
||||
|
||||
if (m_data["killed_stalkers"]) then
|
||||
return_str = return_str .. [[ \n]] .. game.translate_string("st_stalkers_killed") .. ": " .. tostring(m_data["killed_stalkers"])
|
||||
end
|
||||
if (m_data["killed_monsters"]) then
|
||||
return_str = return_str .. [[ \n]] .. game.translate_string("st_mutants_killed") .. ": " .. tostring(m_data["killed_monsters"])
|
||||
end
|
||||
if (m_data["artefacts_found"]) then
|
||||
return_str = return_str .. [[ \n]] .. game.translate_string("st_artefacts_found") .. ": " .. tostring(m_data["artefacts_found"])
|
||||
end
|
||||
if (m_data["wounded_helped"]) then
|
||||
return_str = return_str .. [[ \n]] .. game.translate_string("st_wounded_helped") .. ": " .. tostring(m_data["wounded_helped"])
|
||||
end
|
||||
if (m_data["corpse_looted"]) then
|
||||
return_str = return_str .. [[ \n]] .. game.translate_string("st_corpse_looted") .. ": " .. tostring(m_data["corpse_looted"])
|
||||
end
|
||||
if (m_data["items_sold"]) then
|
||||
return_str = return_str .. [[ \n]] .. game.translate_string("st_items_sold") .. ": " .. tostring(m_data["items_sold"])
|
||||
end
|
||||
end
|
||||
end
|
||||
return return_str
|
||||
end
|
||||
end
|
||||
return ""
|
||||
end
|
||||
|
||||
-- called from engine! must return string!
|
||||
function coc_rankings_set_description(index)
|
||||
local se_obj = coc_ranking_list[index] ~= nil and alife_object(coc_ranking_list[index])
|
||||
if (se_obj) then
|
||||
local faction_color = "%c[255,255,255,1]"
|
||||
if (game_relations.is_factions_enemies(db.actor:character_community(),se_obj:community())) then
|
||||
faction_color = "%c[255,255,1,1]"
|
||||
elseif (game_relations.is_factions_friends(db.actor:character_community(),se_obj:community())) then
|
||||
faction_color = "%c[255,1,255,1]"
|
||||
end
|
||||
|
||||
local reputation = se_obj:reputation()
|
||||
|
||||
local repu_color = "%c[255,255,255,1]"
|
||||
if (reputation <= -500) then
|
||||
repu_color = "%c[255,255,1,1]"
|
||||
elseif (reputation >= 500) then
|
||||
repu_color = "%c[255,1,255,1]"
|
||||
end
|
||||
|
||||
local faction_str = game.translate_string("ui_st_community") .. ": " .. faction_color .. game.translate_string(se_obj:community()) .. "%c[default]"
|
||||
local rank_str = game.translate_string("ui_st_rank") .. ": " .. "%c[255,215,215,215]" .. game.translate_string("st_rank_"..ranks.get_se_obj_rank_name(se_obj)) .. " %c[255,110,110,255]" .. se_obj:rank() .. "%c[default]"
|
||||
local repu_str = game.translate_string("ui_st_reputation") .. ": " .. repu_color .. game.translate_string(utils_obj.get_reputation_name(reputation)) .. "%c[default]"
|
||||
|
||||
return strformat([[ %s \n %s \n %s]],faction_str,rank_str,repu_str)
|
||||
end
|
||||
return ""
|
||||
end
|
||||
|
||||
-- called from engine! must return string!
|
||||
function coc_rankings_set_icon(index)
|
||||
local se_obj = coc_ranking_list[index] ~= nil and alife_object(coc_ranking_list[index])
|
||||
if (se_obj) then
|
||||
local icon_name
|
||||
if (se_obj.id == AC_ID) then
|
||||
if (ui_options.get("gameplay/general/outfit_portrait") == true) then
|
||||
local outfit = db.actor:item_in_slot(7)
|
||||
if (outfit) then
|
||||
local icon = ini_sys:r_string_ex(outfit:section(),"character_portrait")
|
||||
if (icon and icon ~= "") then
|
||||
return icon
|
||||
end
|
||||
end
|
||||
end
|
||||
icon_name = db.actor:character_icon()
|
||||
else
|
||||
local npc = db.storage[se_obj.id] and db.storage[se_obj.id].object
|
||||
if (npc) then
|
||||
icon_name = npc:character_icon()
|
||||
else
|
||||
icon_name = se_obj:character_icon()
|
||||
end
|
||||
end
|
||||
return icon_name and icon_name ~= "" and icon_name or "ui\\ui_noise"
|
||||
end
|
||||
return ""
|
||||
end
|
||||
|
||||
function coc_rankings_show_border(index)
|
||||
local se_obj = coc_ranking_list[index] ~= nil and alife_object(coc_ranking_list[index])
|
||||
return se_obj and se_obj.id == AC_ID or false
|
||||
end
|
||||
|
||||
local distance_tbl = {
|
||||
["l12_stancia"] = 45,
|
||||
["l12_stancia_2"] = 45,
|
||||
["l11_hospital"] = 30,
|
||||
["l10_limansk"] = 35,
|
||||
["l06_rostok"] = 30,
|
||||
["k02_trucks_cemetery"] = 45,
|
||||
}
|
||||
function discover_spots()
|
||||
ResetTimeEvent(0,"ScanForSpots",3)
|
||||
|
||||
local actor = db.actor
|
||||
for k,v in pairs(primary_objects_tbl) do
|
||||
if actor:dont_has_info(v.target) then
|
||||
local obj_id = get_story_object_id(v.target)
|
||||
if obj_id and db.storage[obj_id] and db.storage[obj_id].object then
|
||||
local n_dist = distance_tbl[level.name()] or 40
|
||||
if (db.storage[obj_id].object:position():distance_to(actor:position()) <= n_dist) then
|
||||
give_info(v.target)
|
||||
game_statistics.increment_rank(10)
|
||||
actor_menu.set_fade_msg( game.translate_string(v.hint), 5, nil, "device\\pda\\spot_discovered" )
|
||||
--news_manager.send_tip(actor,game.translate_string(v.hint),0,"tourist",5000,nil,game.translate_string("st_revealled_area"))
|
||||
fill_primary_objects()
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,437 @@
|
||||
--'******************************************************
|
||||
--'*Registry of smart terrains. The playing field simulation.
|
||||
-- Edited by Alundaio
|
||||
--'******************************************************
|
||||
-------------------
|
||||
local level,alife,game_graph,math,pairs,tostring,tonumber,tsort,tinsert = level,alife,game_graph,math,pairs,tostring,tonumber,table.sort,table.insert
|
||||
-------------------
|
||||
-----------------------------------------------------------------------------------
|
||||
-- Public
|
||||
-----------------------------------------------------------------------------------
|
||||
function general_squad_precondition(squad,target)
|
||||
return false
|
||||
end
|
||||
|
||||
function general_base_precondition(squad,target)
|
||||
|
||||
-- Any faction can target a base occupied by their own community / or empty
|
||||
if (target.faction == nil or target.faction == squad.player_id) then
|
||||
return true
|
||||
end
|
||||
|
||||
-- if a base is occupied by enemies, squad can target it during early sunrise time
|
||||
if (game_relations.is_valid(squad.player_id) and game_relations.is_valid(target.faction)) then
|
||||
if (game_relations.is_factions_enemies(squad.player_id,target.faction)) then
|
||||
return in_time_interval(3,6)
|
||||
else
|
||||
return true
|
||||
end
|
||||
end
|
||||
|
||||
return false
|
||||
end
|
||||
|
||||
function general_territory_precondition(squad,target)
|
||||
|
||||
-- Mutants target territories based on their species and proper time
|
||||
if (squad.player_id == "monster_predatory_day") then
|
||||
return in_time_interval(6,19)
|
||||
elseif (squad.player_id == "monster_predatory_night") then
|
||||
return in_time_interval(19,6)
|
||||
elseif (squad.player_id == "monster_zombied_day") then
|
||||
return in_time_interval(6,19)
|
||||
elseif (squad.player_id == "monster_zombied_night") then
|
||||
return in_time_interval(19,6)
|
||||
elseif (squad.player_id == "monster_vegetarian" or squad.player_id == "zombied") then
|
||||
return true
|
||||
end
|
||||
|
||||
-- Any squad can target a territory occupied by their own community / or empty
|
||||
if (target.faction == nil or target.faction == squad.player_id) then
|
||||
return true
|
||||
end
|
||||
|
||||
-- if a territory is occupied by enemies, squad can target it during daytime
|
||||
if (game_relations.is_valid(squad.player_id) and game_relations.is_valid(target.faction)) then
|
||||
if (game_relations.is_factions_enemies(squad.player_id,target.faction)) then
|
||||
return in_time_interval(9,15)
|
||||
else
|
||||
return true
|
||||
end
|
||||
end
|
||||
|
||||
return false
|
||||
end
|
||||
|
||||
function general_resource_precondition(squad,target)
|
||||
return in_time_interval(10,6)
|
||||
end
|
||||
|
||||
function general_lair_precondition(squad,target)
|
||||
return true -- Will fill up all the lairs first, by monster squads
|
||||
end
|
||||
|
||||
--------------------------------------------------------------------------------------------------------
|
||||
-- SIMULATION BOARD
|
||||
--------------------------------------------------------------------------------------------------------
|
||||
|
||||
class "simulation_board"
|
||||
function simulation_board:__init()
|
||||
--' smart = {smrt, targets = {}, dangers = {}, squads = {}, stayed_squads = {}}
|
||||
self.smarts = {}
|
||||
self.smarts_by_names = {}
|
||||
self.simulation_started = true
|
||||
self.squads = {}
|
||||
self.tmp_assigned_squad = {}
|
||||
end
|
||||
|
||||
function simulation_board:register_smart(obj)
|
||||
--utils_data.debug_write(strformat("simulation_board:register_smart %s",obj and obj:name()))
|
||||
if self.smarts[obj.id] ~= nil then
|
||||
printf("Smart already exist in list [%s]", obj:name())
|
||||
return
|
||||
end
|
||||
|
||||
--self.smarts[obj.id] = {smrt = obj, squads = {}, stayed_squads = {}, population = 0}
|
||||
self.smarts[obj.id] = {smrt = obj, squads = {}, population = 0}
|
||||
self.smarts_by_names[obj:name()] = obj
|
||||
end
|
||||
|
||||
function simulation_board:unregister_smart(obj)
|
||||
--utils_data.debug_write(strformat("simulation_board:unregister_smart %s",obj and obj:name()))
|
||||
self.smarts[obj.id] = nil
|
||||
self.smarts_by_names[obj:name()] = nil
|
||||
end
|
||||
|
||||
function simulation_board:start_sim() -- Doesn't seem to be used in 1.6
|
||||
self.simulation_started = true
|
||||
end
|
||||
|
||||
function simulation_board:stop_sim() -- Doesn't seem to be used in 1.6
|
||||
self.simulation_started = false
|
||||
end
|
||||
|
||||
function simulation_board:set_actor_community(community)
|
||||
---- Set the player grouping
|
||||
db.actor:set_character_community(actor_communitites[community], 0, 0)
|
||||
end
|
||||
|
||||
-- Smart initialization
|
||||
function simulation_board:init_smart(obj)
|
||||
--utils_data.debug_write(strformat("simulation_board:init_smart %s",obj and obj:name()))
|
||||
if self.tmp_assigned_squad[obj.id] ~= nil then
|
||||
for k,v in pairs(self.tmp_assigned_squad[obj.id]) do
|
||||
self:assign_squad_to_smart(v, obj.id)
|
||||
end
|
||||
self.tmp_assigned_squad[obj.id] = nil
|
||||
end
|
||||
end
|
||||
|
||||
--' Create a new squad
|
||||
function simulation_board:create_squad(spawn_smart, sq_id)
|
||||
--utils_data.debug_write(strformat("simulation_board:create_squad spawn_smart=%s sq_id=%s",spawn_smart and spawn_smart:name(),sq_id))
|
||||
local squad_id = tostring(sq_id)
|
||||
-- if not (ini_sys:section_exist(squad_id)) then
|
||||
-- printf("squad section does not exist: %s",squad_id)
|
||||
-- return
|
||||
-- end
|
||||
|
||||
local squad = alife_create(squad_id,spawn_smart.position, spawn_smart.m_level_vertex_id,spawn_smart.m_game_vertex_id)
|
||||
squad:create_npc(spawn_smart)
|
||||
self:assign_squad_to_smart(squad, spawn_smart.id)
|
||||
|
||||
local sim = alife()
|
||||
for k in squad:squad_members() do
|
||||
local se_obj = k.object or k.id and sim:object(k.id)
|
||||
if (se_obj) then
|
||||
SIMBOARD:setup_squad_and_group(se_obj)
|
||||
-- Alundaio
|
||||
SendScriptCallback("squad_on_npc_creation",squad,se_obj,spawn_smart)
|
||||
-- Alundaio
|
||||
end
|
||||
end
|
||||
|
||||
-- SMR
|
||||
smr_debug.get_log().info("simboard", "setting up civil war relations for squad %s (smart: %s)", squad:section_name(), spawn_smart:name())
|
||||
smr_civil_war.setup_civil_war_squad(squad, spawn_smart:name())
|
||||
-- SMR END
|
||||
return squad
|
||||
end
|
||||
|
||||
function simulation_board:create_squad_at_named_location(loc_name, squad_id) -- tdef
|
||||
|
||||
-- if not (ini_file('misc\\squad_descr.ltx'):section_exist(squad_id)) then
|
||||
if not (ini_sys:section_exist(squad_id)) then
|
||||
callstack()
|
||||
printf("create_squad_at_named_location: squad section does not exist in misc\\squad_descr.ltx: %s",squad_id)
|
||||
return
|
||||
end
|
||||
|
||||
local str = utils_data.read_from_ini(ini_file("named_locations.ltx"),loc_name,'position')
|
||||
|
||||
if not str then
|
||||
callstack()
|
||||
printf('create_squad_at_named_location: named location not defined in named_locations.ltx: %s',loc_name)
|
||||
return
|
||||
end
|
||||
|
||||
-- printf('%s: %s',loc_name, str)
|
||||
|
||||
local function str_explode_num(str,sep,plain)
|
||||
if not (sep ~= "" and string.find(str,sep,1,plain)) then
|
||||
return { str }
|
||||
end
|
||||
local t = {}
|
||||
local size = 0
|
||||
for s in str:gsplit(sep,plain) do
|
||||
size = size + 1
|
||||
t[size] = tonumber(s)
|
||||
if not t[size] then
|
||||
printf("str_explode_num: warning: %s couldn't be parsed as number", s)
|
||||
end
|
||||
end
|
||||
return t
|
||||
end
|
||||
local data = str_explode_num(str,',')
|
||||
|
||||
-- for k,v in pairs(data) do
|
||||
-- printf('data[%s] = %s (%s)',k, v, type(v))
|
||||
-- end
|
||||
|
||||
local pos = vector():set(data[1], data[2], data[3])
|
||||
|
||||
local squad = alife_create(squad_id, pos, data[4], data[5])
|
||||
if squad then
|
||||
-- printf('create_squad_at_named_location: squad created %s',squad.id)
|
||||
end
|
||||
squad:create_npc(nil, pos, data[4], data[5])
|
||||
|
||||
local sim = alife()
|
||||
for k in squad:squad_members() do
|
||||
local se_obj = k.object or k.id and sim:object(k.id)
|
||||
if (se_obj) then
|
||||
SIMBOARD:setup_squad_and_group(se_obj)
|
||||
-- Alundaio
|
||||
SendScriptCallback("squad_on_npc_creation",squad,se_obj)
|
||||
-- Alundaio
|
||||
end
|
||||
end
|
||||
return squad
|
||||
end
|
||||
|
||||
--' Remove squad
|
||||
function simulation_board:remove_squad(squad)
|
||||
--utils_data.debug_write(strformat("simulation_board:remove_squad %s",squad and squad:name()))
|
||||
|
||||
self:assign_squad_to_smart(squad, nil)
|
||||
|
||||
squad:remove_squad()
|
||||
end
|
||||
--' Assignment squad in smart.
|
||||
function simulation_board:assign_squad_to_smart(squad, smart_id)
|
||||
--utils_data.debug_write(strformat("simulation_board:assign_squad_to_smart %s smart_id=%s",squad and squad:name(),smart_id))
|
||||
|
||||
if (smart_id and self.smarts[smart_id] == nil) then
|
||||
if self.tmp_assigned_squad[smart_id] == nil then
|
||||
self.tmp_assigned_squad[smart_id] = {}
|
||||
end
|
||||
local t = self.tmp_assigned_squad[smart_id]
|
||||
t[#t+1] = squad
|
||||
return
|
||||
end
|
||||
|
||||
local old_smart_id = squad.smart_id
|
||||
squad.smart_id = nil
|
||||
|
||||
-- remove squad from old smart if exist
|
||||
if (old_smart_id and self.smarts[old_smart_id] and self.smarts[old_smart_id].squads[squad.id]) then
|
||||
self.smarts[old_smart_id].squads[squad.id] = nil
|
||||
-- get accurate population count excluding squads using target_smart param
|
||||
self.smarts[old_smart_id].population = smart_terrain.smart_terrain_squad_count(SIMBOARD.smarts[old_smart_id].squads)
|
||||
SendScriptCallback("squad_on_leave_smart",squad,self.smarts[old_smart_id].smrt)
|
||||
end
|
||||
|
||||
if smart_id == nil then
|
||||
squad:assign_smart(nil,old_smart_id)
|
||||
return
|
||||
end
|
||||
|
||||
squad:assign_smart(self.smarts[smart_id].smrt,old_smart_id)
|
||||
|
||||
--' ����������� ����� � ����� ������.
|
||||
if not (self.smarts[smart_id].squads[squad.id]) then
|
||||
self.smarts[smart_id].squads[squad.id] = true
|
||||
if not (squad:get_script_target()) then
|
||||
-- don't count squads with target_smart
|
||||
self.smarts[smart_id].population = self.smarts[smart_id].population + 1
|
||||
end
|
||||
end
|
||||
|
||||
SendScriptCallback("squad_on_enter_smart",squad,self.smarts[smart_id].smrt)
|
||||
end
|
||||
|
||||
local community_groups = {}
|
||||
-- Set squad and group according to work
|
||||
function simulation_board:setup_squad_and_group(se_obj)
|
||||
--utils_data.debug_write(strformat("simulation_board:setup_squad_and_group %s",obj and obj:name()))
|
||||
local sim = alife()
|
||||
local squad = se_obj.group_id and se_obj.group_id ~= 65535 and sim:object(se_obj.group_id)
|
||||
if not (squad) then
|
||||
change_team_squad_group(se_obj, se_obj.team, se_obj.squad, 0)
|
||||
return
|
||||
end
|
||||
|
||||
local smart = squad.smart_id and sim:object(squad.smart_id)
|
||||
change_team_squad_group(se_obj, se_obj.team, smart and smart.squad_id or se_obj.squad, 1)
|
||||
end
|
||||
|
||||
-- Filling start location for squads from "simulation.ltx"
|
||||
function simulation_board:fill_start_position()
|
||||
|
||||
-- SMR
|
||||
smr_civil_war.setup_factions_relation()
|
||||
-- SMR END
|
||||
|
||||
-- Test map
|
||||
if (axr_main.config:r_value("character_creation","new_game_test",1) == true) then
|
||||
axr_main.config:w_value("character_creation","new_game_test")
|
||||
axr_main.config:save()
|
||||
|
||||
-- Prevent spawn terrains from spawning NPCs
|
||||
if ui_debug_launcher then
|
||||
ui_debug_launcher.toggle_respawn()
|
||||
end
|
||||
|
||||
printf("---------------- Welcome To Test Map ----------------")
|
||||
return
|
||||
end
|
||||
|
||||
SendScriptCallback("fill_start_position")
|
||||
|
||||
if self.start_position_filled == true then
|
||||
return
|
||||
end
|
||||
self.start_position_filled = true
|
||||
|
||||
-- SMR
|
||||
local setting_ini = smr_pop.get_population_preset()
|
||||
local stalker_pop_factor = smr_pop.get_stalker_pop_factor()
|
||||
local monster_pop_factor = smr_pop.get_monster_pop_factor()
|
||||
-- SMR END
|
||||
|
||||
local result, squad_section, count, li, lc
|
||||
setting_ini:section_for_each(function(section)
|
||||
lc = setting_ini:line_count(section)
|
||||
for li=0,lc-1 do
|
||||
local smart = self.smarts_by_names[section]
|
||||
if (smart) then
|
||||
result, squad_section, count = setting_ini:r_line(section,li,"","")
|
||||
count = tonumber(count) or 1
|
||||
|
||||
local common = ini_sys:r_bool_ex(squad_section,"common")
|
||||
local faction = ini_sys:r_string_ex(squad_section,"faction")
|
||||
if common then
|
||||
|
||||
-- Common mutants
|
||||
if is_squad_monster[faction] then
|
||||
count = count*monster_pop_factor
|
||||
if (count == 0.5) then
|
||||
count = math.random(0,1)
|
||||
else
|
||||
count = round_idp(count)
|
||||
end
|
||||
|
||||
-- Common stalkers
|
||||
else
|
||||
count = count*stalker_pop_factor
|
||||
if (count == 0.5) then -- just randomly 0 or 1 instead of always rounding to 1
|
||||
count = math.random(0,1)
|
||||
else
|
||||
count = round_idp(count)
|
||||
end
|
||||
end
|
||||
else
|
||||
end
|
||||
|
||||
for i=1,count do
|
||||
-- SMR
|
||||
smr_pop.smr_handle_spawn(squad_section, smart)
|
||||
-- SMR END
|
||||
end
|
||||
else
|
||||
printf("sim_board:fill_start_position incorrect smart by name %s",section)
|
||||
end
|
||||
end
|
||||
end
|
||||
)
|
||||
end
|
||||
|
||||
-- Return smart by its name.
|
||||
function simulation_board:get_smart_by_name(name)
|
||||
return self.smarts_by_names[name]
|
||||
end
|
||||
-- Returns the number of units in smart.
|
||||
function simulation_board:get_smart_population(smart)
|
||||
return self.smarts[smart.id].population
|
||||
end
|
||||
|
||||
-- Getting the playing field.
|
||||
function get_sim_board()
|
||||
if _G.SIMBOARD == nil then
|
||||
_G.SIMBOARD = simulation_board()
|
||||
end
|
||||
return _G.SIMBOARD
|
||||
end
|
||||
|
||||
local priority_tasks = {}
|
||||
function simulation_board:get_squad_target(squad)
|
||||
local size_t = 0
|
||||
|
||||
local object_registry = simulation_objects.object_registry
|
||||
local is_available = simulation_objects.available_by_id
|
||||
for index=1,simulation_objects.object_registry_size do
|
||||
local se_target = object_registry[index]
|
||||
if (not se_target.locked and se_target.id ~= squad.id and is_available[se_target.id]) then
|
||||
local curr_prior = se_target:evaluate_prior(squad)
|
||||
if (curr_prior > 0 and se_target:target_precondition(squad)) then
|
||||
-- Prioritize 5 potential targets
|
||||
if (size_t < 5) then
|
||||
size_t = size_t + 1
|
||||
priority_tasks[size_t] = {se_target,curr_prior}
|
||||
elseif (curr_prior > priority_tasks[size_t][2]) then
|
||||
for i=1,size_t do
|
||||
if (curr_prior > priority_tasks[i][2]) then
|
||||
priority_tasks[i][2] = curr_prior
|
||||
priority_tasks[i][1] = se_target
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- Tronex, get target with highest prior
|
||||
local highest_prior = 0
|
||||
local best_target
|
||||
for i=1,size_t do
|
||||
if highest_prior < priority_tasks[i][2] then
|
||||
highest_prior = priority_tasks[i][2]
|
||||
best_target = priority_tasks[i][1]
|
||||
end
|
||||
end
|
||||
|
||||
if (size_t > 0) then
|
||||
--local target = priority_tasks[math.random(size_t)][1]
|
||||
local target = (math.random(1,100) <= 50) and priority_tasks[math.random(size_t)][1] or best_target -- Tronex
|
||||
--printf("squad=%s size=%s target=%s",squad:name(),size_t,target:name())
|
||||
iempty_table(priority_tasks) -- It is better to reuse table to avoid GC
|
||||
return target
|
||||
end
|
||||
end
|
||||
|
||||
-- Nilling the list on the creation of the game.
|
||||
function clear()
|
||||
_G.SIMBOARD = nil
|
||||
end
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,43 @@
|
||||
local defaults = {
|
||||
["smr_enabled"] = true,
|
||||
["glitched_pda"] = false,
|
||||
["respawn_idle"] = 86400,
|
||||
}
|
||||
|
||||
function get_config(key)
|
||||
if ui_mcm then return ui_mcm.get("SMR/smr_amain/"..key) else return defaults[key] end
|
||||
end
|
||||
|
||||
function level_present(r)
|
||||
return (level.present() == r)
|
||||
end
|
||||
|
||||
function on_mcm_load()
|
||||
return { id="smr_amain", sh=true, gr={
|
||||
{ id="title_header", type="slide", link="ui_options_slider_mask", text="ui_mcm_menu_smr_amain", size= {512,50}, spacing=20 },
|
||||
{ id="persist_info_mm", type="desc", clr={200, 200, 200, 255}, text="ui_mcm_SMR_smr_amain_persist_info_mm", precondition={level_present, false} },
|
||||
{ id="persist_info_level", type="desc", clr={200, 200, 255, 200}, text="ui_mcm_SMR_smr_amain_persist_info_level", precondition={level_present, true} },
|
||||
{ id="tooltip_info", type="desc", text="ui_mcm_SMR_smr_amain_tooltip_info" },
|
||||
{ id="persist_divider", type="line" },
|
||||
{ id="smr_enabled", type="check", val=1, def=true},
|
||||
{ id="smr_debug_log", type="check", val=1, def=false},
|
||||
{ id="smr_persist_override", type="check", val=1, def=false},
|
||||
{ id="smr_enabled_divider", type="line" },
|
||||
{ id="respawn_idle", type="list", val=2, def=86400, content={
|
||||
{10800,"smr_amain_respawn_idle_10800"},
|
||||
{21600,"smr_amain_respawn_idle_21600"},
|
||||
{43200,"smr_amain_respawn_idle_43200"},
|
||||
{86400,"smr_amain_respawn_idle_86400"},
|
||||
{172800,"smr_amain_respawn_idle_172800"},
|
||||
{345600,"smr_amain_respawn_idle_345600"},
|
||||
{604800,"smr_amain_respawn_idle_604800"},
|
||||
{1209600, "smr_amain_respawn_idle_1209600"},
|
||||
{-1, "smr_amain_respawn_idle_1"},
|
||||
}},
|
||||
{ id="pop_factor_info", type="desc", clr={200, 125, 125, 125}, text="ui_mcm_SMR_smr_amain_pop_factor_info" },
|
||||
{ id="monster_pop_factor", type="track", val=2, min=0, max=3, step=0.05, def=0.5 },
|
||||
{ id="stalker_pop_factor", type="track", val=2, min=0, max=3, step=0.05, def=0.5 },
|
||||
{ id="pop_factor_divider", type="line" },
|
||||
{ id="glitched_pda", type="check", val=1, def=false},
|
||||
}}, "SMR"
|
||||
end
|
||||
@@ -0,0 +1,26 @@
|
||||
local defaults = {
|
||||
}
|
||||
|
||||
function get_config(key)
|
||||
if ui_mcm then return ui_mcm.get("SMR/smr_anomalies/"..key) else return defaults[key] end
|
||||
end
|
||||
|
||||
function level_present(r)
|
||||
return (level.present() == r)
|
||||
end
|
||||
|
||||
function on_mcm_load()
|
||||
return { id="smr_anomalies", sh=true, gr={
|
||||
{ id="title_header", type="slide", link="ui_options_slider_psi_storm", text="ui_mcm_menu_smr_anomalies", size= {512,50}, spacing=20 },
|
||||
{ id="dyn_ano_chance", type="track", val=2, min=1, max=100, step=1, def=35 },
|
||||
{ id="pulse", type="check", val=1, def=true},
|
||||
{ id="anomalies_types_divider", type="line" },
|
||||
{ id="anomalies_types_header", type="title", text="ui_mcm_smr_anomalies_anomalies_types_title", align="c" },
|
||||
{ id="anomalies_types_info", type="desc", clr={200, 125, 125, 125}, text="ui_mcm_SMR_smr_anomalies_anomalies_types_info", },
|
||||
{ id="electric", type="check", val=1, def=true},
|
||||
{ id="chemical", type="check", val=1, def=true},
|
||||
{ id="thermal", type="check", val=1, def=true},
|
||||
{ id="gravitational", type="check", val=1, def=true},
|
||||
{ id="radioactive", type="check", val=1, def=true},
|
||||
}}, "SMR"
|
||||
end
|
||||
@@ -0,0 +1,231 @@
|
||||
--[[
|
||||
------------------------------------------------------------
|
||||
-- Survival Mode Remade - Civil War
|
||||
------------------------------------------------------------
|
||||
-- Sets up relations if Civil War is enabled.
|
||||
-- by dph-hcl
|
||||
------------------------------------------------------------
|
||||
]]--
|
||||
|
||||
-- TODO: factor these out into ltx files
|
||||
local smart_bases = {
|
||||
["sim_smr_default"] = {
|
||||
"pri_a18_smart_terrain",
|
||||
"agr_smart_terrain_1_6",
|
||||
"agr_smart_terrain_1_6_near_1",
|
||||
"agr_smart_terrain_1_6_near_2",
|
||||
"bar_dolg_bunker",
|
||||
"bar_dolg_general",
|
||||
"bar_visitors",
|
||||
"bar_zastava",
|
||||
"bar_zastava_2",
|
||||
"cit_killers",
|
||||
"cit_killers_2",
|
||||
"mlr_terrain",
|
||||
"ds2_domik_st",
|
||||
"esc_smart_terrain_2_12",
|
||||
"esc_smart_terrain_3_16",
|
||||
"esc_smart_terrain_5_7",
|
||||
"gar_smart_terrain_3_5",
|
||||
"gar_smart_terrain_6_3",
|
||||
"jup_a12",
|
||||
"jup_a6",
|
||||
"jup_b41",
|
||||
"mar_smart_terrain_base",
|
||||
"mar_smart_terrain_doc",
|
||||
"mil_smart_terrain_7_10",
|
||||
"mil_smart_terrain_7_8",
|
||||
"mil_smart_terrain_7_7",
|
||||
"mil_smart_terrain_7_12",
|
||||
"pri_a15",
|
||||
"pri_a16_mlr_copy",
|
||||
"pri_a16",
|
||||
"pri_a18_smart_terrain",
|
||||
"pri_monolith",
|
||||
"red_smart_terrain_4_2",
|
||||
"red_smart_terrain_3_2",
|
||||
"ros_smart_stalker_killers1",
|
||||
"ros_smart_stalker1",
|
||||
"trc_sim_20",
|
||||
"val_smart_terrain_7_3",
|
||||
"val_smart_terrain_7_4",
|
||||
"val_smart_terrain_7_5",
|
||||
"yan_smart_terrain_6_4",
|
||||
"zat_b40_smart_terrain",
|
||||
"zat_stalker_base_smart"
|
||||
},
|
||||
["sim_smr_survival"] = {
|
||||
"pri_a18_smart_terrain",
|
||||
"agr_smart_terrain_1_6",
|
||||
"agr_smart_terrain_1_6_near_1",
|
||||
"agr_smart_terrain_1_6_near_2",
|
||||
"bar_dolg_bunker",
|
||||
"bar_dolg_general",
|
||||
"bar_visitors",
|
||||
"bar_zastava",
|
||||
"bar_zastava_2",
|
||||
"cit_killers",
|
||||
"ds2_domik_st",
|
||||
"esc_smart_terrain_2_12",
|
||||
"esc_smart_terrain_3_16",
|
||||
"gar_smart_terrain_3_5",
|
||||
"jup_a12",
|
||||
"jup_a6",
|
||||
"jup_b41",
|
||||
"mar_smart_terrain_base",
|
||||
"mar_smart_terrain_doc",
|
||||
"mil_smart_terrain_7_10",
|
||||
"mil_smart_terrain_7_7",
|
||||
"pri_monolith",
|
||||
"trc_sim_20",
|
||||
"val_smart_terrain_7_3",
|
||||
"val_smart_terrain_7_4",
|
||||
"val_smart_terrain_7_5",
|
||||
"yan_smart_terrain_6_4",
|
||||
"zat_b40_smart_terrain",
|
||||
"zat_stalker_base_smart"
|
||||
},
|
||||
["sim_smr_minimal"] = {
|
||||
"bar_dolg_bunker",
|
||||
"bar_dolg_general",
|
||||
"bar_visitors",
|
||||
"bar_zastava",
|
||||
"bar_zastava_2",
|
||||
"yan_smart_terrain_6_4",
|
||||
"zat_stalker_base_smart"
|
||||
},
|
||||
["sim_smr_none"] = {}
|
||||
}
|
||||
|
||||
local civil_war_stalkers = {}
|
||||
|
||||
function smart_is_base(smart)
|
||||
local l = smart_bases[smr_stalkers_mcm.get_config("base_population")]
|
||||
for i,n in ipairs(l) do
|
||||
if smart == n then return true end
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
local function setup_squad_relation(squad, member)
|
||||
local sim = alife()
|
||||
for k in squad:squad_members() do
|
||||
if (member.id ~= k.id) then
|
||||
local se_obj = sim:object(member.id)
|
||||
local se_obj2 = sim:object(k.id)
|
||||
smr_debug.get_log().info("civilwar/relations", "setting up squad relations between %s and %s in squad %s", se_obj:section_name(), se_obj2:section_name(), squad:section_name())
|
||||
-- these are cse_alife_human_abstract objs, their implementation of force_set_goodwill takes an ID as parameter.
|
||||
se_obj:force_set_goodwill(5000, se_obj2.id)
|
||||
se_obj2:force_set_goodwill(5000, se_obj.id)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function setup_stalker_relation(squad)
|
||||
local sim = alife()
|
||||
for k in squad:squad_members() do
|
||||
local se_obj = sim:object(k.id)
|
||||
if (not IsStalker(nil, se_obj:clsid())) then
|
||||
smr_debug.get_log().info("civilwar/relations", "not a stalker: %s in squad %s", se_obj:section_name(), squad:section_name())
|
||||
goto continue
|
||||
end
|
||||
smr_debug.get_log().info("civilwar/relations", "setting up relations for %s in squad %s", se_obj:section_name(), squad:section_name())
|
||||
se_obj:force_set_goodwill(-5000, sim:object(0))
|
||||
for i, n in ipairs(game_relations.factions_table) do
|
||||
relation_registry.set_community_goodwill(n, k.id, -2000)
|
||||
game_relations.change_factions_community_num(n, k.id, -2000)
|
||||
end
|
||||
if smr_stalkers_mcm.get_config("civil_war") == "civilwar_squads" then
|
||||
setup_squad_relation(squad, k)
|
||||
end
|
||||
::continue::
|
||||
end
|
||||
civil_war_stalkers[squad.id] = true
|
||||
end
|
||||
|
||||
-- ---
|
||||
-- ENTRY POINTS
|
||||
-- ---
|
||||
|
||||
-- simulation_board:fill_start_position()
|
||||
function setup_factions_relation()
|
||||
if smr_stalkers_mcm.get_config("civil_war_monolith_allied") then
|
||||
smr_debug.get_log().info("civilwar/relations", "monolith are allied")
|
||||
relation_registry.set_community_relation("monolith", "monolith", 2000)
|
||||
else
|
||||
smr_debug.get_log().info("civilwar/relations", "monolith are enemies")
|
||||
relation_registry.set_community_relation("monolith", "monolith", -5000)
|
||||
end
|
||||
if smr_stalkers_mcm.get_config("civil_war") == "civilwar_factions" then
|
||||
apply_faction_civil_war()
|
||||
end
|
||||
end
|
||||
|
||||
-- smart_terrain.se_smart_terrain:try_respawn()
|
||||
function setup_civil_war_squad(squad, smart)
|
||||
if (not smr_amain_mcm.get_config("smr_enabled")) or smr_stalkers_mcm.get_config("civil_war") == "civilwar_disabled" then
|
||||
-- smr_debug.get_log().info("civilwar", "ZCP or civil war disabled, skipping setup")
|
||||
return
|
||||
end
|
||||
if (not smr_stalkers_mcm.get_config("civil_war_base_population")) and smart_is_base(smart) then
|
||||
smr_debug.get_log().info("civilwar/relations", "smart %s is base, skipping squad %s", smart, squad:section_name())
|
||||
return
|
||||
end
|
||||
local faction = ini_sys:r_string_ex(squad:section_name(), "faction")
|
||||
if is_squad_monster[faction] then
|
||||
smr_debug.get_log().info("civilwar/relations", "skipping monster squad %s", squad:section_name())
|
||||
return
|
||||
end
|
||||
setup_stalker_relation(squad)
|
||||
end
|
||||
|
||||
function squad_on_npc_death(squad, npc, killer)
|
||||
if not smr_amain_mcm.get_config("smr_enabled") then
|
||||
return
|
||||
end
|
||||
if (not (killer.id == AC_ID) and civil_war_stalkers[squad.id]) then
|
||||
return
|
||||
end
|
||||
local pf = db.actor:character_community()
|
||||
local nf = squad:get_squad_community()
|
||||
if game_relations.is_factions_enemies(pf, nf) then
|
||||
smr_debug.get_log().info("civilwar/relations", "actor killed enemy stalker %s", squad:section_name())
|
||||
return
|
||||
elseif game_relations.is_factions_friends(pf, nf) then
|
||||
smr_debug.get_log().info("civilwar/relations", "actor killed friendly stalker %s", squad:section_name())
|
||||
db.actor:change_character_reputation(100)
|
||||
else
|
||||
smr_debug.get_log().info("civilwar/relations", "actor killed neutral stalker %s", squad:section_name())
|
||||
db.actor:change_character_reputation(75)
|
||||
end
|
||||
if (squad:npc_count() == 0) then
|
||||
smr_debug.get_log().info("civilwar/relations", "actor killed last member of squad %s", squad:section_name())
|
||||
civil_war_stalkers[squad.id] = nil
|
||||
end
|
||||
end
|
||||
|
||||
local function save_state(data)
|
||||
if not (data.smr_civil_war) then
|
||||
data.smr_civil_war = {}
|
||||
end
|
||||
data.smr_civil_war.civil_war_stalkers = civil_war_stalkers
|
||||
end
|
||||
|
||||
local function load_state(data)
|
||||
if not (data.smr_civil_war) then
|
||||
return
|
||||
end
|
||||
civil_war_stalkers = data.smr_civil_war.civil_war_stalkers or {}
|
||||
data.smr_civil_war.civil_war_stalkers = {}
|
||||
end
|
||||
|
||||
function on_game_start()
|
||||
if (not smr_amain_mcm.get_config("smr_enabled")) or smr_stalkers_mcm.get_config("civil_war") == "civilwar_disabled" then
|
||||
smr_debug.get_log().info("civilwar", "Civil War disabled")
|
||||
return
|
||||
end
|
||||
setup_factions_relation()
|
||||
RegisterScriptCallback("save_state", save_state)
|
||||
RegisterScriptCallback("load_state", load_state)
|
||||
RegisterScriptCallback("squad_on_npc_death", squad_on_npc_death)
|
||||
end
|
||||
@@ -0,0 +1,62 @@
|
||||
--[[
|
||||
------------------------------------------------------------
|
||||
-- Survival Mode Remade - Persistent configuration per savefile
|
||||
------------------------------------------------------------
|
||||
-- Saves/Load configuration state to/from savefile.
|
||||
-- by dph-hcl
|
||||
------------------------------------------------------------
|
||||
]]--
|
||||
|
||||
local collection = "SMR"
|
||||
local modules = {
|
||||
"smr_amain",
|
||||
"smr_loot",
|
||||
"smr_zzintegration",
|
||||
"smr_zombies",
|
||||
"smr_stalkers",
|
||||
}
|
||||
|
||||
local function load_state(data)
|
||||
if smr_amain_mcm.get_config("smr_persist_override") then
|
||||
return
|
||||
end
|
||||
local t = axr_main.config:collect_section("mcm")
|
||||
for p, v in pairs(t) do
|
||||
for i, m in ipairs(modules) do
|
||||
if not data[m] then
|
||||
goto continue
|
||||
end
|
||||
local pp = str_explode(p, "/")
|
||||
if (pp[1] and pp[1] == collection)
|
||||
and (pp[2] and pp[2] == m)
|
||||
and (pp[3])
|
||||
then
|
||||
ui_mcm.set(p, (data[m][p] or false))
|
||||
end
|
||||
::continue::
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function save_state(data)
|
||||
local t = axr_main.config:collect_section("mcm")
|
||||
for p, v in pairs(t) do
|
||||
for i, m in ipairs(modules) do
|
||||
if not data[m] then
|
||||
data[m] = {}
|
||||
end
|
||||
local pp = str_explode(p, "/")
|
||||
if (pp[1] and pp[1] == collection)
|
||||
and (pp[2] and pp[2] == m)
|
||||
and (pp[3])
|
||||
then
|
||||
data[m][p] = ui_mcm.get(p)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function on_game_start()
|
||||
RegisterScriptCallback("save_state", save_state)
|
||||
RegisterScriptCallback("load_state", load_state)
|
||||
end
|
||||
@@ -0,0 +1,37 @@
|
||||
local log = false
|
||||
|
||||
function get_log()
|
||||
if (log == false) and (dph_debug_log) then
|
||||
local log_config = {
|
||||
["file"] = "dph_zcp.log",
|
||||
["targets"] = {
|
||||
-- ["log"] = 1,
|
||||
["gamelog"] = 1,
|
||||
}
|
||||
}
|
||||
local modules = {
|
||||
"loot",
|
||||
"integration",
|
||||
"population",
|
||||
"civilwar",
|
||||
"smart",
|
||||
"simboard",
|
||||
"anomalies"
|
||||
}
|
||||
log = dph_debug_log.new(log_config, modules)
|
||||
if (smr_amain_mcm.get_config("smr_debug_log")) then
|
||||
log.enable()
|
||||
end
|
||||
end
|
||||
return log
|
||||
end
|
||||
|
||||
function on_option_change()
|
||||
if smr_amain_mcm.get_config("smr_debug_log") then
|
||||
log.enable()
|
||||
else
|
||||
log.disable()
|
||||
end
|
||||
end
|
||||
|
||||
RegisterScriptCallback("on_option_change", on_option_change)
|
||||
@@ -0,0 +1,461 @@
|
||||
--[[
|
||||
------------------------------------------------------------
|
||||
-- Survival Mode Remade - Extra items from stash boxes
|
||||
------------------------------------------------------------
|
||||
-- MCM-configurable script to give the player a chance to get some extra items whenever they open a stash box.
|
||||
-- by dph-hcl
|
||||
------------------------------------------------------------
|
||||
]]--
|
||||
|
||||
-- REPAIR KITS
|
||||
local repair_tier1 = {
|
||||
"glue_a",
|
||||
"glue_b",
|
||||
"glue_e",
|
||||
"gun_oil",
|
||||
"gun_oil_ru",
|
||||
"gun_oil_ru_d",
|
||||
"armor_repair_fa",
|
||||
"sharpening_stones",
|
||||
}
|
||||
|
||||
local repair_tier2 = {
|
||||
"sharpening_stones",
|
||||
"cleaning_kit_p",
|
||||
"cleaning_kit_s",
|
||||
"cleaning_kit_r5",
|
||||
"cleaning_kit_r7",
|
||||
"sewing_kit_b",
|
||||
"sewing_kit_a",
|
||||
}
|
||||
|
||||
local repair_tier3 = {
|
||||
"cleaning_kit_u",
|
||||
"toolkit_p",
|
||||
"toolkit_s",
|
||||
"sewing_kit_h",
|
||||
"medium_repair_kit",
|
||||
"helmet_repair_kit",
|
||||
"light_repair_kit",
|
||||
}
|
||||
|
||||
local repair_tier4 = {
|
||||
"toolkit_r5",
|
||||
"toolkit_r7",
|
||||
"heavy_repair_kit",
|
||||
"exo_repair_kit",
|
||||
}
|
||||
|
||||
-- BASIC AMMO
|
||||
local basic_ammo = {
|
||||
"ammo_11.43x23_fmj",
|
||||
"ammo_12x70_buck",
|
||||
"ammo_7.62x25_p",
|
||||
"ammo_12x76_zhekan",
|
||||
"ammo_5.45x39_fmj",
|
||||
"ammo_5.45x39_ep",
|
||||
"ammo_5.56x45_fmj",
|
||||
"ammo_5.56x45_ss190",
|
||||
"ammo_9x18_fmj",
|
||||
"ammo_9x19_fmj",
|
||||
"ammo_11.43x23_hydro",
|
||||
"ammo_12x76_dart",
|
||||
"ammo_7.62x25_ps",
|
||||
"ammo_5.45x39_ap",
|
||||
"ammo_5.56x45_ap",
|
||||
"ammo_9x18_ap",
|
||||
"ammo_9x18_pmm",
|
||||
"ammo_9x19_ap",
|
||||
"ammo_9x19_pbp",
|
||||
}
|
||||
|
||||
-- ADVANCED AMMO
|
||||
local advanced_ammo = {
|
||||
"ammo_357_hp_mag",
|
||||
"ammo_7.62x39_fmj",
|
||||
"ammo_7.62x51_fmj",
|
||||
"ammo_7.62x54_7h1",
|
||||
"ammo_9x39_pab9",
|
||||
"ammo_7.62x39_ap",
|
||||
"ammo_7.62x51_ap",
|
||||
"ammo_7.62x54_7h14",
|
||||
"ammo_7.62x54_ap",
|
||||
"ammo_9x39_ap",
|
||||
}
|
||||
|
||||
-- EXOTIC AMMO
|
||||
local exotic_ammo = {
|
||||
"ammo_12.7x55_fmj",
|
||||
"ammo_4.6x30_fmj",
|
||||
"ammo_5.7x28_ss195",
|
||||
"ammo_7.92x33_fmj",
|
||||
"ammo_m209",
|
||||
"ammo_vog-25",
|
||||
"ammo_12.7x55_ap",
|
||||
"ammo_5.7x28_ss190",
|
||||
"ammo_50_bmg",
|
||||
"ammo_7.92x33_ap",
|
||||
"ammo_magnum_300",
|
||||
"ammo_pkm_100",
|
||||
"ammo_gauss",
|
||||
}
|
||||
|
||||
-- USEFUL ITEMS
|
||||
local useful_tier1 = {
|
||||
"device_torch_dummy",
|
||||
"batteries_dead", "batteries_dead", "batteries_dead",
|
||||
"detector_simple",
|
||||
"af_iam",
|
||||
"itm_sleepbag",
|
||||
"wpn_knife2",
|
||||
"wpn_axe",
|
||||
"kit_hunt",
|
||||
"wpn_binoc_inv",
|
||||
"itm_actor_backpack",
|
||||
"leatherman_tool",
|
||||
"itm_sleepbag",
|
||||
"equ_small_pack",
|
||||
"af_aac",
|
||||
}
|
||||
|
||||
local useful_tier2 = {
|
||||
"device_torch_nv_1",
|
||||
"detector_advanced",
|
||||
"wpn_knife3",
|
||||
"wpn_axe2",
|
||||
"equ_small_military_pack",
|
||||
"itm_tent",
|
||||
}
|
||||
|
||||
local useful_tier3 = {
|
||||
"device_torch_nv_2",
|
||||
"detector_scientific",
|
||||
"wpn_knife4",
|
||||
"wpn_knife5",
|
||||
"wpn_axe3",
|
||||
"equ_military_pack",
|
||||
}
|
||||
|
||||
local useful_tier4 = {
|
||||
"device_torch_nv_3",
|
||||
"detector_elite",
|
||||
"af_aam",
|
||||
"equ_tourist_pack",
|
||||
}
|
||||
|
||||
-- MEDICAL ITEMS
|
||||
|
||||
local meds_tier1 = {
|
||||
"bandage",
|
||||
"caffeine",
|
||||
"drug_sleepingpills",
|
||||
"drug_coagulant",
|
||||
"yadylin",
|
||||
"medkit",
|
||||
"jgut",
|
||||
"glucose_s",
|
||||
"antirad",
|
||||
"antirad_cystamine",
|
||||
}
|
||||
|
||||
local meds_tier2 = {
|
||||
"medkit_army",
|
||||
"stimpack",
|
||||
"salicidic_acid",
|
||||
"glucose",
|
||||
"drug_psy_blockade",
|
||||
"antirad_kalium",
|
||||
"medkit_ai1",
|
||||
"akvatab",
|
||||
}
|
||||
|
||||
local meds_tier3 = {
|
||||
"medkit_scientic",
|
||||
"stimpack_army",
|
||||
"morphine",
|
||||
"drug_radioprotector",
|
||||
"medkit_ai3",
|
||||
"adrenalin",
|
||||
"drug_anabiotic",
|
||||
}
|
||||
|
||||
local meds_tier4 = {
|
||||
"stimpack_scientic",
|
||||
"survival_kit",
|
||||
"medkit_ai2",
|
||||
}
|
||||
|
||||
local lootboxes_tier1 = {
|
||||
"lootbox_1",
|
||||
"lootbox_11",
|
||||
"lootbox_2",
|
||||
"lootbox_5",
|
||||
"lootbox_51",
|
||||
}
|
||||
|
||||
local lootboxes_tier2 = {
|
||||
"lootbox_7",
|
||||
"lootbox_4",
|
||||
"lootbox_41",
|
||||
"lootbox_6",
|
||||
"lootbox_61",
|
||||
"lootbox_71",
|
||||
"lootbox_3",
|
||||
}
|
||||
|
||||
local lootboxes_tier3 = {
|
||||
"lootbox_8",
|
||||
"lootbox_81",
|
||||
"lootbox_9",
|
||||
}
|
||||
|
||||
|
||||
-- table of already looted boxes
|
||||
local boxes = {}
|
||||
-- table of already looted npcs
|
||||
local npcs = {}
|
||||
|
||||
local pda_msg_status = true
|
||||
|
||||
local function pda_message(type)
|
||||
local strs = {
|
||||
["repair"] = "st_smr_loot_found_repair",
|
||||
["ammo"] = "st_smr_loot_found_ammo",
|
||||
["meds"] = "st_smr_loot_found_meds",
|
||||
["useful"] = "st_smr_loot_found_useful",
|
||||
["mags"] = "st_smr_loot_found_mags",
|
||||
["lootbox"] = "st_smr_loot_found_lootbox",
|
||||
|
||||
}
|
||||
if (not smr_loot_mcm.get_config("send_message")) or (not pda_msg_status) then
|
||||
return
|
||||
end
|
||||
db.actor:give_game_news(game.translate_string(strs[type]), "", "ui_inGame2_Polucheni_koordinaty_taynika", 0, 3000)
|
||||
smr_debug.get_log().info("loot/general", "PDA message sent: %s", strs[type])
|
||||
xr_sound.set_sound_play(AC_ID, "pda_tips")
|
||||
end
|
||||
|
||||
-- creates an item with a random amount of uses or condition
|
||||
local function create_item_random_uses(i, box)
|
||||
smr_debug.get_log().info("loot/general", "Creating item with random uses: %s", i)
|
||||
local max_uses = ini_sys:r_float_ex(i, "max_uses")
|
||||
local se_item = alife_create_item(i, box)
|
||||
if max_uses then
|
||||
alife_process_item(i, se_item.id, {uses = (math.random(1, max_uses))})
|
||||
elseif utils_item.is_degradable(nil, se_item.id) then
|
||||
alife_process_item(i, se_item.id, {cond = (math.random(50,100)/100)})
|
||||
end
|
||||
end
|
||||
|
||||
local function roll_item_tiered(t, box)
|
||||
local r = math.random(1,100)
|
||||
table.sort(t, function(a, b) return a[1] > b[1] end)
|
||||
for i, n in ipairs(t) do
|
||||
if (r >= n[1]) then
|
||||
local itm = n[2][math.random(#n[2])]
|
||||
smr_debug.get_log().info("loot/rolls", "Rolled succesfully for %s (%s >= %s)", itm, r, n[1])
|
||||
create_item_random_uses(itm, box)
|
||||
return true
|
||||
end
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
function try_spawn_lootbox(box)
|
||||
if math.random(1,100) <= smr_zzintegration_mcm.get_config("lootboxes_chance") then
|
||||
pda_message("lootbox")
|
||||
local tbl = {
|
||||
{ 90, lootboxes_tier3},
|
||||
{ 50, lootboxes_tier2},
|
||||
{ 0, lootboxes_tier1},
|
||||
}
|
||||
roll_item_tiered(tbl, box)
|
||||
end
|
||||
end
|
||||
|
||||
function try_spawn_mag(box)
|
||||
if math.random(1,100) <= smr_zzintegration_mcm.get_config("mags_redux_chance") then
|
||||
smr_debug.get_log().info("integration", "Rolling for magazine")
|
||||
local mags = {}
|
||||
for i=1,3 do
|
||||
local wpn = db.actor:item_in_slot(i)
|
||||
if wpn and magazine_binder.is_supported_weapon(wpn) then
|
||||
mags = magazine_binder.get_mags_for_basetype(magazine_binder.get_weapon_base_type(wpn))
|
||||
end
|
||||
end
|
||||
if (next(mags) == nil) then
|
||||
return
|
||||
end
|
||||
pda_message("mags")
|
||||
alife_create_item(mags[math.random(#mags)], box)
|
||||
end
|
||||
end
|
||||
|
||||
-- rolls for a repair kit, and spawns if sucessful
|
||||
function try_spawn_repair(box)
|
||||
if math.random(1,100) <= smr_loot_mcm.get_config("repair_chance") then
|
||||
pda_message("repair")
|
||||
local tbl = {
|
||||
{ 90, repair_tier4},
|
||||
{ 50, repair_tier3},
|
||||
{ 0, repair_tier2},
|
||||
}
|
||||
roll_item_tiered(tbl, box)
|
||||
end
|
||||
end
|
||||
|
||||
function try_spawn_repair_minor(box)
|
||||
if math.random(1,100) <= smr_loot_mcm.get_config("repair_minor_chance") then
|
||||
pda_message("repair")
|
||||
create_item_random_uses(repair_tier1[math.random(#repair_tier1)], box)
|
||||
end
|
||||
end
|
||||
|
||||
-- rolls for ammo, and spawns if sucessful
|
||||
function try_spawn_ammo(box)
|
||||
if math.random(1,100) <= smr_loot_mcm.get_config("ammo_chance") then
|
||||
pda_message("ammo")
|
||||
local r = math.random(1,100)
|
||||
if r > 90 then create_ammo(exotic_ammo[math.random(#exotic_ammo)], box)
|
||||
elseif r > 60 then create_ammo(advanced_ammo[math.random(#advanced_ammo)], box)
|
||||
else create_ammo(basic_ammo[math.random(#basic_ammo)], box)end
|
||||
end
|
||||
end
|
||||
|
||||
-- rolls for an medical item, and spawns if sucessful
|
||||
function try_spawn_meds(box)
|
||||
if math.random(1,100) <= smr_loot_mcm.get_config("meds_chance") then
|
||||
pda_message("meds")
|
||||
local tbl = {
|
||||
{ 90, meds_tier4},
|
||||
{ 70, meds_tier3},
|
||||
{ 40, meds_tier2},
|
||||
{ 0, meds_tier1},
|
||||
}
|
||||
roll_item_tiered(tbl, box)
|
||||
end
|
||||
end
|
||||
|
||||
-- rolls for a useful item, and spawns if sucessful
|
||||
function try_spawn_useful(box)
|
||||
local f = factor or 1
|
||||
if math.random(1,100) <= smr_loot_mcm.get_config("useful_chance") then
|
||||
pda_message("useful")
|
||||
local tbl = {
|
||||
{ 90, useful_tier4},
|
||||
{ 70, useful_tier3},
|
||||
{ 40, useful_tier2},
|
||||
{ 0, useful_tier1},
|
||||
}
|
||||
roll_item_tiered(tbl, box)
|
||||
end
|
||||
end
|
||||
|
||||
-- creates a random amount of ammo in a box
|
||||
function create_ammo(i, box)
|
||||
local se_item
|
||||
if smr_loot_mcm.get_config("ammo_bad_spawn") and (math.random(1,100) <= smr_loot_mcm.get_config("ammo_bad_chance"))
|
||||
then se_item = alife_create_item(i .. "_bad", box)
|
||||
else se_item = alife_create_item(i, box) end
|
||||
local bs = ini_sys:r_float_ex(i, "box_size") or 10
|
||||
local r = math.ceil(math.random(bs/2, bs*2) * smr_loot_mcm.get_config("ammo_amount"))
|
||||
alife_process_item(i, se_item.id, {ammo = r})
|
||||
end
|
||||
|
||||
function try_spawn(box)
|
||||
if smr_zzintegration_mcm.get_config("mags_redux") and magazines then smr_loot.try_spawn_mag(box) end
|
||||
if smr_zzintegration_mcm.get_config("lootboxes") and arti_lootboxes_mcm then smr_loot.try_spawn_lootbox(box) end
|
||||
if smr_loot_mcm.get_config("repair_spawn") then smr_loot.try_spawn_repair(box) end
|
||||
if smr_loot_mcm.get_config("repair_minor_spawn") then smr_loot.try_spawn_repair_minor(box) end
|
||||
if smr_loot_mcm.get_config("ammo_spawn") then smr_loot.try_spawn_ammo(box) end
|
||||
if smr_loot_mcm.get_config("useful_spawn") then smr_loot.try_spawn_useful(box) end
|
||||
if smr_loot_mcm.get_config("meds_spawn") then smr_loot.try_spawn_meds(box) end
|
||||
end
|
||||
-- ---
|
||||
-- ENTRY POINTS
|
||||
-- ---
|
||||
|
||||
-- callback, used to write box table to save
|
||||
local function save_state(data)
|
||||
if not (data.smr_loot) then
|
||||
data.smr_loot = {}
|
||||
end
|
||||
data.smr_loot.npcs = npcs
|
||||
data.smr_loot.boxes = boxes
|
||||
end
|
||||
|
||||
-- callback, used to load box table from save
|
||||
local function load_state(data)
|
||||
if not (data.smr_loot) then
|
||||
return
|
||||
end
|
||||
boxes = data.smr_loot.boxes or {}
|
||||
data.smr_loot.boxes = {}
|
||||
npcs = data.smr_loot.npcs or {}
|
||||
data.smr_loot.npcs = {}
|
||||
end
|
||||
-- callback, when opening boxes
|
||||
local function physic_object_on_use_callback(box)
|
||||
local id = box:id()
|
||||
local player_stashes = alife_storage_manager.get_state().player_created_stashes
|
||||
if (id and boxes and boxes[id]) or (player_stashes and player_stashes[id]) then
|
||||
return
|
||||
end
|
||||
if (IsInvbox(box)) then
|
||||
try_spawn(box)
|
||||
boxes[id] = true
|
||||
end
|
||||
end
|
||||
|
||||
local function npc_on_death_callback(obj, who)
|
||||
local id = obj:id()
|
||||
if id and npcs and npcs[id] then
|
||||
return
|
||||
end
|
||||
if math.random(1,100) <= smr_loot_mcm.get_config("npc_chance") then
|
||||
pda_msg_status = false
|
||||
try_spawn(obj)
|
||||
pda_msg_status = true
|
||||
npcs[id] = true
|
||||
end
|
||||
end
|
||||
|
||||
-- register callback for box opening
|
||||
local function actor_on_first_update()
|
||||
if smr_amain_mcm.get_config("smr_enabled") then
|
||||
RegisterScriptCallback("physic_object_on_use_callback", physic_object_on_use_callback)
|
||||
if smr_loot_mcm.get_config("npc_spawn") then
|
||||
RegisterScriptCallback("npc_on_death_callback", npc_on_death_callback)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- register callbacks for saving/loading
|
||||
function on_game_start()
|
||||
if not smr_amain_mcm.get_config("smr_enabled") then
|
||||
return
|
||||
end
|
||||
if smr_zzintegration_mcm.get_config("glowsticks") and zz_glowstick_mcm then
|
||||
table.insert(useful_tier1, "device_glowstick_orange")
|
||||
table.insert(useful_tier1, "device_glowstick_red")
|
||||
table.insert(useful_tier1, "device_glowstick_blue")
|
||||
table.insert(useful_tier1, "device_glowstick")
|
||||
end
|
||||
if smr_zzintegration_mcm.get_config("lootboxes") and arti_lootboxes_mcm then
|
||||
table.insert(useful_tier1, "lockpick")
|
||||
table.insert(useful_tier1, "bundle_lockpick")
|
||||
table.insert(useful_tier2, "lockpick_set")
|
||||
table.insert(useful_tier4, "skeleton_key")
|
||||
end
|
||||
if smr_loot_mcm.get_config("repair_parts_spawn") then
|
||||
table.insert(repair_tier1, "ramrod_tool")
|
||||
table.insert(repair_tier1, "rasp_tool")
|
||||
table.insert(repair_tier1, "sewing_thread")
|
||||
table.insert(repair_tier2, "heavy_sewing_thread")
|
||||
end
|
||||
|
||||
RegisterScriptCallback("save_state", save_state)
|
||||
RegisterScriptCallback("load_state", load_state)
|
||||
RegisterScriptCallback("npc_on_death_callback", npc_on_death_callback)
|
||||
RegisterScriptCallback("actor_on_first_update", actor_on_first_update)
|
||||
end
|
||||
@@ -0,0 +1,55 @@
|
||||
local defaults = {
|
||||
["send_message"] = true,
|
||||
["npc_spawn"] = true,
|
||||
["npc_chance"] = 10,
|
||||
["repair_spawn"] = false,
|
||||
["repair_parts_spawn"] = true,
|
||||
["repair_chance"] = 15,
|
||||
["ammo_spawn"] = false,
|
||||
["ammo_chance"] = 20,
|
||||
["ammo_bad_spawn"] = true,
|
||||
["ammo_bad_chance"] = 50,
|
||||
["ammo_amount"] = 1,
|
||||
["useful_spawn"] = false,
|
||||
["useful_chance"] = 10,
|
||||
["random_items"] = 0.5,
|
||||
}
|
||||
|
||||
function get_config(key)
|
||||
if ui_mcm then return ui_mcm.get("SMR/smr_loot/"..key) else return defaults[key] end
|
||||
end
|
||||
|
||||
function on_mcm_load()
|
||||
return { id="smr_loot", sh=true, gr={
|
||||
{ id="header", type="slide", link="ui_options_slider_economy_diff", text="ui_mcm_menu_smr_loot", size= {512,50}, spacing=20 },
|
||||
{ id="random_items", type="track", val=2, min=0, max=1, step=0.05, def=0.5},
|
||||
{ id="loot_divider", type="line" },
|
||||
{ id="general_info", type="desc", text="ui_mcm_SMR_smr_loot_general_info", },
|
||||
{ id="send_message", type="check", val=1, def=true},
|
||||
{ id="npc_spawn", type="check", val=1, def=true},
|
||||
{ id="npc_chance", type="track", val=2, min=1, max=100, step=1, def=10 },
|
||||
-- repair
|
||||
{ id="repair_divider", type="line" },
|
||||
{ id="repair_spawn", type="check", val=1, def=false},
|
||||
{ id="repair_chance", type="track", val=2, min=1, max=100, step=1, def=5 },
|
||||
{ id="repair_minor_divider", type="line" },
|
||||
{ id="repair_minor_spawn", type="check", val=1, def=true},
|
||||
{ id="repair_parts_spawn", type="check", val=1, def=true},
|
||||
{ id="repair_minor_chance", type="track", val=2, min=1, max=100, step=1, def=15 },
|
||||
-- useful items
|
||||
{ id="useful_divider", type="line" },
|
||||
{ id="useful_spawn", type="check", val=1, def=false},
|
||||
{ id="useful_chance", type="track", val=2, min=1, max=100, step=1, def=10 },
|
||||
-- meds
|
||||
{ id="meds_divider", type="line" },
|
||||
{ id="meds_spawn", type="check", val=1, def=false},
|
||||
{ id="meds_chance", type="track", val=2, min=1, max=100, step=1, def=15 },
|
||||
-- ammo
|
||||
{ id="ammo_divider", type="line" },
|
||||
{ id="ammo_spawn", type="check", val=1, def=false},
|
||||
{ id="ammo_chance", type="track", val=2, min=1, max=100, step=1, def=20 },
|
||||
{ id="ammo_amount", type="track", val=2, min=0.1, max=3, step=0.1, def=1 },
|
||||
{ id="ammo_bad_spawn", type="check", val=1, def=true},
|
||||
{ id="ammo_bad_chance", type="track", val=2, min=1, max=100, step=1, def=50 },
|
||||
}}, "SMR"
|
||||
end
|
||||
@@ -0,0 +1,9 @@
|
||||
SetActiveSubdialog = pda.set_active_subdialog
|
||||
|
||||
pda.set_active_subdialog = function(section)
|
||||
if smr_amain_mcm.get_config("smr_enabled") and smr_amain_mcm.get_config("glitched_pda") then
|
||||
return ui_pda_glitched_tab.get_ui()
|
||||
end
|
||||
|
||||
return SetActiveSubdialog(section)
|
||||
end
|
||||
@@ -0,0 +1,59 @@
|
||||
local defaults = {
|
||||
}
|
||||
|
||||
function get_config(key)
|
||||
if ui_mcm then return ui_mcm.get("SMR/smr_mutants/"..key) else return defaults[key] end
|
||||
end
|
||||
|
||||
function on_mcm_load()
|
||||
return { id="smr_mutants", sh=true, gr={
|
||||
{ id="title_header", type="slide", link="ui_options_slider_weather_foggy", text="ui_mcm_menu_smr_mutants", size= {512,50}, spacing=20 },
|
||||
{ id="squad_size", type="track", val=2, min=0.1, max=5, step=0.1, def=1 },
|
||||
{ id="squad_size_variance", type="track", val=2, min=0, max=3, step=0.1, def=0 },
|
||||
{ id="squad_size_divider", type="line" },
|
||||
{ id="random_mutants", type="check", val=1, def=false },
|
||||
{ id="random_mutants_chance", type="track", val=2, min=1, max=100, step=1, def=10 },
|
||||
{ id="types_divider", type="line" },
|
||||
{ id="types_header", type="title", text="ui_mcm_smr_mutants_types_title", align="c" },
|
||||
{ id="types_info", type="desc", clr={200, 125, 125, 125}, text="ui_mcm_SMR_smr_mutants_types_info", },
|
||||
{ id="types_replace_squads", type="check", val=1, def=false },
|
||||
{ id="types_replace_divider", type="line" },
|
||||
{ id="dogp", type="check", val=1, def=true},
|
||||
{ id="psydogp", type="check", val=1, def=true},
|
||||
{ id="ratp", type="check", val=1, def=true},
|
||||
{ id="tushkanop", type="check", val=1, def=true},
|
||||
{ id="zombiep", type="check", val=1, def=true},
|
||||
{ id="fracturep", type="check", val=1, def=true},
|
||||
{ id="catp", type="check", val=1, def=true},
|
||||
{ id="fleshp", type="check", val=1, def=true},
|
||||
{ id="boarp", type="check", val=1, def=true},
|
||||
{ id="snorkp", type="check", val=1, def=true},
|
||||
{ id="psysuckerp", type="check", val=1, def=true},
|
||||
{ id="bloodsuckerp", type="check", val=1, def=true},
|
||||
{ id="lurkerp", type="check", val=1, def=true},
|
||||
{ id="karlikp", type="check", val=1, def=true},
|
||||
{ id="burerp", type="check", val=1, def=true},
|
||||
{ id="poltergeistp", type="check", val=1, def=true},
|
||||
{ id="controllerp", type="check", val=1, def=true},
|
||||
{ id="chimerap", type="check", val=1, def=true},
|
||||
{ id="gigantp", type="check", val=1, def=true},
|
||||
{ id="unused_divider", type="line" },
|
||||
{ id="unused_header", type="title", text="ui_mcm_smr_mutants_unused_title", align="c" },
|
||||
{ id="unused_info", type="desc", clr={200, 125, 125, 125}, text="ui_mcm_smr_mutants_unused_info", },
|
||||
{ id="bibliotekarp", type="check", val=1, def=false},
|
||||
{ id="boryap", type="check", val=1, def=false},
|
||||
{ id="unused_types_info", type="desc", clr={200, 125, 125, 125}, text="ui_mcm_smr_mutants_unused_types_info", },
|
||||
{ id="unused_types_chance", type="track", val=2, min=1, max=100, step=1, def=20 },
|
||||
{ id="bloodsucker_strong_bigp", type="check", val=1, def=false},
|
||||
{ id="burer_electrap", type="check", val=1, def=false},
|
||||
{ id="burer_firerp", type="check", val=1, def=false},
|
||||
{ id="flesh_bolotp", type="check", val=1, def=false},
|
||||
{ id="gigant_jumperp", type="check", val=1, def=false},
|
||||
{ id="snork_no_maskp", type="check", val=1, def=false},
|
||||
{ id="zombie_babkap", type="check", val=1, def=false},
|
||||
{ id="zombie_gholp", type="check", val=1, def=false},
|
||||
{ id="zombie_ghostp", type="check", val=1, def=false},
|
||||
{ id="zombie_tetap", type="check", val=1, def=false},
|
||||
{ id="zombie_wichp", type="check", val=1, def=false},
|
||||
}}, "SMR"
|
||||
end
|
||||
@@ -0,0 +1,412 @@
|
||||
--[[
|
||||
------------------------------------------------------------
|
||||
-- Survival Mode Remade - Setup Zone population and manage smart terrain spawms
|
||||
------------------------------------------------------------
|
||||
-- by dph-hcl
|
||||
------------------------------------------------------------
|
||||
]]--
|
||||
|
||||
local zombie_spawn_table = {}
|
||||
local zombie_spawn_cfg = {
|
||||
["zombifiedp"] = { "zombied_sim_squad_novice", "zombied_sim_squad_advanced", "zombied_sim_squad_veteran" },
|
||||
["fracturep"] = { "simulation_fracture" },
|
||||
["snorkp"] = { "simulation_snork" },
|
||||
["bloodsuckerp"] = { "simulation_bloodsucker" },
|
||||
["psysuckerp"] = { "simulation_psysucker" },
|
||||
["blindp"] = { "simulation_zombie_blind_3zomb_civ", "simulation_zombie_blind_3zomb" },
|
||||
}
|
||||
|
||||
|
||||
local faction_spawn_table = {}
|
||||
local faction_spawn_cfg = {
|
||||
"stalker", "bandit", "csky", "duty", "freedom", "merc", "army", "ecolog", "monolith", "renegade", "greh", "isg", "zombied"
|
||||
}
|
||||
|
||||
local retarded_squad_names = {
|
||||
["duty_sim_squad_alpha"] = "dolg_sim_squad_alpha",
|
||||
["merc_sim_squad_alpha"] = "killer_sim_squad_alpha",
|
||||
["duty_sim_squad_trader"] = "dolg_sim_squad_trader",
|
||||
["duty_sim_squad_medic"] = "dolg_sim_squad_medic",
|
||||
["duty_sim_squad_barman"] = "dolg_sim_squad_barman",
|
||||
["duty_sim_squad_mechanic"] = "dolg_sim_squad_mechanic",
|
||||
}
|
||||
|
||||
local mutant_spawn_table = {}
|
||||
local mutant_spawn_cfg = {
|
||||
["psysucker_"] = "psysuckerp",
|
||||
["bloodsucker_"] = "bloodsuckerp",
|
||||
["boar_"] = "boarp",
|
||||
["snork_"] = "snorkp",
|
||||
["chimera_"] = "chimerap",
|
||||
["m_controller_"] = "controllerp",
|
||||
["dog_"] = "dogp",
|
||||
["tushkano_"] = "tushkanop",
|
||||
["pseudodog_"] = "dogp",
|
||||
["fracture_"] = "fracturep",
|
||||
["lurker_"] = "lurkerp",
|
||||
["cat_"] = "catp",
|
||||
["psy_dog_"] = "psydogp",
|
||||
["m_karlik_"] = "karlikp",
|
||||
["burer_"] = "burerp",
|
||||
["m_poltergeist_"] = "poltergeistp",
|
||||
["gigant_"] = "gigantp",
|
||||
["flesh_"] = "fleshp",
|
||||
["rat_"] = "ratp",
|
||||
["zombie_"] = "zombiep",
|
||||
["borya_"] = "boryap",
|
||||
["bibliotekar_"] = "bibliotekarp",
|
||||
}
|
||||
|
||||
local unused_mutant_spawn_table = {}
|
||||
local unused_mutant_spawn_cfg = {
|
||||
["bloodsucker_strong_bigp"] = { "bloodsucker_strong_big" },
|
||||
["burer_electrap"] = { "burer_electra" },
|
||||
["burer_firerp"] = { "burer_fire" },
|
||||
["flesh_bolotp"] = { "flesh_bolot", "flesh_bolot1" },
|
||||
["gigant_jumperp"] = { "gigant_jumper" },
|
||||
["snork_no_maskp"] = { "snork_normal_no_mask", "snork_strong_no_mask", "snork_weak_no_mask" },
|
||||
["zombie_babkap"] = { "zombi_babka_1", "zombi_babka_2", "zombi_babka_3" },
|
||||
["zombie_gholp"] = { "zombie_ghol" },
|
||||
["zombie_ghostp"] = { "zombie_ghost" },
|
||||
["zombie_tetap"] = { "zombie_teta" },
|
||||
["zombie_wichp"] = { "zombie_wich" },
|
||||
}
|
||||
|
||||
local mutant_spawn_squads = {}
|
||||
|
||||
|
||||
local function please_die_sid()
|
||||
local ids = {"red_forester_tech", "esc_m_trader"}
|
||||
for i, n in ipairs(ids) do
|
||||
smr_debug.get_log().info("population", "removing story object %s", n)
|
||||
local so = get_story_object_id(n)
|
||||
if so then alife_release_id(so) end
|
||||
end
|
||||
end
|
||||
|
||||
function get_mutant_spawn_squads()
|
||||
if next(mutant_spawn_squads) == nil then
|
||||
local ini = ini_file("plugins\\zcp\\squads_by_type.ltx")
|
||||
for m, c in pairs(mutant_spawn_cfg) do
|
||||
if (smr_mutants_mcm.get_config(c) == true) then
|
||||
local squads = smr_utils.ini_lines_to_table(ini, c)
|
||||
for i, v in ipairs(squads) do
|
||||
table.insert(mutant_spawn_squads, v)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
return mutant_spawn_squads
|
||||
end
|
||||
|
||||
function get_unused_mutant_spawn_table()
|
||||
if next(unused_mutant_spawn_table) == nil then
|
||||
for m, c in pairs(unused_mutant_spawn_cfg) do
|
||||
if (smr_mutants_mcm.get_config(m) == true) then
|
||||
local mn = str_explode(m, "_")
|
||||
if not unused_mutant_spawn_table[mn[1]] then
|
||||
unused_mutant_spawn_table[mn[1]] = {}
|
||||
end
|
||||
for i, v in ipairs(c) do
|
||||
table.insert(unused_mutant_spawn_table[mn[1]], v)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
return unused_mutant_spawn_table
|
||||
end
|
||||
|
||||
function get_zombie_spawn_table()
|
||||
if next(zombie_spawn_table) == nil then
|
||||
for k, n in pairs(zombie_spawn_cfg) do
|
||||
if smr_zombies_mcm.get_config(k) then
|
||||
for i, s in ipairs(n) do
|
||||
table.insert(zombie_spawn_table, s)
|
||||
end
|
||||
end
|
||||
end
|
||||
if next(zombie_spawn_table) == nil or smr_zombies_mcm.get_config("zombiesp") then
|
||||
for i = 1, smr_zombies_mcm.get_config("zombies_amount") do
|
||||
table.insert(zombie_spawn_table, "simulation_zombie")
|
||||
end
|
||||
end
|
||||
end
|
||||
return zombie_spawn_table
|
||||
end
|
||||
|
||||
function get_faction_spawn_table()
|
||||
if next(faction_spawn_table) == nil then
|
||||
for k, n in ipairs(faction_spawn_cfg) do
|
||||
if smr_stalkers_mcm.get_config(n) then
|
||||
table.insert(faction_spawn_table, n)
|
||||
end
|
||||
end
|
||||
end
|
||||
if next(faction_spawn_table) == nil then
|
||||
table.insert(faction_spawn_table, "stalker")
|
||||
end
|
||||
return faction_spawn_table
|
||||
end
|
||||
|
||||
function is_squad_faction_enabled(squad)
|
||||
local t = get_faction_spawn_table()
|
||||
local faction = ini_sys:r_string_ex(squad, "faction")
|
||||
if faction == "dolg" then
|
||||
faction = "duty"
|
||||
end
|
||||
if faction == "killer" then
|
||||
faction = "merc"
|
||||
end
|
||||
for i, f in ipairs(t) do
|
||||
if (faction == f) then
|
||||
return true
|
||||
end
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
function get_mutant_spawn_table()
|
||||
if next(mutant_spawn_table) == nil then
|
||||
for m, c in pairs(mutant_spawn_cfg) do
|
||||
if (smr_mutants_mcm.get_config(c) == true) then
|
||||
table.insert(mutant_spawn_table, m)
|
||||
end
|
||||
end
|
||||
if next(mutant_spawn_table) == nil then
|
||||
table.insert(mutant_spawn_table, "chimera_")
|
||||
end
|
||||
end
|
||||
return mutant_spawn_table
|
||||
end
|
||||
|
||||
function is_mutant_type_enabled(section)
|
||||
local t = get_mutant_spawn_table()
|
||||
for i, m in pairs(t) do
|
||||
if (string.sub(section, 1, string.len(m)) == m) then
|
||||
return true
|
||||
end
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
local function get_random_enabled_mutant_squad()
|
||||
local t = get_mutant_spawn_squads()
|
||||
return t[math.random(#t)]
|
||||
end
|
||||
|
||||
local function get_common_squad_type(squad_name)
|
||||
local ss = str_explode(squad_name, "_")
|
||||
if ss[4] == "novice"
|
||||
or ss[4] == "advanced"
|
||||
or ss[4] == "veteran"
|
||||
or ss[4] == "alpha"
|
||||
or ss[4] == "trader"
|
||||
or ss[4] == "medic"
|
||||
or ss[4] == "barman"
|
||||
or ss[4] == "mechanic"
|
||||
then
|
||||
return ss[4]
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
local function release_npc_or_squad(npc, squad)
|
||||
alife_release(npc)
|
||||
if (squad:npc_count() <= 1) then
|
||||
alife_release_id(squad.id)
|
||||
end
|
||||
end
|
||||
|
||||
local function try_spawn_faction(orig_spawn, smart)
|
||||
if (not orig_spawn) then
|
||||
return false
|
||||
end
|
||||
-- setup comparable squad of random enabled faction
|
||||
local t = get_faction_spawn_table()
|
||||
local st = { "novice", "veteran", "advanced" }
|
||||
local squad_type = get_common_squad_type(orig_spawn) or st[math.random(#st)]
|
||||
local tt = t[math.random(#t)] .. "_sim_squad_" .. squad_type
|
||||
for n, r in pairs(retarded_squad_names) do
|
||||
if tt == n then
|
||||
tt = r
|
||||
end
|
||||
end
|
||||
-- random stalkers
|
||||
if smr_stalkers_mcm.get_config("random_stalkers")
|
||||
and (math.random(1,100) <= smr_stalkers_mcm.get_config("random_stalkers_chance"))
|
||||
-- only replace common squads with random stalkers
|
||||
and (ini_sys:r_bool_ex(orig_spawn, "common"))
|
||||
-- check if smart is base
|
||||
and (not smr_civil_war.smart_is_base(smart:name()))
|
||||
then
|
||||
smr_debug.get_log().info("population/stalkers", "replaced squad %s with random stalkers %s (smart: %s)", orig_spawn, tt, smart:name())
|
||||
return tt
|
||||
end
|
||||
-- check if faction is enabled
|
||||
if is_squad_faction_enabled(orig_spawn) then
|
||||
smr_debug.get_log().info("population/stalkers", "faction enabled - returning %s", orig_spawn)
|
||||
return orig_spawn
|
||||
end
|
||||
-- replace if option enabled
|
||||
if not smr_stalkers_mcm.get_config("factions_replace_squads") then
|
||||
smr_debug.get_log().info("population/stalkers", "faction %s not enabled - not spawning squad %s", ini_sys:r_string_ex(orig_spawn,"faction"), orig_spawn)
|
||||
return false
|
||||
end
|
||||
smr_debug.get_log().info("population/stalkers", "faction %s not enabled: replaced squad %s with random stalkers %s", ini_sys:r_string_ex(orig_spawn,"faction"), orig_spawn, tt)
|
||||
return tt
|
||||
end
|
||||
|
||||
local function add_random_npc_to_squad(squad, smart)
|
||||
local npcs = ini_sys:r_string_ex(squad:section_name(),"npc_random")
|
||||
if (not npcs) then
|
||||
-- npcs = ini_sys:r_string_ex(squad:section_name(),"npc")
|
||||
return
|
||||
end
|
||||
local t = parse_names(npcs)
|
||||
local section = t[math.random(#t)]
|
||||
local faction = ini_sys:r_string_ex(squad:section_name(), "faction")
|
||||
if is_squad_monster[faction] and (not is_mutant_type_enabled(section)) then
|
||||
smr_debug.get_log().warn("population/monsters", "could not add %s to squad %s (type disabled)", section, squad:section_name(), faction)
|
||||
return nil
|
||||
end
|
||||
local npc = alife_create(section, smart)
|
||||
if not npc then
|
||||
smr_debug.get_log().error("population/monsters", "error while adding %s to squad %s", section, squad:section_name())
|
||||
return nil
|
||||
end
|
||||
squad:register_member(npc.id)
|
||||
smr_debug.get_log().info("population/monsters", "added %s to squad %s", section, squad:section_name())
|
||||
return npc
|
||||
end
|
||||
|
||||
-- ---
|
||||
-- ENTRY POINTS
|
||||
-- ---
|
||||
|
||||
-- smart_terrain.se_smart_terrain:try_respawn()
|
||||
-- simulation_board:fill_start_position()
|
||||
function smr_handle_spawn(orig_spawn, smart)
|
||||
-- player wished for control
|
||||
if has_alife_info("actor_made_wish_for_control") then
|
||||
return SIMBOARD:create_squad(smart, "simulation_controller_psy")
|
||||
end
|
||||
-- ZCP not enabled
|
||||
if not smr_amain_mcm.get_config("smr_enabled") then
|
||||
smr_debug.get_log().info("population", "not replacing spawn -- ZCP disabled")
|
||||
return SIMBOARD:create_squad(smart, orig_spawn)
|
||||
end
|
||||
-- zombies
|
||||
local rnd = math.random(1,100)
|
||||
if smr_zombies_mcm.get_config("zombie_spawn")
|
||||
and rnd <= smr_zombies_mcm.get_config("zombie_chance")
|
||||
-- only replace common squads
|
||||
and ini_sys:r_bool_ex(orig_spawn,"common")
|
||||
-- skip bases
|
||||
and (not smr_civil_war.smart_is_base(smart))
|
||||
then
|
||||
local t = get_zombie_spawn_table()
|
||||
local tt = t[math.random(#t)]
|
||||
smr_debug.get_log().info("population/zombies", "replaced squad %s with zombie variant %s (%s <= %s)", orig_spawn, tt, rnd, smr_zombies_mcm.get_config("zombie_chance"))
|
||||
return SIMBOARD:create_squad(smart, tt)
|
||||
end
|
||||
local faction = ini_sys:r_string_ex(orig_spawn, "faction")
|
||||
-- mutant squads
|
||||
if is_squad_monster[faction] then
|
||||
if (string.sub(orig_spawn, 1, string.len("simulation_")) == "simulation_")
|
||||
and smr_mutants_mcm.get_config("random_mutants")
|
||||
and (math.random(1,100) <= smr_mutants_mcm.get_config("random_mutants_chance"))
|
||||
then
|
||||
local m
|
||||
if smr_spawns_mcm.get_config("preset_apply_random") then
|
||||
m = smr_spawn_template.get_random_squad_for_smart(smart) or get_random_enabled_mutant_squad()
|
||||
smr_debug.get_log().info("population/monsters", "replaced squad %s with random mutant %s (template)", orig_spawn, m)
|
||||
else
|
||||
m = get_random_enabled_mutant_squad()
|
||||
smr_debug.get_log().info("population/monsters", "replaced squad %s with random mutant %s", orig_spawn, m)
|
||||
end
|
||||
return SIMBOARD:create_squad(smart, m)
|
||||
end
|
||||
-- stalker squads
|
||||
else
|
||||
local maybe_squad_section = try_spawn_faction(orig_spawn, smart)
|
||||
if maybe_squad_section then
|
||||
return SIMBOARD:create_squad(smart, maybe_squad_section)
|
||||
end
|
||||
return nil
|
||||
end
|
||||
-- return original spawn
|
||||
return SIMBOARD:create_squad(smart, orig_spawn)
|
||||
end
|
||||
|
||||
-- smart_terrain.se_smart_terrain:try_respawn()
|
||||
function smart_can_respawn(smart)
|
||||
local name = smart:name()
|
||||
local last_respawn_update = smart.last_respawn_update
|
||||
-- default value
|
||||
if (not smr_amain_mcm.get_config("smr_enabled")) and (smr_amain_mcm.get_config("respawn_idle") ~= 86400) then
|
||||
smr_debug.get_log().info("population/smart", "default respawn check value: ZCP disabled or respawn_idle set to 86400 (testing for smart %s)", name)
|
||||
return last_respawn_update == nil or curr_time:diffSec(last_respawn_update) > smart.respawn_idle
|
||||
end
|
||||
-- last update was nil
|
||||
local cfg = smr_amain_mcm.get_config("respawn_idle")
|
||||
if last_respawn_update == nil then
|
||||
smr_debug.get_log().info("population/smart", "respawn check sucessful for smart %s (last update was nil)", name)
|
||||
return true
|
||||
end
|
||||
-- respawns disabled
|
||||
if cfg == -1 then
|
||||
smr_debug.get_log().info("population/smart", "respawn check failed: respawns disabled (testing for smart %s)", name)
|
||||
return false
|
||||
end
|
||||
-- use ZCP config value
|
||||
local diff = game.get_game_time():diffSec(last_respawn_update)
|
||||
if diff > cfg then
|
||||
return true
|
||||
else
|
||||
return false
|
||||
end
|
||||
end
|
||||
|
||||
-- smart_terrain.se_smart_terrain:try_respawn()
|
||||
-- simulation_board:fill_start_position()
|
||||
function get_stalker_pop_factor()
|
||||
if smr_amain_mcm.get_config("smr_enabled") then
|
||||
--smr_debug.get_log().info("population/stalkers", "overriding population factor")
|
||||
return smr_amain_mcm.get_config("stalker_pop_factor")
|
||||
end
|
||||
--smr_debug.get_log().info("population/stalkers", "ZCP disabled: using default population factor")
|
||||
return ui_options.get("alife/general/alife_stalker_pop")
|
||||
end
|
||||
|
||||
-- smart_terrain.se_smart_terrain:try_respawn()
|
||||
-- simulation_board:fill_start_position()
|
||||
function get_monster_pop_factor()
|
||||
if smr_amain_mcm.get_config("smr_enabled") then
|
||||
--smr_debug.get_log().info("population/monsters", "overriding population factor")
|
||||
return smr_amain_mcm.get_config("monster_pop_factor")
|
||||
end
|
||||
--smr_debug.get_log().info("population/monsters", "ZCP disabled: using default population factor")
|
||||
return ui_options.get("alife/general/alife_mutant_pop")
|
||||
end
|
||||
|
||||
-- simulation_board:fill_start_position()
|
||||
function get_population_preset()
|
||||
if smr_amain_mcm.get_config("smr_enabled") and (smr_stalkers_mcm.get_config("base_population") ~= "sim_smr_default") then
|
||||
smr_debug.get_log().info("population", "using population preset %s", "misc\\"..smr_stalkers_mcm.get_config("base_population")..".ltx")
|
||||
return ini_file("misc\\"..smr_stalkers_mcm.get_config("base_population")..".ltx")
|
||||
else
|
||||
smr_debug.get_log().info("population", "using default population preset")
|
||||
return ini_file("misc\\simulation.ltx")
|
||||
end
|
||||
end
|
||||
|
||||
local function actor_on_first_update()
|
||||
if smr_amain_mcm.get_config("smr_enabled") and (smr_stalkers_mcm.get_config("base_population") == "sim_smr_none") then
|
||||
smr_debug.get_log().info("population", "removing story objects")
|
||||
please_die_sid()
|
||||
end
|
||||
end
|
||||
|
||||
function on_game_start()
|
||||
RegisterScriptCallback("actor_on_first_update", actor_on_first_update)
|
||||
end
|
||||
@@ -0,0 +1,97 @@
|
||||
template_cfg = {}
|
||||
template_cfg_weights = {}
|
||||
|
||||
function get_template_config()
|
||||
if next(template_cfg) == nil then
|
||||
smr_debug.get_log().info("population/monsters", "Using preset %s ", smr_spawns_mcm.get_config("preset_file"))
|
||||
template_cfg = load_template_config()
|
||||
end
|
||||
return template_cfg
|
||||
end
|
||||
|
||||
function load_template_config()
|
||||
local tcfg = {}
|
||||
local msq = smr_pop.get_mutant_spawn_squads()
|
||||
local ini = ini_file(smr_spawns_mcm.get_config("preset_file"))
|
||||
|
||||
|
||||
local function itr(section)
|
||||
local tmp = {}
|
||||
template_cfg_weights[section] = 0
|
||||
lc = ini:line_count(section)
|
||||
for li=0,lc-1 do
|
||||
local sq, weight = smr_utils.read_spawn_template_ln(ini, section, li)
|
||||
local ss = str_explode(sq, "*")
|
||||
if ss[2] and ss[3] then
|
||||
local mini = ini_file("plugins\\zcp\\spawn_groups\\" .. ss[2] .. ".ltx")
|
||||
for nk, nv in pairs(smr_utils.spawn_template_lines_to_table(mini, ss[3])) do
|
||||
template_cfg_weights[section] = template_cfg_weights[section] + nv
|
||||
tmp[nk] = nv
|
||||
end
|
||||
else
|
||||
if smr_utils.table_has_value(msq, sq) then
|
||||
tmp[sq] = weight
|
||||
template_cfg_weights[section] = template_cfg_weights[section] + weight
|
||||
end
|
||||
end
|
||||
end
|
||||
if next(tmp) ~= nil then
|
||||
tcfg[section] = tmp
|
||||
end
|
||||
end
|
||||
ini:section_for_each(itr)
|
||||
return tcfg
|
||||
end
|
||||
|
||||
-- Weight code adapted from TheMrDemonized's "ZCP Kinda Balanced Spawns" (https://www.moddb.com/mods/stalker-anomaly/addons/zcp-balanced-spawns/)
|
||||
function get_random_squad_for_smart(smart)
|
||||
local tier = get_squad_tier()
|
||||
local key = alife():level_name(game_graph():vertex(smart.m_game_vertex_id):level_id()) .. "_tier" .. tier .. "_monsters"
|
||||
local mutant_table = get_template_config()[key]
|
||||
if not mutant_table or next(mutant_table) == nil then
|
||||
smr_debug.get_log().warn("population/monsters", "empty mutant table for %".. key)
|
||||
return nil
|
||||
end
|
||||
local rand = math.random() * template_cfg_weights[key]
|
||||
for mutant, weight in pairs(mutant_table) do
|
||||
if (rand < weight) then
|
||||
smr_debug.get_log().info("population/monsters", "got squad %s for section (roll: %s/%s) ".. key, mutant, rand, weight)
|
||||
return mutant
|
||||
end
|
||||
rand = rand - weight
|
||||
end
|
||||
smr_debug.get_log().warn("population/monsters", "no weighted squad for section".. key)
|
||||
return mutant_table[math.random(#mutant_table)]
|
||||
end
|
||||
|
||||
function get_squad_tier()
|
||||
local tier_1_fac = get_tier_factor(1)
|
||||
local tier_2_fac = get_tier_factor(2)
|
||||
local tier_3_fac = get_tier_factor(3)
|
||||
local range = tier_1_fac + tier_2_fac + tier_3_fac
|
||||
local rnd = math.random(0, range)
|
||||
if rnd <= tier_1_fac then
|
||||
return 1
|
||||
elseif rnd <= tier_1_fac + tier_2_fac then
|
||||
return 2
|
||||
else
|
||||
return 3
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
function get_tier_factor(tier)
|
||||
return smr_spawns_mcm.get_config("preset_week".. actor_weeks_in_zone() .."_tier" .. tier)
|
||||
end
|
||||
|
||||
function actor_weeks_in_zone()
|
||||
if not db.actor then
|
||||
return 0
|
||||
end
|
||||
local s_time = level.get_start_time()
|
||||
local seconds = tonumber(game.get_game_time():diffSec(s_time))
|
||||
local days = math.floor(((seconds/60)/60)/24)
|
||||
weeks = math.floor(days/7)
|
||||
if weeks > 3 then weeks = 3 end
|
||||
return weeks
|
||||
end
|
||||
@@ -0,0 +1,52 @@
|
||||
local defaults = {
|
||||
}
|
||||
|
||||
local flist = {}
|
||||
|
||||
function get_config(key)
|
||||
if ui_mcm then return ui_mcm.get("SMR/smr_spawns/"..key) else return defaults[key] end
|
||||
end
|
||||
|
||||
local function get_flist()
|
||||
if next(flist) == nil then
|
||||
local files = getFS():file_list_open('$game_config$', "plugins\\zcp\\spawn_templates\\", bit_or(FS.FS_ListFiles, FS.FS_RootOnly))
|
||||
for i=0,files:Size()-1 do
|
||||
local file_name = files:GetAt(i)
|
||||
table.insert(flist, {"plugins\\zcp\\spawn_templates\\" .. file_name, file_name })
|
||||
end
|
||||
end
|
||||
return flist
|
||||
end
|
||||
|
||||
function on_mcm_load()
|
||||
local templates = get_flist()
|
||||
return { id="smr_spawns", sh=true, gr={
|
||||
{ id="title_header", type="slide", link="ui_options_slider_warfare", text="ui_mcm_menu_smr_spawns", size= {512,50}, spacing=20 },
|
||||
{ id="preset_desc", type="desc", clr={200, 125, 125, 125}, text="ui_mcm_SMR_smr_spawns_preset_desc"},
|
||||
{ id="preset_file", type="list", val=0, no_str=true, content=templates},
|
||||
{ id="preset_file_desc", type="desc", clr={200, 125, 125, 125}, text="ui_mcm_SMR_smr_spawns_preset_file_desc"},
|
||||
{ id="preset_apply_random", type="check", val=1, def=false },
|
||||
{ id="preset_apply_replaced", type="check", val=1, def=false },
|
||||
-- week 1
|
||||
{ id="preset_week0_title", type="title", text="ui_mcm_smr_spawns_preset_week0_title", align="c" },
|
||||
{ id="preset_week0_tier1", type="track", val=2, min=1, max=100, step=1, def=70 },
|
||||
{ id="preset_week0_tier2", type="track", val=2, min=1, max=100, step=1, def=25 },
|
||||
{ id="preset_week0_tier3", type="track", val=2, min=1, max=100, step=1, def=5 },
|
||||
-- week 2
|
||||
{ id="preset_week1_title", type="title", text="ui_mcm_smr_spawns_preset_week1_title", align="c" },
|
||||
{ id="preset_week1_tier1", type="track", val=2, min=1, max=100, step=1, def=50 },
|
||||
{ id="preset_week1_tier2", type="track", val=2, min=1, max=100, step=1, def=40 },
|
||||
{ id="preset_week1_tier3", type="track", val=2, min=1, max=100, step=1, def=10 },
|
||||
-- week 3
|
||||
{ id="preset_week2_title", type="title", text="ui_mcm_smr_spawns_preset_week2_title", align="c" },
|
||||
{ id="preset_week2_tier1", type="track", val=2, min=1, max=100, step=1, def=35 },
|
||||
{ id="preset_week2_tier2", type="track", val=2, min=1, max=100, step=1, def=50 },
|
||||
{ id="preset_week2_tier3", type="track", val=2, min=1, max=100, step=1, def=15 },
|
||||
-- week 4
|
||||
{ id="preset_week3_title", type="title", text="ui_mcm_smr_spawns_preset_week3_title", align="c" },
|
||||
{ id="preset_week3_tier1", type="track", val=2, min=1, max=100, step=1, def=30 },
|
||||
{ id="preset_week3_tier2", type="track", val=2, min=1, max=100, step=1, def=45 },
|
||||
{ id="preset_week3_tier3", type="track", val=2, min=1, max=100, step=1, def=25 },
|
||||
|
||||
}}, "SMR"
|
||||
end
|
||||
@@ -0,0 +1,68 @@
|
||||
function adjust_random_count(squad, c)
|
||||
-- uncommon squad
|
||||
if not ini_sys:r_bool_ex(squad:section_name(),"common") then
|
||||
smr_debug.get_log().warn("population", "no adjustment to squad size for %s (uncommon squad)", squad:section_name())
|
||||
return c
|
||||
end
|
||||
-- story squad
|
||||
if get_story_squad(squad:section_name()) then
|
||||
smr_debug.get_log().warn("population", "no adjustment to squad size for %s (story squad)", squad:section_name())
|
||||
return c
|
||||
end
|
||||
-- get adjustment factor
|
||||
local variance
|
||||
local squad_size
|
||||
if is_squad_monster[ini_sys:r_string_ex(squad:section_name(), "faction")] then
|
||||
variance = smr_mutants_mcm.get_config("squad_size_variance")
|
||||
squad_size = smr_mutants_mcm.get_config("squad_size")
|
||||
else
|
||||
variance = smr_stalkers_mcm.get_config("squad_size_variance")
|
||||
squad_size = smr_stalkers_mcm.get_config("squad_size")
|
||||
end
|
||||
local varf = math.random(-variance, variance)
|
||||
local fac = varf + squad_size
|
||||
-- factor is 1 (no adjustment)
|
||||
if (fac == 1.0) then
|
||||
smr_debug.get_log().info("population", "no adjustment to squad size for %s", squad:section_name())
|
||||
return c
|
||||
end
|
||||
-- return adjusted count
|
||||
local target_count = math.floor(c * fac)
|
||||
smr_debug.get_log().info("population", "adusted squad size for %s: %s -> %s", squad:section_name(), c, target_count)
|
||||
return target_count
|
||||
end
|
||||
|
||||
function replace_mutant_variant(section)
|
||||
smr_debug.get_log().info("population/monsters", "FOO %s", section)
|
||||
local vt = smr_pop.get_unused_mutant_spawn_table()
|
||||
for m, v in pairs(vt) do
|
||||
if (str_explode(section, "_")[1] == m)
|
||||
and (math.random(1,100) <= smr_mutants_mcm.get_config("unused_types_chance"))
|
||||
then
|
||||
local mrs = v[math.random(#v)]
|
||||
smr_debug.get_log().info("population/monsters", "replaced %s with variant %s", section, mrs)
|
||||
return mrs
|
||||
end
|
||||
end
|
||||
return section
|
||||
end
|
||||
|
||||
function is_mutant_type_enabled(section)
|
||||
local t = smr_pop.get_mutant_spawn_table()
|
||||
for _, m in pairs(t) do
|
||||
if (string.sub(section, 1, string.len(m)) == m) then
|
||||
return true
|
||||
end
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
local function on_key_press(key)
|
||||
if (dik == key_bindings.kSAFEMODE) then
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
function on_game_start()
|
||||
RegisterScriptCallback("on_key_press", on_key_press)
|
||||
end
|
||||
@@ -0,0 +1,61 @@
|
||||
local defaults = {
|
||||
["base_population"] = "sim_smr_default",
|
||||
["civil_war"] = "civilwar_disabled",
|
||||
["civil_war_base_population"] = false,
|
||||
["civil_war_monolith_allied"] = false,
|
||||
["monolith_spawns"] = "disabled",
|
||||
}
|
||||
|
||||
function get_config(key)
|
||||
if ui_mcm then return ui_mcm.get("SMR/smr_stalkers/"..key) else return defaults[key] end
|
||||
end
|
||||
|
||||
local function p_base_pop(n)
|
||||
return get_config("base_population") == n
|
||||
end
|
||||
|
||||
function on_mcm_load()
|
||||
return { id="smr_stalkers", sh=true, gr={
|
||||
{ id="title_header", type="slide", link="ui_options_slider_disguise", text="ui_mcm_menu_smr_stalkers", size= {512,50}, spacing=20 },
|
||||
{ id="squad_size", type="track", val=2, min=0.1, max=5, step=0.1, def=1 },
|
||||
{ id="squad_size_variance", type="track", val=2, min=0, max=3, step=0.1, def=0 },
|
||||
{ id="squad_size_divider", type="line" },
|
||||
{ id="base_population", type="list", val=0, def="sim_smr_default", content={
|
||||
{"sim_smr_default", "smr_stalkers_base_population_default"},
|
||||
{"sim_smr_survival","smr_stalkers_base_population_survival"},
|
||||
{"sim_smr_minimal","smr_stalkers_base_population_minimal"},
|
||||
{"sim_smr_none","smr_stalkers_base_population_none"}} },
|
||||
{ id="base_population_default", type="desc", clr={200, 125, 125, 125}, text="ui_mcm_SMR_smr_stalkers_base_population_default", precondition={p_base_pop, "sim_smr_default"}},
|
||||
{ id="base_population_survival", type="desc", clr={200, 125, 125, 125}, text="ui_mcm_SMR_smr_stalkers_base_population_survival", precondition={p_base_pop, "sim_smr_survival"}},
|
||||
{ id="base_population_minimal", type="desc", clr={200, 125, 125, 125}, text="ui_mcm_SMR_smr_stalkers_base_population_minimal", precondition={p_base_pop, "sim_smr_minimal"}},
|
||||
{ id="base_population_none", type="desc", clr={200, 125, 125, 125}, text="ui_mcm_SMR_smr_stalkers_base_population_none", precondition={p_base_pop, "sim_smr_none"}},
|
||||
{ id="civil_war", type="list", val=0, def="civilwar_disabled", content={
|
||||
{"civilwar_disabled","smr_stalkers_civilwar_disabled"},
|
||||
{"civilwar_stalkers","smr_stalkers_civilwar_stalkers"},
|
||||
{"civilwar_squads","smr_stalkers_civilwar_squads"},
|
||||
}},
|
||||
{ id="civil_war_base_population", type="check", val=1, def=false },
|
||||
{ id="civil_war_monolith_allied", type="check", val=1, def=false },
|
||||
{ id="random_stalkers_divider", type="line" },
|
||||
{ id="random_stalkers", type="check", val=1, def=false },
|
||||
{ id="random_stalkers_chance", type="track", val=2, min=1, max=100, step=1, def=10 },
|
||||
{ id="factions_divider", type="line" },
|
||||
{ id="factions_header", type="title", text="ui_mcm_smr_stalkers_factions_title", align="c" },
|
||||
{ id="factions_info", type="desc", clr={200, 125, 125, 125}, text="ui_mcm_SMR_smr_stalkers_factions_info", },
|
||||
{ id="factions_replace_squads", type="check", val=1, def=false },
|
||||
{ id="factions_replace_divider", type="line" },
|
||||
{ id="stalker", type="check", val=1, def=true},
|
||||
{ id="bandit", type="check", val=1, def=true},
|
||||
{ id="csky", type="check", val=1, def=true},
|
||||
{ id="duty", type="check", val=1, def=true},
|
||||
{ id="freedom", type="check", val=1, def=true},
|
||||
{ id="merc", type="check", val=1, def=true},
|
||||
{ id="army", type="check", val=1, def=true},
|
||||
{ id="ecolog", type="check", val=1, def=true},
|
||||
{ id="monolith", type="check", val=1, def=true},
|
||||
{ id="renegade", type="check", val=1, def=true},
|
||||
{ id="greh", type="check", val=1, def=true},
|
||||
{ id="isg", type="check", val=1, def=true},
|
||||
{ id="zombied", type="check", val=1, def=true},
|
||||
}}, "SMR"
|
||||
end
|
||||
@@ -0,0 +1,64 @@
|
||||
function intersect(t1,t2)
|
||||
|
||||
local function make_lookup(t)
|
||||
local res={}
|
||||
for _,v in ipairs(t) do
|
||||
res[v]=true
|
||||
end
|
||||
return res
|
||||
end
|
||||
|
||||
local smaller,larger
|
||||
if (#t1>#t2) then
|
||||
larger=t1
|
||||
smaller=t2
|
||||
else
|
||||
larger=t2
|
||||
smaller=t1
|
||||
end
|
||||
|
||||
local lookup=make_lookup(smaller)
|
||||
|
||||
local res={}
|
||||
for _,v in ipairs(larger) do
|
||||
if lookup[v] then
|
||||
res[#res+1]=v
|
||||
end
|
||||
end
|
||||
return res
|
||||
end
|
||||
|
||||
function table_has_value(t, n)
|
||||
for _,v in ipairs(t) do
|
||||
if v == n then
|
||||
return true
|
||||
end
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
function ini_lines_to_table(ini, section)
|
||||
local tmp = {}
|
||||
lc = ini:line_count(section)
|
||||
for li=0,lc-1 do
|
||||
local result, sq, count = ini:r_line(section,li,"","")
|
||||
table.insert(tmp, sq)
|
||||
end
|
||||
return tmp
|
||||
end
|
||||
|
||||
function spawn_template_lines_to_table(ini, section)
|
||||
local tmp = {}
|
||||
lc = ini:line_count(section)
|
||||
for li=0,lc-1 do
|
||||
local result, sq, count = ini:r_line(section,li,"","")
|
||||
tmp[sq] = tonumber(count) or 1.0
|
||||
end
|
||||
return tmp
|
||||
end
|
||||
|
||||
function read_spawn_template_ln(ini, section, line)
|
||||
local result, sq, count = ini:r_line(section,line,"","")
|
||||
local weight = tonumber(count) or 1.0
|
||||
return sq, weight
|
||||
end
|
||||
@@ -0,0 +1,42 @@
|
||||
local defaults = {
|
||||
["zombie_spawn"] = false,
|
||||
["zombie_chance"] = 90,
|
||||
["seek_enabled"] = false,
|
||||
["seek_distance"] = 250,
|
||||
["zombiesp"] = true,
|
||||
["zombies_amount"] = 5,
|
||||
["blindp"] = true,
|
||||
["zombifiedp"] = true,
|
||||
["fracturep"] = true,
|
||||
["snorkp"] = true,
|
||||
["bloodsuckerp"] = false,
|
||||
["psysuckerp"] = false
|
||||
}
|
||||
|
||||
function get_config(key)
|
||||
if ui_mcm then return ui_mcm.get("SMR/smr_zombies/"..key) else return defaults[key] end
|
||||
end
|
||||
|
||||
function on_mcm_load()
|
||||
return { id="smr_zombies", sh=true, gr={
|
||||
{ id="title_header", type="slide", link="ui_options_slider_night", text="ui_mcm_menu_smr_zombies", size= {512,50}, spacing=20 },
|
||||
-- zombies
|
||||
{ id="zombie_spawn", type="check", val=1, def=false},
|
||||
{ id="zombie_spawn_divider", type="line" },
|
||||
{ id="zombie_chance", type="track", val=2, min=0, max=100, step=1, def=90 },
|
||||
{ id="zombies_amount", type="track", val=2, min=1, max=10, step=1, def=5 },
|
||||
{ id="seek_enabled", type="check", val=1, def=false},
|
||||
{ id="seek_distance", type="track", val=2, min=1, max=250, step=10, def=250 },
|
||||
-- zombie types
|
||||
{ id="zombie_types_divider", type="line" },
|
||||
{ id="zombie_types_header", type="title", text="ui_mcm_smr_zombies_zombie_types_title", align="c" },
|
||||
{ id="zombie_types_info", type="desc", clr={200, 125, 125, 125}, text="ui_mcm_SMR_smr_zombies_zombie_types_info", },
|
||||
{ id="zombiesp", type="check", val=1, def=true},
|
||||
{ id="blindp", type="check", val=1, def=true},
|
||||
{ id="zombifiedp", type="check", val=1, def=true},
|
||||
{ id="fracturep", type="check", val=1, def=true},
|
||||
{ id="snorkp", type="check", val=1, def=true},
|
||||
{ id="bloodsuckerp", type="check", val=1, def=false},
|
||||
{ id="psysuckerp", type="check", val=1, def=false}
|
||||
}}, "SMR"
|
||||
end
|
||||
@@ -0,0 +1,25 @@
|
||||
local defaults = {
|
||||
["glowsticks"] = false,
|
||||
["mad_mags"] = false,
|
||||
["mad_mags_chance"] = false,
|
||||
}
|
||||
|
||||
function get_config(key)
|
||||
if ui_mcm then return ui_mcm.get("SMR/smr_zzintegration/"..key) else return defaults[key] end
|
||||
end
|
||||
|
||||
function on_mcm_load()
|
||||
return { id="smr_zzintegration", sh=true, gr={
|
||||
{ id="integration_header", type="slide", link="ui_options_slider_alife", text="ui_mcm_menu_smr_zzintegration", size={512,50}, spacing=20 },
|
||||
{ id="integration_info", type="desc", text="ui_mcm_SMR_smr_zzintegration_integration_info" },
|
||||
{ id="glowsticks", type="check", val=1, def=false },
|
||||
{ id="glowsticks_info", type="desc", clr={200, 125, 125, 125}, text="ui_mcm_SMR_smr_zzintegration_glowsticks_info" },
|
||||
{ id="glowsticks_divider", type="line" },
|
||||
{ id="mags_redux", type="check", val=1, def=false },
|
||||
{ id="mags_redux_chance", type="track", val=2, min=1, max=100, step=1, def=5 },
|
||||
{ id="mags_redux_info", type="desc", clr={200, 125, 125, 125}, text="ui_mcm_SMR_smr_zzintegration_mags_redux_info" },
|
||||
{ id="lootboxes", type="check", val=1, def=false },
|
||||
{ id="lootboxes_chance", type="track", val=2, min=1, max=100, step=1, def=5 },
|
||||
{ id="lootboxes_info", type="desc", clr={200, 125, 125, 125}, text="ui_mcm_SMR_smr_zzintegration_lootboxes_info" },
|
||||
}}, "SMR"
|
||||
end
|
||||
@@ -0,0 +1,748 @@
|
||||
local DIALOG_ID = {}
|
||||
local sfind = string.find
|
||||
|
||||
local fetch_items = {}
|
||||
local fetch_rank_tier = {}
|
||||
|
||||
local patch_general = {
|
||||
["army"] = {
|
||||
["freedom_patch"] = 0,
|
||||
["bandit_patch"] = 0,
|
||||
["stalker_patch"] = 0,
|
||||
["csky_patch"] = 0,
|
||||
["monolith_patch"] = 0,
|
||||
},
|
||||
["bandit"] = {
|
||||
["army_patch"] = 0,
|
||||
["dolg_patch"] = 0,
|
||||
["stalker_patch"] = 0,
|
||||
["csky_patch"] = 0,
|
||||
["ecolog_patch"] = 0,
|
||||
},
|
||||
["csky"] = {
|
||||
["army_patch"] = 0,
|
||||
["bandit_patch"] = 0,
|
||||
["renegade_patch"] = 0,
|
||||
},
|
||||
["dolg"] = {
|
||||
["freedom_patch"] = 0,
|
||||
["bandit_patch"] = 0,
|
||||
["monolith_patch"] = 0,
|
||||
},
|
||||
["freedom"] = {
|
||||
["dolg_patch"] = 0,
|
||||
["army_patch"] = 0,
|
||||
["monolith_patch"] = 0,
|
||||
},
|
||||
["killer"] = {
|
||||
["freedom_patch"] = 0,
|
||||
["bandit_patch"] = 0,
|
||||
["dolg_patch"] = 0,
|
||||
["army_patch"] = 0,
|
||||
["monolith_patch"] = 0,
|
||||
},
|
||||
["monolith"] = {
|
||||
["army_patch"] = 0,
|
||||
["freedom_patch"] = 0,
|
||||
["bandit_patch"] = 0,
|
||||
["stalker_patch"] = 0,
|
||||
["csky_patch"] = 0,
|
||||
["dolg_patch"] = 0,
|
||||
},
|
||||
["stalker"] = {
|
||||
["bandit_patch"] = 0,
|
||||
},
|
||||
["greh"] = {
|
||||
["army_patch"] = 0,
|
||||
["freedom_patch"] = 0,
|
||||
["bandit_patch"] = 0,
|
||||
["stalker_patch"] = 0,
|
||||
["csky_patch"] = 0,
|
||||
["dolg_patch"] = 0,
|
||||
},
|
||||
["renegade"] = {
|
||||
["army_patch"] = 0,
|
||||
["dolg_patch"] = 0,
|
||||
["stalker_patch"] = 0,
|
||||
["csky_patch"] = 0,
|
||||
["ecolog_patch"] = 0,
|
||||
},
|
||||
}
|
||||
|
||||
local faction_lookup = { -- List of factions used in patch tasks
|
||||
"stalker",
|
||||
"dolg",
|
||||
"freedom",
|
||||
"csky",
|
||||
"ecolog",
|
||||
"killer",
|
||||
"army",
|
||||
"bandit",
|
||||
"monolith"
|
||||
}
|
||||
|
||||
if smr_amain_mcm.get_config("smr_enabled") then
|
||||
faction_lookup = smr_pop.get_faction_spawn_table()
|
||||
end
|
||||
|
||||
---------------------------< Utility >---------------------------
|
||||
function postpone_fetch_for_next_frame(task_id, section, amount)
|
||||
if not (task_id and section) then
|
||||
return true
|
||||
end
|
||||
|
||||
task_id = string.sub(task_id,1,-7) or "" -- because it ends with fetch
|
||||
amount = amount or 1
|
||||
local extra = ""
|
||||
if (ini_sys:r_string_ex(section,"kind") == "i_arty") then
|
||||
extra = " " .. game.translate_string("st_ui_artefact")
|
||||
end
|
||||
|
||||
local clr = utils_xml.get_color("pda_white") --"%c[255,238,153,26]"
|
||||
local news_caption = game.translate_string("ui_inv_needs") .. ":" --game.translate_string(task_manager.task_ini:r_string_ex(task_id, "title")) or "error"
|
||||
local news_ico = task_manager.task_ini:r_string_ex(task_id, "icon") or "ui_inGame2_D_Sisshik"
|
||||
local news_text = ui_item.get_sec_name(section) .. extra .. clr .. " (x" .. amount .. ")"
|
||||
|
||||
db.actor:give_talk_message2(news_caption, news_text, news_ico, "iconed_answer_item")
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
|
||||
xr_effects.fetch_reward_and_remove = function(actor, npc, p) -- Remove fetch items and give money reward:
|
||||
-- Description: Removes fetch task items and gives actor money reward based on item value
|
||||
-- Usage: fetch_reward_and_remove( p[1]:p[2] )
|
||||
-- Parameters:
|
||||
-- p[1] (type: string) Var name given to fetch task items
|
||||
-- p[2] (type: float) Multiplier for cost of items to apply to reward value (optional; default = 1.0)
|
||||
-- Return value (type: none): none, removes fetch items and gives actor reward
|
||||
|
||||
-- Get fetch items
|
||||
local sec = load_var( db.actor, p[1] )
|
||||
if not (sec) then return end
|
||||
|
||||
local sim = alife()
|
||||
|
||||
-- Extract artefact if its in container
|
||||
if string.find(sec,"af_") and (not db.actor:object(sec)) then
|
||||
local break_con
|
||||
local break_arty
|
||||
local id_combo
|
||||
local search_cont = { "lead_box" , "af_aam", "af_aac", "af_iam" }
|
||||
for i=1,#search_cont do
|
||||
if db.actor:object(sec .. "_" .. search_cont[i]) then
|
||||
break_arty = sec
|
||||
break_con = search_cont[i]
|
||||
id_combo = db.actor:object(sec .. "_" .. search_cont[i]):id()
|
||||
break
|
||||
end
|
||||
end
|
||||
|
||||
if id_combo and break_con and break_arty and ini_sys:section_exist(break_con) then
|
||||
printdbg("/ Artefact container found, artefact [%s] - contairer [%s]", break_arty, break_con)
|
||||
alife_create_item(break_arty, db.actor)
|
||||
alife_create_item(break_con, db.actor)
|
||||
alife_release_id(id_combo)
|
||||
|
||||
-- play effect
|
||||
level.add_cam_effector('camera_effects\\item_use.anm', 8053, false,'')
|
||||
xr_effects.play_inv_aac_open()
|
||||
end
|
||||
end
|
||||
|
||||
local function timer() -- delay for 1 sec, to register alife changes
|
||||
|
||||
-- Gather task items and cost
|
||||
local count = load_var( db.actor, (p[1] .. "_count") ) or 1
|
||||
local mult = tonumber(p[2]) or 1
|
||||
local max_use = IsItem("multiuse",sec) or 1
|
||||
local cost = ini_sys:r_float_ex(sec,"cost") * (1 / max_use)
|
||||
|
||||
local last_obj
|
||||
local collected_itms = {}
|
||||
local total_cost, remain = 0,0
|
||||
local cur_count = count
|
||||
local use_con = (max_use == 1) and (not IsItem("device",sec)) and (not IsItem("battery", sec)) and true or false
|
||||
local function itr(temp, obj)
|
||||
if (obj:section() == sec) then
|
||||
local cnt = (max_use > 1) and obj:get_remaining_uses() or 1
|
||||
local con = use_con and obj:condition() or 1
|
||||
|
||||
collected_itms[obj:id()] = cnt
|
||||
total_cost = total_cost + (cost * cnt * (con * con) * mult)
|
||||
cur_count = cur_count - cnt
|
||||
|
||||
last_obj = obj
|
||||
end
|
||||
if (cur_count <= 0) then
|
||||
if (cur_count < 0) then
|
||||
remain = math.abs(cur_count)
|
||||
end
|
||||
return true
|
||||
end
|
||||
--return false
|
||||
end
|
||||
db.actor:iterate_inventory(itr, nil)
|
||||
|
||||
-- Check availability
|
||||
if is_empty(collected_itms) then
|
||||
printe("! ERROR: fetch_reward_and_remove | no fetch item found!")
|
||||
return true
|
||||
end
|
||||
if (total_cost < 50) then
|
||||
total_cost = 50
|
||||
printf("~ Warning: fetch_reward_and_remove | total_cost is below 50")
|
||||
end
|
||||
|
||||
-- Reward value for artefacts depends on progression difficulty
|
||||
if IsArtefact(last_obj) then
|
||||
local eco = game_difficulties.get_eco_factor("type") or 0.5
|
||||
local factor = (eco == 3 and 0.4) or (eco == 2 and 0.5) or 0.6
|
||||
total_cost = total_cost * factor
|
||||
end
|
||||
--
|
||||
|
||||
local delta = math.floor(total_cost * 0.1)
|
||||
local min_reward = (total_cost - delta)
|
||||
local max_reward = (total_cost + delta)
|
||||
|
||||
xr_effects.reward_random_money( actor, npc, { min_reward , max_reward } )
|
||||
|
||||
-- Give task items to npc
|
||||
local trade_npc = false --get_speaker()
|
||||
for k,v in pairs(collected_itms) do
|
||||
if trade_npc then
|
||||
local obj = level.object_by_id(k)
|
||||
if obj then
|
||||
db.actor:transfer_item(obj, trade_npc)
|
||||
end
|
||||
else
|
||||
alife_release_id(k)
|
||||
end
|
||||
end
|
||||
if (remain > 0) and IsItem("multiuse",sec) then
|
||||
alife_create_item(sec, db.actor, {uses = remain})
|
||||
local last_obj_uses = last_obj:get_remaining_uses()
|
||||
if last_obj_uses and (last_obj_uses > remain) then
|
||||
local uses = (last_obj_uses - remain)
|
||||
alife_process_item(last_obj:section(), last_obj:id(), {uses = uses})
|
||||
end
|
||||
end
|
||||
|
||||
news_manager.relocate_item(db.actor, "out", sec, count)
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
CreateTimeEvent(0,"delay_reward", 1, timer)
|
||||
end
|
||||
|
||||
xr_effects.remove_fetch_item = function(actor,npc,p)
|
||||
local section = load_var(db.actor,p[1])
|
||||
if (section and db.actor:object(section)) then
|
||||
local amt = p[2] or load_var(db.actor,p[1].."_count") or 1
|
||||
local trade_npc = get_speaker()
|
||||
if (trade_npc) then
|
||||
local function transfer_object_item(itm)
|
||||
if (itm:section() == section and amt > 0) then
|
||||
db.actor:transfer_item(itm, trade_npc)
|
||||
amt = amt - 1
|
||||
end
|
||||
if (amt <= 0) then
|
||||
return true
|
||||
end
|
||||
return false
|
||||
end
|
||||
db.actor:inventory_for_each(transfer_object_item)
|
||||
else
|
||||
xr_effects.remove_item(actor, npc, {section,amt})
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
xr_effects.remove_artefact_item = function(actor,npc,p)
|
||||
local section = load_var(db.actor,p[1])
|
||||
if (not section) then
|
||||
printe("!ERROR xr_effects.remove_artefact_item | no var found for %s", p[1])
|
||||
return
|
||||
end
|
||||
|
||||
local cont
|
||||
local obj = db.actor:object(section)
|
||||
if (not obj) then
|
||||
local search_cont = { "lead_box" , "af_aam", "af_aac", "af_iam" }
|
||||
for i=1,#search_cont do
|
||||
if db.actor:object(section .. "_" .. search_cont[i]) then
|
||||
obj = db.actor:object(section .. "_" .. search_cont[i])
|
||||
cont = search_cont[i]
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if (not obj) then
|
||||
return
|
||||
end
|
||||
|
||||
local trade_npc = get_speaker()
|
||||
if (trade_npc) then
|
||||
db.actor:transfer_item(obj, trade_npc)
|
||||
else
|
||||
alife_release(obj)
|
||||
end
|
||||
|
||||
if cont then
|
||||
alife_create_item(cont, db.actor)
|
||||
|
||||
-- play effect
|
||||
level.add_cam_effector('camera_effects\\item_use.anm', 8053, false,'')
|
||||
xr_effects.play_inv_aac_open()
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
---------------------------< Effects >---------------------------
|
||||
local function get_suitable_item(tbl,rank)
|
||||
local temp = {}
|
||||
for sec,tier in pairs(tbl) do
|
||||
if (not rank) or (rank and fetch_rank_tier[rank] and fetch_rank_tier[rank][tier]) then
|
||||
temp[#temp + 1] = sec
|
||||
--printf("- Fetch items | found proper item [%s] tier (%s) for rank (%s)", sec, tier, rank)
|
||||
end
|
||||
end
|
||||
return (#temp > 0) and temp[math.random(#temp)]
|
||||
end
|
||||
|
||||
xr_effects.setup_fetch_task = function(actor,npc,p) -- setup_supplies_fetch_task
|
||||
-- Pick a random item from the list:
|
||||
-- param 1 - var name
|
||||
-- param 2 - items type
|
||||
-- param 2 - min count
|
||||
-- param 3 - max count
|
||||
|
||||
local npc = get_speaker(true)
|
||||
local id = npc and npc:id()
|
||||
local sec = DIALOG_ID[id] and DIALOG_ID[id][p[1]] and DIALOG_ID[id][p[1]].sec
|
||||
local cnt = DIALOG_ID[id] and DIALOG_ID[id][p[1]] and DIALOG_ID[id][p[1]].cnt
|
||||
|
||||
if (sec and ini_sys:section_exist(sec) and cnt) then
|
||||
dialogs._FETCH_TEXT = ui_item.get_sec_name(sec)
|
||||
save_var( db.actor, p[1], sec )
|
||||
save_var( db.actor, (p[1] .. "_count"), cnt )
|
||||
|
||||
else
|
||||
local npc_comm = npc and character_community(npc) or "stalker"
|
||||
local npc_rank = ranks.get_obj_rank_name(npc) or "experienced"
|
||||
|
||||
local itms = {} -- non-key table
|
||||
|
||||
-- expand supplies list to include drinks and smoke if the task giver is not monolith
|
||||
if (p[2] == "supplies") and (npc_comm ~= "monolith") then
|
||||
itms = fetch_items["supplies"]
|
||||
for sec,tier in pairs(fetch_items["drink"]) do
|
||||
itms[sec] = tier
|
||||
end
|
||||
|
||||
-- Gather patches of NPC's enemy factions
|
||||
elseif (p[2] == "patch_general") then
|
||||
local patches = {}
|
||||
for i=1,#faction_lookup do
|
||||
if game_relations.is_factions_enemies(faction_lookup[i], npc_comm) then
|
||||
local comm
|
||||
if (faction_lookup[i] == "killer") then comm = "merc"
|
||||
elseif (faction_lookup[i] == "dolg") then comm = "duty"
|
||||
else comm = faction_lookup[i]
|
||||
end
|
||||
|
||||
local patch = comm .. "_patch"
|
||||
patches[patch] = 0
|
||||
end
|
||||
end
|
||||
|
||||
if is_empty(patches) then
|
||||
if smr_amain_mcm.get_config("smr_enabled") then
|
||||
local t = smr_pop.get_faction_spawn_table()
|
||||
local patch = t[math.random(#t)] .. "_patch"
|
||||
patches[patch] = 0
|
||||
else
|
||||
patches = patch_general[npc_comm]
|
||||
end
|
||||
end
|
||||
|
||||
itms = patches
|
||||
|
||||
-- Gather suitable repair kits
|
||||
elseif (p[2] == "repair") then
|
||||
|
||||
-- Get NPC's weapon
|
||||
local obj_wep = npc:best_weapon()
|
||||
local sec_wep = obj_wep and obj_wep:section()
|
||||
|
||||
-- Gather proper repair kits
|
||||
local repair_kits = {
|
||||
["sharpening_stones"] = 0,
|
||||
["sewing_kit_b"] = 0,
|
||||
}
|
||||
if sec_wep then
|
||||
local wep_type = ini_sys:r_string_ex(sec_wep,"repair_type") or ""
|
||||
for sec,tier in pairs(fetch_items["repair"]) do
|
||||
local kit_type = parse_list(ini_sys,sec,"repair_only",true)
|
||||
if kit_type[wep_type] then
|
||||
repair_kits[sec] = tier
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
itms = repair_kits
|
||||
|
||||
-- Gather suitable weapons
|
||||
elseif (p[2] == "weapons") then
|
||||
local f = faction_expansions.faction[npc_comm]
|
||||
local npc_preference = f and f["weapon"] or ""
|
||||
|
||||
-- Collects weapons suitable for npc rank
|
||||
local wpn_by_rank = {}
|
||||
if fetch_items["weapons_" .. npc_rank] then
|
||||
local tbl = fetch_items["weapons_" .. npc_rank]
|
||||
for sec,tier in pairs(tbl) do
|
||||
wpn_by_rank[sec] = tier
|
||||
end
|
||||
end
|
||||
|
||||
-- Collects weapons suitable for npc faction
|
||||
local wpn_by_ref = {}
|
||||
if fetch_items["weapons_" .. npc_preference] then
|
||||
local tbl = fetch_items["weapons_" .. npc_preference]
|
||||
for sec,tier in pairs(tbl) do
|
||||
wpn_by_ref[sec] = tier
|
||||
end
|
||||
end
|
||||
|
||||
-- collect suitable weapons
|
||||
local wpns = {}
|
||||
for sec,tier in pairs(wpn_by_rank) do
|
||||
if wpn_by_ref[sec] then
|
||||
wpns[sec] = tier
|
||||
end
|
||||
end
|
||||
for sec,tier in pairs(wpn_by_ref) do
|
||||
if wpn_by_rank[sec] then
|
||||
wpns[sec] = tier
|
||||
end
|
||||
end
|
||||
|
||||
if is_not_empty(wpns) then
|
||||
itms = wpns
|
||||
else
|
||||
itms = fetch_items["weapons"]
|
||||
end
|
||||
else
|
||||
itms = fetch_items[p[2]]
|
||||
end
|
||||
|
||||
if (not itms) then
|
||||
printe("! ERROR: %s | fetch list [%s] is invalid", p[1], p[2])
|
||||
end
|
||||
|
||||
local min_count = (p[3] and tonumber( p[3] ) or 1)
|
||||
local max_count = (p[4] and tonumber( p[4] ) or min_count)
|
||||
sec = get_suitable_item(itms, npc_rank) or random_key_table(itms)
|
||||
cnt = math.random( min_count, max_count )
|
||||
|
||||
-- Save chosen fetch item:
|
||||
if (not DIALOG_ID[id]) then DIALOG_ID[id] = {} end
|
||||
if (not DIALOG_ID[id][p[1]]) then DIALOG_ID[id][p[1]] = {} end
|
||||
|
||||
DIALOG_ID[id][p[1]].sec = sec
|
||||
DIALOG_ID[id][p[1]].cnt = cnt
|
||||
dialogs._FETCH_TEXT = ui_item.get_sec_name(sec)
|
||||
save_var( db.actor, p[1], sec )
|
||||
save_var( db.actor, (p[1] .. "_count"), cnt )
|
||||
|
||||
end
|
||||
|
||||
CreateTimeEvent(0,"setup_fetch_task", 0, postpone_fetch_for_next_frame, p[1], sec, cnt)
|
||||
end
|
||||
|
||||
xr_effects.setup_supplies_fetch_task_lostzone_patch = function(actor,npc,p)
|
||||
local npc = get_speaker(true)
|
||||
local id = npc and npc:id()
|
||||
local sec = DIALOG_ID[id] and DIALOG_ID[id][p[1]] and DIALOG_ID[id][p[1]].sec
|
||||
local cnt = DIALOG_ID[id] and DIALOG_ID[id][p[1]] and DIALOG_ID[id][p[1]].cnt
|
||||
|
||||
if (sec and cnt and ini_sys:section_exist(sec)) then
|
||||
dialogs._FETCH_TEXT = ui_item.get_sec_name(sec)
|
||||
save_var( db.actor, p[1], sec )
|
||||
save_var( db.actor, (p[1] .. "_count"), cnt )
|
||||
else
|
||||
local comm = npc and character_community(npc) or "stalker"
|
||||
local itms = patch_general[comm] or patch_general["stalker"]
|
||||
-- SMR
|
||||
if smr_amain_mcm.get_config("smr_enabled") then
|
||||
local itms = {}
|
||||
for i=1,#faction_lookup do
|
||||
if game_relations.is_factions_enemies(faction_lookup[i], comm) then
|
||||
if (faction_lookup[i] == "killer") then comm = "merc"
|
||||
elseif (faction_lookup[i] == "dolg") then comm = "duty"
|
||||
else comm = faction_lookup[i]
|
||||
end
|
||||
local patch = comm .. "_patch"
|
||||
itms[patch] = 0
|
||||
end
|
||||
end
|
||||
|
||||
if is_empty(itms) then
|
||||
local t = smr_pop.get_faction_spawn_table()
|
||||
local patch = t[math.random(#t)] .. "_patch"
|
||||
itms[patch] = 0
|
||||
end
|
||||
end
|
||||
sec = random_key_table(itms)
|
||||
cnt = math.random(p[2] and tonumber(p[2]) or 1,p[3] and tonumber(p[3]) or 1)
|
||||
|
||||
-- Save chosen fetch item:
|
||||
if (not DIALOG_ID[id]) then DIALOG_ID[id] = {} end
|
||||
if (not DIALOG_ID[id][p[1]]) then DIALOG_ID[id][p[1]] = {} end
|
||||
|
||||
DIALOG_ID[id][p[1]].sec = sec
|
||||
DIALOG_ID[id][p[1]].cnt = cnt
|
||||
dialogs._FETCH_TEXT = ui_item.get_sec_name(sec)
|
||||
save_var( db.actor, p[1], sec )
|
||||
save_var( db.actor, (p[1] .. "_count"), cnt )
|
||||
end
|
||||
|
||||
CreateTimeEvent(0,"setup_fetch_task", 0, postpone_fetch_for_next_frame, p[1], sec, cnt)
|
||||
end
|
||||
|
||||
xr_effects.setup_generic_fetch_task = function(actor,npc,p)
|
||||
-- param1 - variable name
|
||||
-- param2 - count
|
||||
-- param3+ - sections
|
||||
|
||||
if (p[1] and p[2] and p[3]) then
|
||||
local npc = get_speaker(true)
|
||||
local id = npc and npc:id()
|
||||
local sec = DIALOG_ID[id] and DIALOG_ID[id][p[1]] and DIALOG_ID[id][p[1]].sec
|
||||
local cnt = DIALOG_ID[id] and DIALOG_ID[id][p[1]] and DIALOG_ID[id][p[1]].cnt
|
||||
|
||||
if (sec and cnt and ini_sys:section_exist(sec)) then
|
||||
dialogs._FETCH_TEXT = ui_item.get_sec_name(sec)
|
||||
save_var( db.actor, p[1], sec )
|
||||
if (cnt > 1) then
|
||||
save_var( db.actor, (p[1] .. "_count"), cnt )
|
||||
end
|
||||
else
|
||||
sec = #p > 3 and p[math.random(3,#p)] or p[3]
|
||||
if (sec and ini_sys:section_exist(sec)) then
|
||||
cnt = tonumber(p[2]) or 1
|
||||
|
||||
-- Save chosen fetch item:
|
||||
if (not DIALOG_ID[id]) then DIALOG_ID[id] = {} end
|
||||
if (not DIALOG_ID[id][p[1]]) then DIALOG_ID[id][p[1]] = {} end
|
||||
|
||||
DIALOG_ID[id][p[1]].sec = sec
|
||||
DIALOG_ID[id][p[1]].cnt = cnt
|
||||
dialogs._FETCH_TEXT = ui_item.get_sec_name(sec)
|
||||
save_var( db.actor, p[1], sec )
|
||||
if (cnt > 1) then
|
||||
save_var( db.actor, (p[1] .. "_count"), cnt )
|
||||
end
|
||||
else
|
||||
printe("!ERROR: xr_effects:setup_generic_fetch_task - invalid section %s",sec)
|
||||
end
|
||||
end
|
||||
|
||||
CreateTimeEvent(0,"setup_fetch_task", 0, postpone_fetch_for_next_frame, p[1], sec, cnt)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
---------------------------< Target functor >---------------------------
|
||||
task_functor.general_fetch_task = function(task_id,field,p,tsk)
|
||||
if (field == "title") then
|
||||
local fetch = db.actor and ui_item.get_sec_name(load_var(db.actor,task_id.."_fetch",""))
|
||||
local count = fetch and load_var(db.actor,task_id.."_fetch_count") or 1
|
||||
if (count > 1) then
|
||||
return strformat((game.translate_string(p) or ""),fetch .. " x" .. tostring(count))
|
||||
end
|
||||
return strformat(game.translate_string(p) or "",fetch)
|
||||
elseif (field == "descr") then
|
||||
if (tsk.stage == 1) then
|
||||
return game.translate_string("st_return_for_reward")
|
||||
end
|
||||
local fetch = db.actor and ui_item.get_sec_name(load_var(db.actor,task_id.."_fetch",""))
|
||||
local count = fetch and load_var(db.actor,task_id.."_fetch_count") or 1
|
||||
if (count > 1) then
|
||||
return strformat((game.translate_string(p) or ""),fetch .. " x" .. tostring(count))
|
||||
end
|
||||
return strformat(game.translate_string(p) or "",fetch)
|
||||
elseif (field == "target") then
|
||||
if (tsk.stage == 1) then
|
||||
local id = db.actor and load_var(db.actor,task_id.."_target_id") or tsk.task_giver_id
|
||||
if (id) then
|
||||
return id
|
||||
end
|
||||
local story_id = string.sub(task_id,1,string.find(task_id,"_task")-1)
|
||||
local se_obj = get_story_se_object(story_id)
|
||||
if (se_obj) then
|
||||
return se_obj.id
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
task_functor.general_warfare_fetch_task = function(task_id,field,p,tsk) -- xQd, add the name and location of the warfare trader to the task description along with the fetch item
|
||||
local id = tsk.task_giver_id
|
||||
local se_obj = id and alife_object(id)
|
||||
if not (se_obj) then
|
||||
--printf("is_task_giver_valid se_obj nil id=%s %s",id,tsk.id)
|
||||
return ""
|
||||
else
|
||||
local name = se_obj:character_name()
|
||||
local lvl = --[[game.translate_string(se_obj.community) or]] game.translate_string(alife():level_name(game_graph():vertex(se_obj.m_game_vertex_id):level_id()))
|
||||
if (field == "title") then
|
||||
local fetch = db.actor and ui_item.get_sec_name(load_var(db.actor,task_id.."_fetch",""))
|
||||
local count = fetch and load_var(db.actor,task_id.."_fetch_count") or 1
|
||||
if (count > 1) then
|
||||
return strformat((game.translate_string(p) or ""),fetch .. " x" .. tostring(count))
|
||||
end
|
||||
return strformat(game.translate_string(p) or "",fetch)
|
||||
elseif (field == "descr") then
|
||||
if (tsk.stage == 1) then
|
||||
return game.translate_string("st_return_for_reward")
|
||||
end
|
||||
local fetch = db.actor and ui_item.get_sec_name(load_var(db.actor,task_id.."_fetch",""))
|
||||
local count = fetch and load_var(db.actor,task_id.."_fetch_count") or 1
|
||||
if (count > 1) then
|
||||
return strformat((game.translate_string(p) or ""),name,lvl,fetch .. " x" .. tostring(count))
|
||||
end
|
||||
return strformat(game.translate_string(p) or "",name,lvl,fetch)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
---------------------------< Status functor >---------------------------
|
||||
task_status_functor.actor_has_fetch_item = function(tsk,task_id)
|
||||
local actor = db.actor
|
||||
local section = actor and load_var(actor,task_id.."_fetch")
|
||||
if (not section) then
|
||||
return
|
||||
end
|
||||
|
||||
local item = section and actor:object(section)
|
||||
if (item ~= nil) then
|
||||
if (task_id == "esc_2_12_stalker_nimble_task_1" or task_id == "jup_b220_trapper_task_3") then
|
||||
if (item:condition() >= 0.9) then
|
||||
tsk.stage = 1
|
||||
else
|
||||
tsk.stage = 0
|
||||
end
|
||||
else
|
||||
local count = load_var(actor,task_id.."_fetch_count")
|
||||
if (count and count > 1) then
|
||||
local cnt = utils_item.get_amount(db.actor, section, 1)
|
||||
if (cnt >= count) then
|
||||
tsk.stage = 1
|
||||
else
|
||||
tsk.stage = 0
|
||||
end
|
||||
return
|
||||
end
|
||||
tsk.stage = 1 -- should never happen but in such case let player finish quest for free
|
||||
end
|
||||
|
||||
elseif section and sfind(section,"af_") then
|
||||
if actor:object(section .. "_af_aam")
|
||||
or actor:object(section .. "_af_iam")
|
||||
or actor:object(section .. "_af_aac")
|
||||
or actor:object(section .. "_lead_box")
|
||||
then
|
||||
tsk.stage = 1
|
||||
else
|
||||
tsk.stage = 0
|
||||
end
|
||||
else
|
||||
tsk.stage = 0
|
||||
end
|
||||
end
|
||||
|
||||
task_status_functor.actor_has_fetch_weapon_warfare = function(tsk,task_id) -- xQd, added this for warfare fetch weapon tasks
|
||||
if not (db.actor) then
|
||||
return
|
||||
end
|
||||
local section = db.actor and load_var(db.actor,task_id.."_fetch")
|
||||
local item = section and db.actor:object(section)
|
||||
if (item ~= nil) then
|
||||
if (item:condition() >= 0.60) then
|
||||
tsk.stage = 1
|
||||
else
|
||||
tsk.stage = 0
|
||||
end
|
||||
else
|
||||
tsk.stage = 0
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
---------------------------< Callbacks >---------------------------
|
||||
local function save_state(m_data)
|
||||
m_data.tasks_fetch_ids = DIALOG_ID
|
||||
end
|
||||
|
||||
local function load_state(m_data)
|
||||
DIALOG_ID = m_data.tasks_fetch_ids or {}
|
||||
end
|
||||
|
||||
local function on_before_level_changing()
|
||||
empty_table(DIALOG_ID)
|
||||
alife_storage_manager.get_state().tasks_fetch_ids = nil
|
||||
printdbg("~ tasks_fetch | cleaned fetch list for npcs")
|
||||
end
|
||||
|
||||
function on_game_start()
|
||||
local ini_fetch = ini_file("items\\settings\\fetch_list.ltx")
|
||||
local n = 0
|
||||
local result, id, value = "","",""
|
||||
|
||||
local list = {}
|
||||
n = ini_fetch:line_count("fetch_list")
|
||||
for i=0,n-1 do
|
||||
result, id, value = ini_fetch:r_line_ex("fetch_list",i,"","")
|
||||
list[#list + 1] = id
|
||||
end
|
||||
|
||||
n = ini_fetch:line_count("fetch_tiers")
|
||||
for i=0,n-1 do
|
||||
result, id, value = ini_fetch:r_line_ex("fetch_tiers",i,"","")
|
||||
if id and value then
|
||||
fetch_rank_tier[id] = {}
|
||||
fetch_rank_tier[id][0] = true
|
||||
local nums = str_explode(value,",")
|
||||
for j=1,#nums do
|
||||
local m = tonumber(nums[j]) or 0
|
||||
fetch_rank_tier[id][m] = true
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
for k=1,#list do
|
||||
local category = list[k]
|
||||
fetch_items[category] = {}
|
||||
|
||||
n = ini_fetch:line_count(category)
|
||||
for i=0,n-1 do
|
||||
result, id, value = ini_fetch:r_line_ex(category,i,"","")
|
||||
if id and ini_sys:section_exist(id) then
|
||||
fetch_items[category][id] = (value == "true" and 0) or ini_sys:r_float_ex(id,"tier") or 0
|
||||
else
|
||||
printe("! WARNING: fetch_list.ltx | wrong section name [%s]", id)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
RegisterScriptCallback("save_state",save_state)
|
||||
RegisterScriptCallback("load_state",load_state)
|
||||
RegisterScriptCallback("on_before_level_changing",on_before_level_changing)
|
||||
end
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,37 @@
|
||||
|
||||
local SINGLETON = nil
|
||||
function get_ui()
|
||||
SINGLETON = SINGLETON or pda_glitched_tab()
|
||||
SINGLETON:Reset()
|
||||
return SINGLETON
|
||||
end
|
||||
|
||||
class "pda_glitched_tab" (CUIScriptWnd)
|
||||
function pda_glitched_tab:__init() super()
|
||||
self:InitControls()
|
||||
end
|
||||
|
||||
function pda_glitched_tab:__finalize()
|
||||
end
|
||||
|
||||
function pda_glitched_tab:InitControls()
|
||||
self:SetWndRect(Frect():set(0,0,1024,768))
|
||||
local xml = CScriptXmlInit()
|
||||
xml:ParseFile("pda_glitched.xml")
|
||||
self.form = xml:InitStatic("glitched_pda",self)
|
||||
self.form_text = xml:InitTextWnd("glitched_pda:state", self.form)
|
||||
end
|
||||
|
||||
function pda_glitched_tab:Update()
|
||||
CUIScriptWnd.Update(self)
|
||||
end
|
||||
|
||||
|
||||
|
||||
function pda_glitched_tab:Reset()
|
||||
self.form_text:SetText(game.translate_string("st_smr_glitched_pda_text"))
|
||||
self.form_text:SetTextColor(GetARGB(255, 255, 255, 1))
|
||||
self.form_text:Show(true)
|
||||
local pda_menu = ActorMenu.get_pda_menu()
|
||||
pda_menu:GetTabControl():Show(false)
|
||||
end
|
||||
Reference in New Issue
Block a user