Divergent/mods/Western Goods/gamedata/scripts/western_goods_utils.script

989 lines
34 KiB
Plaintext
Raw Permalink Normal View History

2024-03-17 20:18:03 -04:00
---==================================================================================================================---
--- ---
--- Original Author(s) : NLTP_ASHES ---
--- Edited : N/A ---
--- Date : 05/02/2024 ---
--- License : Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International (CC BY-NC-SA 4.0) ---
--- ---
--- Script used to define various common functions defined in the scripts of the Western Goods addon. ---
--- ---
---==================================================================================================================---
-- ---------------------------------------------------------------------------------------------------------------------
-- Constants, global variables and imported functions
-- ---------------------------------------------------------------------------------------------------------------------
local ini_loc = ini_file_ex([[localization.ltx]])
local ini_keys = ini_file_ex([[plugins\western_goods\misc\western_goods_key_localization.ltx]])
local ini_trade = ini_file([[items\trade\trade_generic.ltx]])
-- ---------------------------------------------------------------------------------------------------------------------
-- Debug Functions
-- ---------------------------------------------------------------------------------------------------------------------
--- Function used to print information into the console/log file only when Western Goods' debug mode is enabled.
--- @return nil
function dbg_printf(...)
if not western_goods_mcm.get_config("debug_mode") then return end
printf(...)
end
-- ---------------------------------------------------------------------------------------------------------------------
-- Table Functions
-- ---------------------------------------------------------------------------------------------------------------------
--- Function used to know if a certain value is contained in a table. This function is generic enough so that it'd work on any table.
--- @param tab table
--- @param val any
--- @return boolean
function table_contains(tab, val)
if not validate_params({tab,val,"table_contains"}) then return end
for _,value in pairs(tab) do
if val == value then
return true
end
end
return false
end
--- Function used to get a random id (as an int) from a given table.
--- Returns a random number between 1 and the size of the table.
--- @param tab table
--- @return number
function table_random_id(tab)
if not validate_params({tab,"table_random_id"}) then return end
return math.random(1,#tab)
end
--- Function used to get a random key from a key-value table.
--- @param tab table
--- @return any
function table_random_key(tab)
if not validate_params({tab,"table_random_key"}) then return end
local n = {}
for k,v in pairs(tab) do
n[#n+1] = k
end
return #n > 0 and n[math.random(#n)] or nil
end
--- Function used to know if an element of a table has a next.
--- @param tab table
--- @param pos number
--- @return boolean
function has_next(tab, pos)
if not validate_params({tab,pos,"has_next"}) then return end
return next(tab,pos) ~= nil
end
-- ---------------------------------------------------------------------------------------------------------------------
-- Data Functions
-- ---------------------------------------------------------------------------------------------------------------------
--- Function used to get a given variable as a number. Returns nil if the variable cannot be casted.
--- @param var any
--- @return number
function as_number(var)
if not validate_params({var,"as_number"}) then return end
if type(var) == "string" then
return tonumber(var)
end
if type(var) == "number" then
return var
end
printf("![WG] ERROR | Utils | Cannot cast variable to number")
return var
end
--- Function used to get a given variable as a string. Returns nil if the variable cannot be casted.
--- The parameter length can be used to specify the length of the return value, when working with numbers.
--- The function will add 0s before the number to match the desired length.
--- @param var any
--- @param length number
--- @return string
function as_string(var, length)
if not validate_params({var,"as_string"}) then return end
if type(var) == "number" then
local ret = tostring(var)
if length then
while #ret < length do
ret = "0" .. ret
end
end
return ret
end
if type(var) == "boolean" then
return tostring(var)
end
if type(var) == "string" then
return var
end
printf("![WG] ERROR | Utils | Cannot cast variable to string")
return var
end
--- Function used to get a given variable as a boolean. Returns nil if the variable cannot be casted.
--- @param var any
--- @return boolean
function as_boolean(var)
if not validate_params({var,"as_boolean"}) then return end
if type(var) == "string" then
if var == "true" then
return true
elseif var == "false" then
return false
end
end
if type(var) == "boolean" then
return var
end
printf("![WG] ERROR | Utils | Cannot cast variable to boolean")
return var
end
--- Function used to clear the code a bit.
--- @param num number
--- @return number
function round_number(num)
if not validate_params({num,"round_number"}) then return end
return tostring(math.floor(num+0.5))
end
--- Function used to know if there exists a translation for a given game string.
--- @param str string
--- @return boolean
function has_translation(str)
if not validate_params({str,"has_translation"}) then return end
return game.translate_string(str) ~= str
end
--- Function used to know if there exists a translation for a given game string.
--- @param str string
--- @return boolean
function get_translation(str, ...)
if not validate_params({str,"get_translation"}) then return end
if not has_translation(str) then
return str.."[Missing translation]"
end
local string = game.translate_string(str)
if (select('#',...) >= 1) then
local i = 0
local p = {...}
local function sr()
i = i + 1
if (type(p[i]) == "userdata") then
return "userdata"
end
return tostring(p[i])
end
string = string.gsub(string,"%%s",sr)
end
return string
end
--- Function used to print the a textual version of a DIK key.
--- @author RavenAscendant
--- @param dik DIK_keys
--- @return string
function get_key_translation(dik)
if not validate_params({dik,"get_key_translation"}) then return end
local loc = ini_loc:r_value("string_table","language")
loc = ini_keys:section_exist(loc) and loc or "eng"
return ini_keys:r_value(loc, dik,0,"<!!!>")
end
-- ---------------------------------------------------------------------------------------------------------------------
-- Info Portions Functions
-- ---------------------------------------------------------------------------------------------------------------------
--- Function used to give an info portion to a game object.
--- If no game object is passed, defaults back to db.actor.
--- @param info_name string
--- @param who game_object
--- @return nil
function give_info(info_name, who)
if not validate_params({info_name,"give_info"}) then return end
-- Default values
who = who or db.actor
if not has_info(info_name,who) then
who:give_info_portion(info_name)
dbg_printf("[WG] Utils | Info portion '%s' added to '%s'", info_name, who:name())
end
end
--- Function used to check if a game object has a given info portion.
--- If no game object is passed, defaults back to db.actor.
--- @param info_name string
--- @param who game_object
--- @return nil
function has_info(info_name, who)
if not validate_params({info_name,"has_info"}) then return end
-- Default values
who = who or db.actor
return alife():has_info(who:id(), info_name)
end
--- Function used to remove an info portion from a game object.
--- If no game object is passed, defaults back to db.actor.
--- @param info_name string
--- @param who game_object
--- @return nil
function rem_info(info_name, who)
if not validate_params({info_name,"rem_info"}) then return end
-- Default values
who = who or db.actor
if has_info(info_name,who) then
who:disable_info_portion(info_name)
dbg_printf("[WG] Utils | Info portion '%s' disabled from '%s'", info_name, who:name())
end
end
-- ---------------------------------------------------------------------------------------------------------------------
-- Distance Functions
-- ---------------------------------------------------------------------------------------------------------------------
--- Function used to get the distance between two points in on the X and Z axis.
--- @param position_1 vector
--- @param position_2 vector
--- @return number
function get_distance(position_1, position_2)
if not validate_params({position_1,position_2,"get_distance"}) then return end
return position_1:distance_to(position_2) or 100000
end
--- Function used to get the distance between two points in on the X and Z axis.
--- @param position_1 vector
--- @param position_2 vector
--- @return number
function get_distance_sqr(position_1, position_2)
if not validate_params({position_1,position_2,"get_distance_sqr"}) then return end
return position_1:distance_to_sqr(position_2) or 10000000000
end
-- ---------------------------------------------------------------------------------------------------------------------
-- Objects Getter Functions
-- ---------------------------------------------------------------------------------------------------------------------
--- Function used to iterate through each existing server object.
--- The function passed in arguments will be called once per game object, with a guarantee that the server object exists and isn't nil.
--- Extra arguments passed to 'server_objects_iter' function are passed on to 'func' function.
--- If 'func' function returns true, then the iteration stops.
--- @param func function
--- @param ... table
--- @return nil
function server_objects_iter(func, ...)
if not validate_params({func,"server_objects_iter"}) then return end
dbg_printf("[WG] Utils | Iterating through all possible IDs...")
local args = {...}
if alife().iterate_object ~= nil then
alife():iterate_object(function(se_obj)
return func(se_obj, unpack(args))
end)
else
for id=0, 65534 do
local se_obj = alife_object(id)
if se_obj and func(se_obj, unpack(args)) then
return
end
end
end
end
--- Function used to retrieve a server object by its story ID.
--- @param story_id string
--- @return cse_alife_object|nil
function server_object_by_sid(story_id)
if not validate_params({story_id,"server_object_by_sid"}) then return end
return get_story_se_object(story_id)
end
--- Function used to retrieve a level object by its story ID.
--- @param story_id string
--- @return game_object|nil
function level_object_by_sid(story_id)
if not validate_params({story_id,"level_object_by_sid"}) then return end
local se_obj = server_object_by_sid(story_id)
return se_obj and level_object_by_id(se_obj.id)
end
--- Function used to get game object by its ID if it exists on the current level.
--- @param id number
--- @return game_object
function level_object_by_id(id)
if not validate_params({id,"level_object_by_id"}) then return end
return db.storage[id] and db.storage[id].object or level.object_by_id(id)
end
-- ---------------------------------------------------------------------------------------------------------------------
-- Objects Functions
-- ---------------------------------------------------------------------------------------------------------------------
--- Function used to get the character ID of an NPC.
--- @param se_obj cse_alife_object|game_object
--- @return string
function get_character_id(se_obj)
if not validate_params({se_obj,"get_character_id"}) then return end
-- Get cse_alife_object if game_object is passed
if type(se_obj.id) == "function" then
se_obj = alife_object(se_obj:id())
end
if not IsStalker(se_obj) then
return
end
local net_data = utils_stpk.get_stalker_data(se_obj)
if not net_data then
printf("![WG] ERROR | Utils | Failed to get Stalker Net Data for %s", se_obj:section_name())
return
end
dbg_printf("[WG] Utils | NPC %s(%s) has character ID '%s'", se_obj:section_name(), se_obj.id, net_data.specific_character)
return net_data.specific_character
end
--- Function used to get the list of dialogs of a given character.
--- @param character_id string
--- @return table
function get_dialog_list(character_id)
if not validate_params({character_id,"get_dialog_list"}) then return end
dbg_printf("[WG] Utils | Getting dialog list for '%s'...", character_id)
local profiler = profile_timer()
profiler:start()
local dialog_list = {}
local file_list = str_explode(ini_sys:r_string("profiles", "specific_characters_files"),",")
for _,file_name in pairs(file_list) do
local xml = CScriptXmlInit()
xml:ParseDirFile([[gameplay]],file_name..".xml")
local char_count = xml:GetNodesNum("", 0, "specific_character")
for i=0, char_count-1 do
local char_id = xml:ReadAttribute("specific_character", i, "id")
if char_id == character_id then
xml:NavigateToNode("specific_character", i)
local diag_count = xml:GetNodesNum("specific_character", i, "actor_dialog")
for y=0, diag_count-1 do
table.insert(dialog_list, xml:ReadValue("actor_dialog", y))
end
profiler:stop()
dbg_printf("[WG] Utils | Dialog list of '%s' retrieved in %sms :\n%s", character_id, profiler:time()/1000, utils_data.print_table(dialog_list, false, true))
return dialog_list
end
end
end
profiler:stop()
printf("![WG] ERROR | Utils | Impossible to get dialog list, character '%s' not found !", character_id)
end
-- ---------------------------------------------------------------------------------------------------------------------
-- File Functions
-- ---------------------------------------------------------------------------------------------------------------------
--- Function used to list all the files in a given folder (excluding the sub-folders).
--- @param path string
--- @return table
function list_files(path)
local file_list_fs = getFS():file_list_open("$game_config$", path, bit_or(FS.FS_ListFiles, FS.FS_RootOnly))
local file_list = {}
local count = file_list_fs and file_list_fs:Size() or 0
if count <= 0 then
return file_list
end
for i = 1, count do
local file_name = file_list_fs:GetAt(i - 1)
if file_name then
file_list[#file_list + 1] = file_name
end
end
return file_list
end
--- Function used to list all the texture descriptions matching a given pattern.
--- Texture descriptions have to be in gamedata/configs/ui/textures_descr/.
--- This function takes on average 300ms, prioritize using it in on_game_load to avoid stutters.
--- @param pattern string
--- @return table
function collect_texture_descriptions(pattern)
this.dbg_printf("[WG] Utils | Getting matching texture descriptions for '%s'...", pattern)
local profiler = profile_timer()
profiler:start()
local file_list = this.list_files("ui\\textures_descr\\")
local matches = {}
for _,file_name in pairs(file_list) do
local xml = CScriptXmlInit()
xml:ParseDirFile("ui\\textures_descr", file_name)
xml:NavigateToNode("w", 0)
local file_count = xml:GetNodesNum("", 0, "file")
for i=0, file_count-1 do
xml:NavigateToNode("file", i)
local texture_count = xml:GetNodesNum("file", i, "texture")
for y=0, texture_count-1 do
local texture_descr_id = xml:ReadAttribute("texture", y, "id")
if string.find(texture_descr_id, pattern) then
table.insert(matches, texture_descr_id)
end
end
xml:NavigateToRoot()
xml:NavigateToNode("w", 0)
end
end
profiler:stop()
this.dbg_printf("[WG] Utils | Found %s matching texture descriptions for %s in %sms :\n%s", size_table(matches), pattern, profiler:time()/1000, utils_data.print_table(matches, false, true))
return matches
end
-- ---------------------------------------------------------------------------------------------------------------------
-- Objects Functions
-- ---------------------------------------------------------------------------------------------------------------------
--- Function used to get the current renderer used by the game.
--- @return "dx8"|"dx9"|"dx10"|"dx11"|
function get_renderer()
local renderers = {
["renderer_r4"] = "dx11",
["renderer_r3"] = "dx10",
["renderer_r2a"] = "dx9",
["renderer_r2.5"] = "dx9",
["renderer_r1"] = "dx8",
}
return renderers[get_console_cmd(0,"renderer")]
end
-- ---------------------------------------------------------------------------------------------------------------------
-- Squads Functions
-- ---------------------------------------------------------------------------------------------------------------------
--- Function used to spawn a story squad.
--- @param sec string
--- @param pos vector
--- @param smart cse_alife_smart_zone
--- @return cse_alife_online_offline_group
function spawn_story_squad(sec, pos, smart)
if not validate_params({sec,smart,"spawn_story_squad"}) then return end
-- Make sure the squad isn't already spawned in
local se_squad = this.server_object_by_sid(sec)
if se_squad then
printf("![WG] ERROR | Utils | Squad already exists - '%s'", se_squad:section_name())
return se_squad
end
-- Default value
pos = pos or smart.position
-- Spawn squad on the appropriate smart terrain
se_squad = spawn_squad(sec,pos,smart.m_level_vertex_id,smart.m_game_vertex_id, smart)
if se_squad then
-- Force the squad to stay there
se_squad.scripted_target = smart:name()
dbg_printf("[WG] Utils | Story squad %s(%s) created at %s", sec, se_squad.id, smart:name())
return se_squad
else
printf("![WG] ERROR | Utils | Failed to create squad (%s)",sec)
return
end
end
--- Function used to spawn a simulation squad, at a given point in space.
--- @param sec string
--- @param pos vector
--- @param lvid number
--- @param gvid number
--- @param smart cse_alife_smart_zone
--- @return cse_alife_online_offline_group
function spawn_squad(sec, pos, lvid, gvid, smart)
if not validate_params({sec,pos,lvid,gvid,"spawn_squad"}) then return end
local squad = alife_create(sec, pos, lvid, gvid)
if squad then
squad:create_npc(smart, pos, lvid, gvid)
if smart then
SIMBOARD:assign_squad_to_smart(squad, smart.id)
else
SIMBOARD:assign_squad_to_smart(squad)
end
for k in squad:squad_members() do
local se_obj = k.object or k.id and alife_object(k.id)
if (se_obj) then
SIMBOARD:setup_squad_and_group(se_obj)
SendScriptCallback("squad_on_npc_creation",squad,se_obj,smart)
end
end
dbg_printf("[WG] Utils | Squad with id %s created", squad.id)
return squad
else
printf("![WG] ERROR | Utils | Failed to create squad (%s)",sec)
return
end
end
--- Function used to spawn a simulation squad, at a given smart terrain.
--- @param sec string
--- @param smart_name string
--- @return cse_alife_online_offline_group
function spawn_squad_smart(sec, smart_name)
if not validate_params({sec, smart_name,"spawn_squad_smart"}) then return end
local squad = SIMBOARD:create_squad(SIMBOARD.smarts_by_names[smart_name],sec)
if squad then
dbg_printf("[WG] Utils | Squad with id %s created", squad.id)
return squad
else
printf("![WG] ERROR | Utils | Failed to create squad (%s)",sec)
return
end
end
--- Function used to spawn a dead squad, at a given smart terrain.
--- @param sec string
--- @param smart_name string
--- @return number
function spawn_dead_squad(sec, smart_name)
if not validate_params({sec,smart_name,"spawn_dead_squad"}) then return end
local squad = spawn_squad_smart(sec, smart_name)
if squad then
local member_id = nil
for npc in squad:squad_members() do
CreateTimeEvent("western_goods_delay_kill_squad",npc.id,1,surge_manager.make_dead,npc.id)
member_id = npc.id
end
dbg_printf("[WG] Utils | Squad with id %s killed", squad.id)
return member_id
else
printf("![WG] ERROR | Utils | Failed to create dead squad (%s)",sec)
return
end
end
--- Function used to get the ID from a random member of a squad.
--- @param squad cse_alife_online_offline_group
--- @return number
function get_member_id_from_squad(squad)
if not validate_params({squad,"get_member_id_from_squad"}) then return end
for member in squad:squad_members() do
return member.id
end
end
--- Function used to get a "random" member of a squad.
--- @param squad cse_alife_online_offline_group
--- @return cse_alife_object
function get_member_from_squad(squad)
if not validate_params({squad,"get_member_from_squad"}) then return end
for member in squad:squad_members() do
return alife_object(member.id)
end
end
--- Function used to find an NPC by its section name in the player squad.
--- Warning : if multiple NPCs with that section exist, it'll only return the first one it finds.
--- @param sec string
--- @return cse_alife_object
function get_member_from_actor_squad(sec)
if not validate_params({sec,"get_member_from_actor_squad"}) then return end
local actor_squad = axr_companions.list_actor_squad_by_id()
for _,id in pairs(actor_squad) do
local se_npc = alife_object(id)
if se_npc and se_npc:section_name() == sec then
return se_npc
end
end
end
--- Function used to check if a given object id is a member of a given squad.
--- @param squad cse_alife_online_offline_group
--- @param id number
--- @return boolean
function is_id_from_squad(squad, id)
if not validate_params({squad,id,"is_id_from_squad"}) then return end
for member in squad:squad_members() do
if member.id == id then
return true
end
end
return false
end
--- Function used to iterate through and execute a function on each member of a squad.
--- @param squad cse_alife_online_offline_group
--- @param func function
--- @return nil
function squad_iterate_members(squad, func, ...)
if not validate_params({squad,func,"squad_iterate_members"}) then return end
local args = {...}
for member in squad:squad_members() do
local se_obj = alife_object(member.id)
if (se_obj) then
func(se_obj, unpack(args))
end
end
end
--- Function used to get the squad of an object.
--- Unlike the global 'get_object_squad', this function checks if the passed object is the actor.
--- Doing so will kill the script engine thread, and this function ensures this never happens.
--- @param obj game_object
--- @return cse_alife_online_offline_group
function get_squad_of(obj)
if (not validate_params({obj,"get_squad_of"})) then
return
end
-- Calling get_object_squad() or actor object grounds the game !
if (obj:id() == AC_ID) then
return
end
-- Maybe don't call 'get_squad_of' on a door or something
if not (IsStalker(obj) or IsMonster(obj)) then
printf("~[WG] WARNING | Utils | Aborting, trying to get the squad of an object that cannot be in a squad (obj : '%s')", obj and obj:name())
return
end
local squad = get_object_squad(obj)
if not squad then
printf("~[WG] WARNING | Utils | Object '%s' has no squad, this will probably crash the game eventually since stalkers/mutants MUST be in squads !", obj and obj:name())
return
end
return squad
end
-- ---------------------------------------------------------------------------------------------------------------------
-- Bone Functions
-- ---------------------------------------------------------------------------------------------------------------------
--- Function used to get the position of a bone by its name.
--- This function should be used in case the bone is from a world model.
--- @author Thial
--- @param obj game_object
--- @param bone string
--- @return vector
function bone_position(obj, bone)
if not validate_params({obj,bone,"bone_position"}) then return end
return obj:bone_position(obj:get_bone_id(bone, false), false)
end
--- Function used to get the position of a bone by its name.
--- This function should be used in case the bone is from a hud model.
--- @param obj game_object
--- @param hud_bone string
--- @param bone string
--- @return vector
function bone_hud_position(obj, hud_bone, bone)
if not validate_params({obj,hud_bone,bone,"bone_hud_position"}) then return end
-- Cant find hud bone in TPS, use default bone
if level.get_active_cam() ~= 0 then
printf("~[WG] WARNING | Utils | Trying to get HUD bone '%s' position in third person ! Fallback to '%s'", hud_bone, bone)
return this.bone_position(obj, bone)
end
return obj:bone_position(obj:get_bone_id(hud_bone, true), true)
end
--- Function used to set the visibility a bone off a game object.
--- This function can be used as a getter or as a setter.
--- This function should be used in case the bone is from a world model.
--- @param obj game_object
--- @param bone string
--- @param visibility boolean
--- @return nil
function bone_visibility(obj, bone, visibility)
if not validate_params({obj,bone,"bone_visibility"}) then return end
if visibility == nil then
return obj:bone_visible(bone, false)
end
obj:set_bone_visible(bone, visibility, true, false)
end
--- Function used to set the visibility a bone off a game object.
--- This function can be used as a getter or as a setter.
--- This function should be used in case the bone is from a hud model.
--- @param obj game_object
--- @param hud_bone string
--- @param bone string
--- @param visibility boolean
--- @return nil
function bone_hud_visibility(obj, hud_bone, bone, visibility)
if not validate_params({obj,hud_bone,bone,"bone_hud_visibility"}) then return end
-- Cant find hud bone in TPS, use default bone
if level.get_active_cam() ~= 0 then
printf("~[WG] WARNING | Utils | Trying to set HUD bone '%s' visibility in third person ! Fallback to '%s'", hud_bone, bone)
return this.bone_visibility(obj, bone, visibility)
end
if visibility == nil then
return obj:bone_visible(hud_bone, true)
end
obj:set_bone_visible(hud_bone, visibility, true, true)
end
-- ---------------------------------------------------------------------------------------------------------------------
-- Validation Functions
-- ---------------------------------------------------------------------------------------------------------------------
--- Function used to check if all necessary parameters were correctly passed to a function.
--- Last element of the table has to be the name of the function calling validate_params.
--- Use like this : 'if not validate_params({param_1,param_1,"my_function"}) then return end'
--- @param params table
--- @return boolean
function validate_params(params)
local index = 1
for i,_ in pairs(params) do
if i ~= index then
printf("![WG] ERROR | Utils | Missing argument no %s for '%s()'!",index,params[#params])
return false
end
index = index + 1
end
return true
end
--- Function used to check if an object is a type of PDA device.
--- @param obj game_object
--- @return boolean
function validate_is_pda(obj)
if not validate_params({obj,"validate_is_pda"}) then return end
local pda_sections = {
["device_pda_1"] = true,
["device_pda_2"] = true,
["device_pda_3"] = true,
["device_pda_milspec"] = true
}
return pda_sections[obj:section()]
end
-- ---------------------------------------------------------------------------------------------------------------------
-- Other Utils Functions
-- ---------------------------------------------------------------------------------------------------------------------
--- Function used to iterate through the inventory of a game object.
--- The function passed in arguments will be called once per game object inside of the inventory.
--- Extra arguments passed to 'inventory_iter' function are passed on to 'func' function.
--- If 'func' function returns true, then the iteration stops.
--- @param who game_object
--- @param func function
--- @param ... table
--- @return nil
function inventory_iter(who ,func, ...)
if not validate_params({who,func,"inventory_iter"}) then return end
dbg_printf("[WG] Utils | Iterating inventory of '%s'",who:section())
local args = {...}
who:iterate_inventory(function(owner, obj)
return func(owner, obj, unpack(args))
end,who)
end
--- Function used to find an NPC by its section name in the player squad.
--- @author mr_demonized
--- @param func function
--- @param ... table
--- @return nil
function next_tick(func, ...)
if not validate_params({func,"next_tick"}) then return end
local args = {...}
AddUniqueCall(function()
func(unpack(args))
return true
end)
end
--- Function used to sperate an artefact from its container.
--- This function is a copy of itms_manager.use_arty_container(), where the anim is optional.
--- @author Alundaio,Tronex
--- @param obj game_object
--- @param play_anim boolean
--- @return nil
function open_container(obj, play_anim)
if not validate_params({obj,"open_container"}) then return end
local break_con
local break_arty
local sec = obj:section()
if (string.find(sec, "(lead.-_box)",3)) then
break_con = "lead_box"
break_arty = sec:gsub("_lead_box", "")
elseif (string.find(sec, "(af.-_iam)",3)) then
break_con = "af_iam"
break_arty = sec:gsub("_af_iam", "")
elseif (string.find(sec, "(af.-_aac)",3)) then
break_con = "af_aac"
break_arty = sec:gsub("_af_aac", "")
elseif (string.find(sec, "(af.-_aam)",3)) then
break_con = "af_aam"
break_arty = sec:gsub("_af_aam", "")
end
if break_con and break_arty and ini_sys:section_exist(break_con) and ini_sys:section_exist(break_arty) then
local cond = obj:condition()
-- Hack to prevent Artefacts Containers exploit
-- (gaining rank by receiving artefacts)
_G.ARTY_FROM_CONT = true
if play_anim == nil or play_anim == true then
actor_effects.play_item_fx(break_con .. "_dummy")
end
alife_create_item(break_con, db.actor)
alife_create_item(break_arty, db.actor, { cond = cond } )
alife_release(obj)
end
end
--- Function used to check if there are NPCs currently in a fight with the player.
--- @return boolean
function is_player_fighting()
return not is_empty(xr_combat_ignore.fighting_with_actor_npcs)
end
--- Function used to get the real community of the NPC by checking spawn id.
--- @author HarukaSai
--- @param npc game_object
--- @param default string
--- @return string
function get_real_community(npc, default)
if not validate_params({npc,"get_real_community"}) then return end
local furniture = {
["esc_m_trader"] = true,
["red_m_lesnik"] = true
}
local blacklisted_comms = {
["trader"] = true,
["monster"] = true
}
if furniture[npc:name()] then
return "stalker"
end
local community = character_community(npc)
if not blacklisted_comms[community] then
return community
end
local squad = this.get_squad_of(npc)
local squad_community = squad and squad:get_squad_community()
if not squad_community or not blacklisted_comms[squad_community] then
return squad_community
else
return default
end
end
--- Function used to get the price of a item (or multiple) according to progression difficulty.
--- The price is the estimated price when the player buys an item from a trader.
--- Original author is RavenAscendant. Function was edited by NLTP_ASHES.
--- @author RavenAscendant
--- @param section string
--- @param count number
--- @param default number
--- @return number
function get_section_price(section, count, default)
if not validate_params({section,"get_section_price"}) then return end
-- Default values
count = count or 1
default = default or 0
local condlist = ini_trade and ini_trade:r_string_to_condlist("trader","discounts")
local sect = condlist and xr_logic.pick_section_from_condlist(db.actor, nil, condlist)
if sect == nil or sect == "" then
return default
end
local cost = SYS_GetParam(2, section, "cost", 0)
local factor = ini_trade:r_float_ex(sect,"sell") or 1
local eco_factor = game_difficulties.get_eco_factor("sell") or 1
local discount = factor * eco_factor
return (cost * discount) * count
end