Ltx reading through script

From Mod Wiki

Jump to: navigation, search

Instead of creating more and more variables in scripts, you can use ltx files to store your variables (actually constants to be exact) and then load them in a convenient way. This article is about creating/editing ltx files and reading its contents via script.

Contents

Ltx file structure

Ltx files are actually simple text files with an INI file structure. Each file is divided into sections (unique name), sections contains pairs variables (each variable name inside one section must be unique) and values. To read certain value, you need to know which variable holds it and in which section such a variable is defined. Inheritance between sections is allowed which means you can define one base section and then derive from it. Here is a simple example of ltx file we will use in this article:

; config\my_ltx\spawn_data.ltx
 
[artefacts]
af_blood = 0
af_medusa = 0
af_vyvert = 0
af_dummy_pellicle = 0
af_fuzz_kolobok = 0
af_night_star = 0
 
[cheap_artefacts]:artefacts
af_blood = 3
af_medusa = 5
af_vyvert = 12
af_mincer_meat = 6
af_rusty_thorn = 8
 
[expensive_artefacts]:artefacts
af_fuzz_kolobok = 1
af_night_star = 2
af_electra_moonlight = 3
 
[spawn_vectors]
spawn_vector_1 = 334.4873046875, 15.932071685791, -17.644674301147, 582487, 2
spawn_vector_2 = 287.0705871582, 4.5406813621521, 108.36920166016, 556184, 145
spawn_vector_3 = 241.57223510742, 15.355321884155, 125.87966156006, 525993, 149
spawn_vector_4 = 245.78199768066, 8.2552852630615, 186.07391357422, 528854, 148
spawn_vector_5 = 174.6911315918, 10.57382774353, 155.11390686035, 477423, 150
 
[blowout]
enabled = true
show_blowout_timer = false
show_blowout_warning = true
spawn_artefacts = true
spawn_mutants = false
radiation_strength = 0.65
blowout_type = outdoor

As you can see our ltx file defines 5 sections, 2 of them inherits from section artefacts (trivial example for the sake of clarity). Also values of variables inside sections are using basic data types: numbers, boolean values, strings, however by default values are treated as string variables.

Reading ltx file from script

To read variables and values from ltx file Stalker provides class (exported to lua) called ini_file. Here are the methods of this class:

class ini_file
{
   -- constructor
   function ini_file(string)
 
   -- commonly used methods
   function section_exist(string)
   function line_exist(string, string)
   function line_count(string)
   function r_bool(string, string)
   function r_float(string, string)
   function r_string(string, string)
   function r_line(string, number, string&, string&)
 
   -- rarely used methods
   function r_clsid(string, string)
   function r_s32(string, string)
   function r_token(string, string, const token_list&)
   function r_vector(string, string)
   function r_u32(string, string)
   function r_string_wq(string, string)
}

Most of methods has two strings arguments. In that case the first argument is a section name, the second - variable name. Constructor of the ini_file class takes only one argument - path to the ltx file. The main folder where Stalker looks for ltx files is gamedata\config\ as it is defined in fsgame.ltx file (variable $game_config$). To read the ltx file, we need to create an object of ini_file class providing the path to our ltx file:

local path = "my_ltx\\spawn_data.ltx" -- gamedata\config\my_ltx\spawn_data.ltx
local ltx = ini_file(path)

Now we can access our variables using methods from ini_file class:

local ltx = ini_file("my_ltx\\spawn_data.ltx")
 
if ltx then
   -- read value of variable 'enabled' from section 'blowout'
   local is_blowout_enabled = ltx:r_bool("blowout", "enabled") -- true
 
   -- section 'blowout', variable 'radiation_strength'
   local rad_strength = ltx:r_float("blowout", "radiation_strength") -- 0.65
 
   -- section 'blowout', variable 'blowout_type'
   local blow_type = ltx:r_string("blowout", "blowout_type") -- outdoor
 
   -- number of variables in section 'spawn_vectors'
   local num_lines = ltx:line_count("spawn_vectors") -- 5
 
   -- read the 5th vector: v.x = 174.6911315918, v.y = 10.57382774353, v.z = 155.11390686035
   local v = ltx:r_vector("spawn_vectors", "spawn_vector_5")
 
   -- safe reading
   if ltx:section_exist("expensive_artefacts") then
      if ltx:line_exist("expensive_artefacts", "af_electra_moonlight") then
         local moonlights = ltx:r_string("expensive_artefacts", "af_electra_moonlight") .. "x moonlights" -- 3x moonlights
      end
   end
end

Above examples are useful if you only want to read one or two variables. If you want to read all the variables from certain section, you can use loop, for instance:

-- read the whole section, line by line
-- load variables and values to array
function read_section(ltx_path, section_name)
   local ltx = ini_file(ltx_path)
   local array = {}
 
   if not ltx then
      return array
   end
 
   if ltx:section_exist(section_name) then
      local variable, value, lines = "", "", ltx:line_count(section_name)
      for current_line = 0, lines - 1 do
         result, variable, value = ltx:r_line(section_name, current_line, "", "")
         array[variable] = value
      end
   end
 
   return array
end
 
-- function call:
local tbl = read_section("my_ltx\\spawn_data.ltx", "cheap_artefacts")
 
for artefact_name, quantity in pairs(tbl) do
   for counter = 1, quantity do
      alife():create(artefact_name, vector():set(1, 2, 3), 12345, 67890)
   end
end

Reading more complex data

read_section() function reads the given section line by line, each line is read as a string value. Our ltx file contains section spawn_vectors. As the name implies, this section holds vectors to spawn objects, for example mutants or npcs. For such objects we need the position to spawn (vector) but also level vertex id and game vertex id. We can read the section using method r_vector, but this function will return only spawn position (vector - first 3 values). However we can read the whole section using function read_section() and then parse the values:

function parse_spawn_data(str)
   local t = {}
   str = string.gsub(str, "(%a)", "")
   for value in string.gfind(str, "([%-?%d+%.%d+]+)[%p%s]?") do
      table.insert(t, tonumber(value))
   end
 
   for index = 1, #t do
      if t[index] == nil then
         return nil
      end
   end
 
   return {position = vector():set(t[1], t[2], t[3]), level_vertex = t[4], game_vertex = t[5]}
end
 
local string_table = read_section("my_ltx\\spawn_data.ltx", "spawn_vectors")
local parsed_data = {}
 
for k, v in pairs(string_table) do
   table.insert(parsed_data, parse_spawn_data(v))
end
 
local artefacts = read_section("my_ltx\\spawn_data.ltx", "cheap_artefacts")
local temp = nil
 
for artefact_name, quantity in pairs(artefacts) do
   for counter = 1, quantity do
      temp = parsed_data[math.random(1, #parsed_data)]
      alife():create(artefact_name, temp.position, temp.level_vertex, temp.game_vertex)
   end
end

Author

Team:Dez0wave

Personal tools