Another basic lua query
Moderator: Forum Moderators
- Spannerbag
- Posts: 759
- Joined: December 18th, 2016, 6:14 pm
- Location: Yes
Another basic lua query
Hi,
Still playing with the forest animals micro ai and am rather lost after some progress.
The following test setup was merely to check I was capturing correct data and it sent me down a rabbit hole.
Yes, it is basically
Here though I have a couple of issues.
First, the code:
WML:
lua:
Using two types of
Output: - - -
Issue #1
The
(Every unit on the map is returned.)
I've read various code examples but I've struggled to follow the logic as it flows through various files.
When an entire tag contains just a filter things work, as in:
So I'm guessing there's something wrong with my using
Issue #2
If I enable the WML array assignment
(Especially as in the working code I built a simple array from scratch.)
I have various speculations on what might be wrong but I'd rather ask someone who actually knows something about lua.
I did look for the code for
Any pointers on either or both these issues would be greatly appreciated.
Cheers!
-- Spannerbag
Still playing with the forest animals micro ai and am rather lost after some progress.
The following test setup was merely to check I was capturing correct data and it sent me down a rabbit hole.
Yes, it is basically
[store_unit]
and I have a cutdown version that works. 
Here though I have a couple of issues.
First, the code:
WML:
Code: Select all
[event]
name=side 1 turn 1
{GENERIC_UNIT 1 Mage 4 4}
[ftest]
[filter]
side=1
canrecruit=yes
[/filter]
[/ftest]
Code: Select all
--- Parse filter and return units in array "units"
function wesnoth.wml_actions.ftest(cfg)
wml.array_variables.ftest = {}
local units = {}
local unitsm = {}
wesnoth.interface.add_chat_message(string.format("Length 'units' is %d.", #units))
local units = wesnoth.units.find_on_map(cfg.filter)
local unitsm = wesnoth.units.find(cfg.filter)
wesnoth.interface.add_chat_message(string.format("Length 'units' is %d and 'unitsm' is %d.", #units, #unitsm))
wesnoth.interface.add_chat_message(string.format("'units[1,2,3].id' = %s,%s,%s.", units[1].id, units[2].id, units[3].id))
wesnoth.interface.add_chat_message(string.format("'unitsm[1,2,3].id' = %s,%s,%s.", unitsm[1].id, unitsm[2].id, unitsm[3].id))
-- wml.array_variables.ftest = units
end
units.find
just to make this code use the same logic as the working code example below.Output: - - -
Issue #1
The
[filter]
contents are ignored?(Every unit on the map is returned.)
I've read various code examples but I've struggled to follow the logic as it flows through various files.
When an entire tag contains just a filter things work, as in:
Code: Select all
--- If unit(s) found, assumes all are valid
function wesnoth.wml_actions.get_uxyid(cfg)
local guxyid = wesnoth.units.find(cfg)
local gu = {}
wml.array_variables.gu = {}
if guxyid then
for index, unit in ipairs(guxyid) do
if unit.valid == "map" then
gu[index] = {x=unit.x,y=unit.y,id=unit.id}
elseif unit.valid == "recall" then
gu[index] = {x="recall",y="recall",id=unit.id}
end
wml.array_variables.gu = gu
end
end
end
cfg.filter
?Issue #2
If I enable the WML array assignment
wml.array_variables.ftest = units
I get an error:
That last line assigning a WML variable is disabled, it complains and I'm guessing the lua table isn't compatible with this assignment.(Especially as in the working code I built a simple array from scratch.)
I have various speculations on what might be wrong but I'd rather ask someone who actually knows something about lua.

I did look for the code for
[store_unit]
but couldn't find it - if I've missed it, please let me know where it's located.Any pointers on either or both these issues would be greatly appreciated.
Cheers!
-- Spannerbag
- Celtic_Minstrel
- Developer
- Posts: 2371
- Joined: August 3rd, 2012, 11:26 pm
- Location: Canada
- Contact:
Re: Another basic lua query
--1--
When you write
But the WML you've written is like the following:
So to get that in Lua, you use
--2--
You seem to have left out the actual error message, but it's fairly obvious what's wrong here. When assigning to
Assuming the tag is implemented in Lua, you should be able to find a function called
When you write
config.filter
, you're expecting WML like the following:Code: Select all
[ftest]
filter=something
[/ftest]
Code: Select all
[ftest]
[filter]
id=whatever
[/filter]
[/ftest]
wml.get_child('filter')
. See here for more info.--2--
You seem to have left out the actual error message, but it's fairly obvious what's wrong here. When assigning to
wml.array_variables.ftest
, the right-hand side must be an array of WML tables. However, you've assigned an array of units instead. You can convert an array of units to an array of WML tables representing the units with the following code:Code: Select all
for i = 1, #units do
units[i] = units[i].__cfg
end
The code for most ActionWML tags is located either in data/lua/wml-tags.lua or one of the files in data/lua/wml/. A few are located in other places – data/lua/wml-flow.lua or even in the C++ source code in game_events/action_wml.cpp.Spannerbag wrote: ↑May 2nd, 2025, 11:57 am I did look for the code for[store_unit]
but couldn't find it - if I've missed it, please let me know where it's located.
Assuming the tag is implemented in Lua, you should be able to find a function called
wml_actions.tag_name
in one of the above files. I believe [store_unit]
is in wml-tags.lua.- Spannerbag
- Posts: 759
- Joined: December 18th, 2016, 6:14 pm
- Location: Yes
Re: Another basic lua query
Thanks ever so much for the comprehensive explanation, really really helpful.
I might get fairly good at lua - in a few hundred years


Thanks again,
cheers!
-- Spannerbag
- Spannerbag
- Posts: 759
- Joined: December 18th, 2016, 6:14 pm
- Location: Yes
Re: Another basic lua query
Hi again,
Got everything working, no problems.
Just curious about a couple of things?
).
Hope this all makes sense!
Cheers!
-- Spanner bag
Got everything working, no problems.
Just curious about a couple of things?
- I'm assuming
Code: Select all
for i = 1, #units do units[i] = units[i].__cfg end
__cfg
is a metamethod?
Just intested in what changes this makes?
Don't need detailed breakdown (but happy to read if you do provide this) just a summary of the nature of the changes will be fine.
- Re.
filter
assignment:
local filter = wml.get_child(cfg,"filter") or wml.error "[ftest] missing required [filter] tag"
During debug wanted to checkfilter
.
Type wasvconfig
notstring
?
Again, just out of curiosity, I see there is a wml.tovconfig.
Is there a converse method to extract a string from (whatever flavour of) vconfigfilter
contained?
(Assuming this is possible.)

Hope this all makes sense!
Cheers!
-- Spanner bag
Re: Another basic lua query
1. It replaces each element in variable units with __cfg property of its original value.
2. For string format you have wml.tostring.
2. For string format you have wml.tostring.
- Celtic_Minstrel
- Developer
- Posts: 2371
- Joined: August 3rd, 2012, 11:26 pm
- Location: Canada
- Contact:
Re: Another basic lua query
The word "metamethod" is not a correct descriptor for
__cfg
. As for what the code does, Ravana summarized the logic of the assignment, and the __cfg
call is basically equivalent to [store_unit]
– that is, it converts the unit to WML.- Spannerbag
- Posts: 759
- Joined: December 18th, 2016, 6:14 pm
- Location: Yes
Re: Another basic lua query
Many thanks for replying, will remember wml.tostring!
Thanks for clarifying what "__cfg" means/does, if it isn't a metamethod, what is the correct term out of interest please?Celtic_Minstrel wrote: ↑May 3rd, 2025, 4:46 pm The word "metamethod" is not a correct descriptor for__cfg
. As for what the code does, Ravana summarized the logic of the assignment, and the__cfg
call is basically equivalent to[store_unit]
– that is, it converts the unit to WML.
I didn't express my lack of understanding very well.

I am unfamiliar with the "__" notation; I gather that "__literal" means (I believe) "interpret this entity literally without processing special characters"?
So by implication "__cfg" presumably means "reformat entity data to align with WML format"?
When I first saw your code I kinda gathered that
__cgf
reformatted data (from ??? to WML) but had no idea what the original format was but that doesn't matter; I was just curious.Again, thanks to both of you for your help and time, very much appreciated.
Cheers!
-- Spannerbag
- Celtic_Minstrel
- Developer
- Posts: 2371
- Joined: August 3rd, 2012, 11:26 pm
- Location: Canada
- Contact:
Re: Another basic lua query
The "__" isn't really a notation, it's just part of the name of something. I think we usually add "__" to the beginning of names that represent something other than "something that is part of this object". So, for example, if you have a vconfig, most names (like
cfg.x
or cfg.id
) will be a key in that vconfig, but "__literal" is not a key – it's a special value. Similarly, if you have a unit, most names (like unit.name
or unit.hitpoints
) will be some attribute of that unit, but "__cfg" is not an attribute of the unit – it's a conversion. I don't think we have a general term to refer to such things, though. You could use the word "property", but that would describe any name found in the object, not just the special ones beginning with "__".The original format is basically just "a unit", or if you want, "a unit userdata". It's essentially an "opaque" format that we define in the engine to represent a unit. (Opaque means you aren't able to manually inspect it in code, which also means you can't do things like writing it to a file or reading it to a file.)Spannerbag wrote: ↑May 4th, 2025, 9:06 am When I first saw your code I kinda gathered that__cgf
reformatted data (from ??? to WML) but had no idea what the original format was but that doesn't matter; I was just curious.
- Spannerbag
- Posts: 759
- Joined: December 18th, 2016, 6:14 pm
- Location: Yes
Re: Another basic lua query
Ooops , forgot to thank you for your post.

Belated thanks for your informative reply.

Cheers!
-- Spannerbag
- Spannerbag
- Posts: 759
- Joined: December 18th, 2016, 6:14 pm
- Location: Yes
Re: Another basic lua query: location set
Hi,
Finally got a bit of time to work on this a bit further, made some progress but still loads to do.
I'm wanting to generate a random move but am unclear as to whether or not this can be done directly from a location set rather than iterating through it first to generate (I think) an array (or table) of x,y values.
Also changed the names of the units from
Here's the setup code:
Not able to actually test this yet but hopefully should work.
Can I (easily) extract a random location from
(I couldn't find anything definitive in the wiki, apologies if I missed it.)
Many thanks in advance for your time and trouble.
Cheers!
-- Spannerbag
Finally got a bit of time to work on this a bit further, made some progress but still loads to do.
I'm wanting to generate a random move but am unclear as to whether or not this can be done directly from a location set rather than iterating through it first to generate (I think) an array (or table) of x,y values.
Also changed the names of the units from
parent
and child
to wanderer
and follower
to avoid function name clashes. 
Here's the setup code:
Code: Select all
function ca_wanderers_move:execution(cfg)
local unit = get_wanderers(cfg)[1] or ((not all_wanderers[1]) and get_followers(cfg)[1]) -- Move wanderers randomly or (if no wanderers then move followers if any)
local avoid_locs = AH.get_avoid_map(ai, nil, true) -- [avoid]ed locations, if any
local reach_locs = AH.get_reachmap(unit, { avoid_map = avoid_locs, exclude_occupied = true }) -- Unoccupied hexes this unit can reach, honouring [avoid] if set
Can I (easily) extract a random location from
reach_locs
or do I need to:- Strip out border hexes (doubt it but thought I'd best ask)?
- Use
:iter
to build an x,y table?
(I couldn't find anything definitive in the wiki, apologies if I missed it.)
Many thanks in advance for your time and trouble.
Cheers!
-- Spannerbag
Re: Another basic lua query: location set
Did you try location_set.random ?
- Spannerbag
- Posts: 759
- Joined: December 18th, 2016, 6:14 pm
- Location: Yes
Re: Another basic lua query: location set
Aaarghh... looked through that page... guess that as it was the very last entry I missed it.

Thanks!
I guess the actual code to generate a random location from a location set named
reach_locs
would be something like: local rand_x,rand_y = location_set.random(reach_locs)
The wiki doesn't give an example so I'd like to check syntax.
(Doesn't seem to be used in any
.lua
files the BfW directory tree nor did I find an example in local UMC on my PC hence this question.)Also, would still - out of curiosity - appreciate any insight into the internal structure of a location set if anyone knows...?
Thanks again gnombat for pointing this useful function out to me, saved me a lot of hassle.
Cheers!
-- Spannerbag
Re: Another basic lua query: location set
There is an example in data/ai/micro_ais/cas/ca_herding_sheep_move.luaSpannerbag wrote: ↑June 10th, 2025, 8:09 am I guess the actual code to generate a random location from a location set namedreach_locs
would be something like:
local rand_x,rand_y = location_set.random(reach_locs)
The wiki doesn't give an example so I'd like to check syntax.
(Doesn't seem to be used in any.lua
files the BfW directory tree nor did I find an example in local UMC on my PC hence this question.)
- Celtic_Minstrel
- Developer
- Posts: 2371
- Joined: August 3rd, 2012, 11:26 pm
- Location: Canada
- Contact:
Re: Another basic lua query: location set
That should work, but you can shorten it a bit t
local rand_x,rand_y = reach_locs:random()
.It's not all that complicated. It maps from locations to values, by converting the location to a numeric key in a Lua table.Spannerbag wrote: ↑June 10th, 2025, 8:09 amAlso, would still - out of curiosity - appreciate any insight into the internal structure of a location set if anyone knows...?