Difference between revisions of "LuaWML/Variables"

From The Battle for Wesnoth Wiki
(Document wml_matches_filter)
(Syntax highlighting, plus some spelling and grammar fixes)
Line 7: Line 7:
 
Loads a WML variable with the given qualified name (argument 1) and converts it into a Lua object. Returns ''nil'' if the name does not point to anything, a scalar for a WML attribute, and a table for a WML object. The format of the table is described in [[LuaWML#Encoding WML objects into Lua tables]].
 
Loads a WML variable with the given qualified name (argument 1) and converts it into a Lua object. Returns ''nil'' if the name does not point to anything, a scalar for a WML attribute, and a table for a WML object. The format of the table is described in [[LuaWML#Encoding WML objects into Lua tables]].
  
wesnoth.fire("store_unit", { variable="my_unit", { "filter", { id="hero" } } })
+
<syntaxhighlight lang=lua>
local heros_hp = wesnoth.get_variable("my_unit[0].hitpoints")
+
wesnoth.fire("store_unit", { variable="my_unit", { "filter", { id="hero" } } })
wesnoth.message(string.format("The 'hero' unit has %d hitpoints.", heros_hp))
+
local heros_hp = wesnoth.get_variable("my_unit[0].hitpoints")
 +
wesnoth.message(string.format("The 'hero' unit has %d hitpoints.", heros_hp))
 +
</syntaxhighlight>
  
 
Argument 2, if ''true'', prevents the recursive conversion when the name points to an object; a fresh empty table is returned in this case. This is mainly used for writing proxy objects, e.g. in [[#helper.set_wml_var_metatable]].
 
Argument 2, if ''true'', prevents the recursive conversion when the name points to an object; a fresh empty table is returned in this case. This is mainly used for writing proxy objects, e.g. in [[#helper.set_wml_var_metatable]].
Line 21: Line 23:
 
Converts and stores a Lua object (argument 2) to a WML variable (argument 1). A WML object is created for a table, an attribute otherwise.
 
Converts and stores a Lua object (argument 2) to a WML variable (argument 1). A WML object is created for a table, an attribute otherwise.
  
wesnoth.set_variable("my_unit.hitpoints", heros_hp + 10)
+
<syntaxhighlight lang=lua>
 +
wesnoth.set_variable("my_unit.hitpoints", heros_hp + 10)
 +
</syntaxhighlight>
  
 
Setting a WML variable to nil erases it.
 
Setting a WML variable to nil erases it.
Line 31: Line 35:
 
{{DevFeature1.13|0}} Returns all the WML variables currently set in form of a WML table. This function accepts no arguments.
 
{{DevFeature1.13|0}} Returns all the WML variables currently set in form of a WML table. This function accepts no arguments.
  
for key, value in pairs( wesnoth.get_all_vars() ) do
+
<syntaxhighlight lang=lua>
    if type( value ) == "table" then
+
for key, value in pairs( wesnoth.get_all_vars() ) do
        print( key, value[1], value[2] )
+
    if type( value ) == "table" then
    else
+
        print( key, value[1], value[2] )
        print( key, value )
+
    else
    end
+
        print( key, value )
end
+
    end
 +
end
 +
</syntaxhighlight>
  
 
==== wesnoth.wml_matches_filter ====
 
==== wesnoth.wml_matches_filter ====
Line 51: Line 57:
 
Sets the metatable of a table so that it can be used to access WML variables. Returns the table. The fields of the tables are then proxies to the WML objects with the same names; reading/writing to them will directly access the WML variables.
 
Sets the metatable of a table so that it can be used to access WML variables. Returns the table. The fields of the tables are then proxies to the WML objects with the same names; reading/writing to them will directly access the WML variables.
  
helper.set_wml_var_metatable(_G)
+
<syntaxhighlight lang=lua>
my_persistent_variable = 42
+
helper.set_wml_var_metatable(_G)
 +
my_persistent_variable = 42
 +
</syntaxhighlight>
  
 +
It's not recommended to use helper.set_wml_var_metatable(_G) because that limits possible global variables to valid wml attributes or tables. This can have some surprising effects:
  
it's not reccomended to use helper.set_wml_var_metatable(_G) because that limits possible gobal variables to valid wml attributes or tables. This can have some surprising effects:
+
<syntaxhighlight lang=lua>
 +
c = { a= 9}
 +
d = c
 +
c.a = 8
 +
wesnoth.message(d.a) -- normally prints 8 but prints 9 with helper.set_wml_var_metatable(_G)
  
c = { a= 9}
+
local lla = { {"a", {}}}
d = c
+
lla[1][2] = lla
c.a = 8
+
la = lla -- crashes wesnoth with helper.set_wml_var_metatable(_G)
wesnoth.message(d.a) -- normaly prints 8 but prints 9 with helper.set_wml_var_metatable(_G)
 
  
local lla = { {"a", {}}}
+
helper = wesnoth.require("lua/helper.lua")
lla[1][2] = lla
+
helper.set_wml_var_metatable(_G)
la = lla -- crashes wesnoth with helper.set_wml_var_metatable(_G)
+
-- some code later (maybe in another addon)
 +
H = wesnoth.require("lua/helper.lua") -- fails because wesnoth.require("lua/helper.lua") doesn' return a valid wmltable..
  
helper = wesnoth.require("lua/helper.lua")
+
helper = wesnoth.require("lua/helper.lua")
helper.set_wml_var_metatable(_G)
+
helper.set_wml_var_metatable(_G)
-- some code later (maybe in another addon)
+
-- some code later (maybe in another addon)
H = wesnoth.require("lua/helper.lua") -- fails because wesnoth.require("lua/helper.lua") doesn' return a valid wmltable..
+
T = helper.set_wml_tag_metatable {}  -- doesn't work
 +
V = helper.set_wml_var_metatable({}) -- doesn't work
 +
</syntaxhighlight>
  
helper = wesnoth.require("lua/helper.lua")
+
Even if you don't use such code in your addon, it's still bad because other code of modifications or eras to be used with your addon might. And you'll mess up their code. This is also true for SP campaigns because it might interfere with ai code and we plan to enable modifications in SP too.
helper.set_wml_var_metatable(_G)
 
-- some code later (maybe in another addon)
 
T = helper.set_wml_tag_metatable {}  -- doesn't work
 
V = helper.set_wml_var_metatable({}) -- doesn't work
 
 
 
even if you don't use such code in your addon it's still bad because other code of modifications or eras to be used with your addon might do. And you'll mess up their code. This is also true for SP campaigns because it might interfere with ai code and we plan to enable modifications in SP too.
 
 
Instead you should use set_wml_var_metatable with another table ('V' in this example):
 
Instead you should use set_wml_var_metatable with another table ('V' in this example):
  
V = helper.set_wml_var_metatable({})
+
<syntaxhighlight lang=lua>
V.my_persistent_variable = 42
+
V = helper.set_wml_var_metatable({})
 +
V.my_persistent_variable = 42
 +
</syntaxhighlight>
  
 
==== helper.get_child ====
 
==== helper.get_child ====
Line 89: Line 100:
 
Returns the first sub-tag of a WML object with the given name.
 
Returns the first sub-tag of a WML object with the given name.
  
local u = wesnoth.get_units({ id = "Delfador" })[1]
+
<syntaxhighlight lang=lua>
local costs = helper.get_child(u.__cfg, "movement_costs")
+
local u = wesnoth.get_units({ id = "Delfador" })[1]
wesnoth.message(string.format("Delfador needs %d points to move through a forest.", costs.forest))
+
local costs = helper.get_child(u.__cfg, "movement_costs")
 +
wesnoth.message(string.format("Delfador needs %d points to move through a forest.", costs.forest))
 +
</syntaxhighlight>
  
 
If a third parameter is passed, only children having a ''id'' attribute equal to it are considered.
 
If a third parameter is passed, only children having a ''id'' attribute equal to it are considered.
Line 117: Line 130:
 
Returns an iterator over all the sub-tags of a WML object with the given name.
 
Returns an iterator over all the sub-tags of a WML object with the given name.
  
local u = wesnoth.get_units({ id = "Delfador" })[1]
+
<syntaxhighlight lang=lua>
for att in helper.child_range(u.__cfg, "attack") do
+
local u = wesnoth.get_units({ id = "Delfador" })[1]
    wesnoth.message(tostring(att.description))
+
for att in helper.child_range(u.__cfg, "attack") do
end
+
    wesnoth.message(tostring(att.description))
 +
end
 +
</syntaxhighlight>
  
 
==== helper.child_array ====
 
==== helper.child_array ====
Line 137: Line 152:
 
Fetches all the WML container variables with given name and returns a table containing them (starting at index 1). The context specifies where to get variables from. You can pass either a unit or a side as the context in order to get an array from the unit variables or side variables, respectively.
 
Fetches all the WML container variables with given name and returns a table containing them (starting at index 1). The context specifies where to get variables from. You can pass either a unit or a side as the context in order to get an array from the unit variables or side variables, respectively.
  
function get_recall_list(side)
+
<syntaxhighlight lang=lua>
    wesnoth.fire("store_unit", { x = "recall", variable = "LUA_recall_list })
+
function get_recall_list(side)
    local l = get_variable_array "LUA_recall_list"
+
    wesnoth.fire("store_unit", { x = "recall", variable = "LUA_recall_list })
    wesnoth.set_variable "LUA_recall_list"
+
    local l = get_variable_array "LUA_recall_list"
    return l
+
    wesnoth.set_variable "LUA_recall_list"
end
+
    return l
 +
end
 +
</syntaxhighlight>
  
 
==== helper.get_variable_proxy_array ====
 
==== helper.get_variable_proxy_array ====
Line 157: Line 174:
 
Creates WML container variables with given name from given table. The context specifies where to put the variables. You can pass either a unit or a side as the context in order to set an array in the unit variables or side variables, respectively.
 
Creates WML container variables with given name from given table. The context specifies where to put the variables. You can pass either a unit or a side as the context in order to set an array in the unit variables or side variables, respectively.
  
helper.set_variable_array("target", { {t=t1}, {t=t2}, {t=t3} })
+
<syntaxhighlight lang=lua>
-- target[0].t <- t1; target[1].t <- t2; target[2].t <- t3
+
helper.set_variable_array("target", { {t=t1}, {t=t2}, {t=t3} })
 +
-- target[0].t <- t1; target[1].t <- t2; target[2].t <- t3
 +
</syntaxhighlight>
  
 
[[Category: Lua Reference]]
 
[[Category: Lua Reference]]

Revision as of 05:48, 18 March 2018

This page describes the LuaWML functions and helpers for handling WML variables and containers.

wesnoth.get_variable

  • wesnoth.get_variable(var_name)

Loads a WML variable with the given qualified name (argument 1) and converts it into a Lua object. Returns nil if the name does not point to anything, a scalar for a WML attribute, and a table for a WML object. The format of the table is described in LuaWML#Encoding WML objects into Lua tables.

wesnoth.fire("store_unit", { variable="my_unit", { "filter", { id="hero" } } })
local heros_hp = wesnoth.get_variable("my_unit[0].hitpoints")
wesnoth.message(string.format("The 'hero' unit has %d hitpoints.", heros_hp))

Argument 2, if true, prevents the recursive conversion when the name points to an object; a fresh empty table is returned in this case. This is mainly used for writing proxy objects, e.g. in #helper.set_wml_var_metatable.

Note that, if the variable name happens to designate a sequence of WML objects, only the first one (index 0) is fetched. If all the WML objects with this name should have been returned, use #helper.get_variable_array instead.

wesnoth.set_variable

  • wesnoth.set_variable(var_name, value)

Converts and stores a Lua object (argument 2) to a WML variable (argument 1). A WML object is created for a table, an attribute otherwise.

wesnoth.set_variable("my_unit.hitpoints", heros_hp + 10)

Setting a WML variable to nil erases it.

wesnoth.get_all_vars

  • wesnoth.get_all_vars()

(Version 1.13.0 and later only) Returns all the WML variables currently set in form of a WML table. This function accepts no arguments.

for key, value in pairs( wesnoth.get_all_vars() ) do
    if type( value ) == "table" then
        print( key, value[1], value[2] )
    else
        print( key, value )
    end
end

wesnoth.wml_matches_filter

  • wesnoth.wml_matches_filter(config, filter)

Test if a config matches a WML filter (as [filter_wml]).

helper.set_wml_var_metatable

  • helper.set_wml_var_metatable{}

Sets the metatable of a table so that it can be used to access WML variables. Returns the table. The fields of the tables are then proxies to the WML objects with the same names; reading/writing to them will directly access the WML variables.

helper.set_wml_var_metatable(_G)
my_persistent_variable = 42

It's not recommended to use helper.set_wml_var_metatable(_G) because that limits possible global variables to valid wml attributes or tables. This can have some surprising effects:

c = { a= 9}
d = c
c.a = 8
wesnoth.message(d.a) -- normally prints 8 but prints 9 with helper.set_wml_var_metatable(_G)

local lla = { {"a", {}}}
lla[1][2] = lla
la = lla -- crashes wesnoth with helper.set_wml_var_metatable(_G)

helper = wesnoth.require("lua/helper.lua")
helper.set_wml_var_metatable(_G)
-- some code later (maybe in another addon)
H = wesnoth.require("lua/helper.lua") -- fails because wesnoth.require("lua/helper.lua") doesn' return a valid wmltable..

helper = wesnoth.require("lua/helper.lua")
helper.set_wml_var_metatable(_G)
-- some code later (maybe in another addon)
T = helper.set_wml_tag_metatable {}  -- doesn't work
V = helper.set_wml_var_metatable({}) -- doesn't work

Even if you don't use such code in your addon, it's still bad because other code of modifications or eras to be used with your addon might. And you'll mess up their code. This is also true for SP campaigns because it might interfere with ai code and we plan to enable modifications in SP too. Instead you should use set_wml_var_metatable with another table ('V' in this example):

V = helper.set_wml_var_metatable({})
V.my_persistent_variable = 42

helper.get_child

  • helper.get_child(config, child_tag_name)

Returns the first sub-tag of a WML object with the given name.

local u = wesnoth.get_units({ id = "Delfador" })[1]
local costs = helper.get_child(u.__cfg, "movement_costs")
wesnoth.message(string.format("Delfador needs %d points to move through a forest.", costs.forest))

If a third parameter is passed, only children having a id attribute equal to it are considered.

helper.get_nth_child

(Version 1.13.2 and later only)

  • helper.get_nth_child(config, child_tag_name, n)

Returns the nth sub-tag of a WML object with the given name.

helper.child_count

(Version 1.13.2 and later only)

  • helper.child_count(config, child_tag_name)

Returns the number of children in the config with the given tag name.

helper.child_range

  • helper.child_range(config, child_tag_name)

Returns an iterator over all the sub-tags of a WML object with the given name.

local u = wesnoth.get_units({ id = "Delfador" })[1]
for att in helper.child_range(u.__cfg, "attack") do
    wesnoth.message(tostring(att.description))
end

helper.child_array

(Version 1.13.2 and later only)

  • helper.child_array(config, child_tag_name)

Like helper.child_range, but returns an array instead of an iterator. Useful if you need random access to the children.

helper.get_variable_array

Fetches all the WML container variables with given name and returns a table containing them (starting at index 1). The context specifies where to get variables from. You can pass either a unit or a side as the context in order to get an array from the unit variables or side variables, respectively.

function get_recall_list(side)
    wesnoth.fire("store_unit", { x = "recall", variable = "LUA_recall_list })
    local l = get_variable_array "LUA_recall_list"
    wesnoth.set_variable "LUA_recall_list"
    return l
end

helper.get_variable_proxy_array

  • helper.get_variable_proxy_array(var_name)

Creates proxies for all the WML container variables with given name and returns a table containing them (starting at index 1). This function is similar to #helper.get_variable_array, except that the proxies can be used for modifying WML containers.

helper.set_variable_array

Creates WML container variables with given name from given table. The context specifies where to put the variables. You can pass either a unit or a side as the context in order to set an array in the unit variables or side variables, respectively.

helper.set_variable_array("target", { {t=t1}, {t=t2}, {t=t3} })
-- target[0].t <- t1; target[1].t <- t2; target[2].t <- t3