Feasibility of customising return guardian micro ai
Moderator: Forum Moderators
- Spannerbag
- Posts: 978
- Joined: December 18th, 2016, 6:14 pm
- Location: Yes
Feasibility of customising return guardian micro ai
Hi,
Is there a way to customise the return guardian micro ai to specify different
And, maybe, tweak the behaviour (not sure until I playtest which is a long way off
).
Here, I presume, is the relevant code:
Ideally
Is this even feasible given the various dependencies on other lua files?
Alternatively is there another/better way (other than defining multiple micro_ais) of doing this?
Any advice gratefully received!
Cheers!
Is there a way to customise the return guardian micro ai to specify different
return_x,return_y for each unit?And, maybe, tweak the behaviour (not sure until I playtest which is a long way off
Here, I presume, is the relevant code:
Code: Select all
function wesnoth.micro_ais.return_guardian(cfg)
if (cfg.action ~= 'delete') then
if (not cfg.id) and (not wml.get_child(cfg, "filter")) then
wml.error("Return Guardian [micro_ai] tag requires either id= key or [filter] tag")
end
AH.get_named_loc_xy('return', cfg, 'Return guardian [micro_ai] tag')
end
local required_keys = {}
local optional_keys = { id = 'string', filter = 'tag',
return_loc = 'string', return_x = 'integer', return_y = 'integer'
}
local CA_parms = {
ai_id = 'mai_return_guardian',
{ ca_id = 'move', location = 'ca_return_guardian.lua', score = cfg.ca_score or 100100 }
}
return required_keys, optional_keys, CA_parms
endreturn_x,return_y would be obtained from unit variables such as unit.variables.origin.x and unit.variables.origin.y.Is this even feasible given the various dependencies on other lua files?
Alternatively is there another/better way (other than defining multiple micro_ais) of doing this?
Any advice gratefully received!
Cheers!
- Lord-Knightmare
- Discord Moderator
- Posts: 2546
- Joined: May 24th, 2010, 5:26 pm
- Location: Somewhere in the depths of Irdya, gathering my army to eventually destroy the known world.
- Contact:
Re: Feasibility of customising return guardian micro ai
Yes, this is possible.to specify different return_x,return_y for each unit?
This is the way to do it.(other than defining multiple micro_ais) of doing this?
Creator of "War of Legends"
Creator of the Isle of Mists survival scenario.
Maintainer of Forward They Cried
User:Knyghtmare | My Medium
Creator of the Isle of Mists survival scenario.
Maintainer of Forward They Cried
User:Knyghtmare | My Medium
- Spannerbag
- Posts: 978
- Joined: December 18th, 2016, 6:14 pm
- Location: Yes
Re: Feasibility of customising return guardian micro ai
Great - just to be crystal clear the only code I need to change is the stuff I posted and nowhere else (i.e. there are no dependencies)?Lord-Knightmare wrote: August 30th, 2026, 4:03 pmYes, this is possible.to specify different return_x,return_y for each unit?
Trouble with multiple micro ais (mais) is that these units will be created by player action (although not player controlled) and I don't really want to limit them to a preset number of units... hmm ... will have a think. Should be possible to dynamically spawn multiple mais in WML, bit not sure if this will impact gameplay/performance if the player creates several units...Lord-Knightmare wrote: August 30th, 2026, 4:03 pmThis is the way to do it.(other than defining multiple micro_ais) of doing this?
Will consider my options.
Thanks for the reply, appreciated!
- Lord-Knightmare
- Discord Moderator
- Posts: 2546
- Joined: May 24th, 2010, 5:26 pm
- Location: Somewhere in the depths of Irdya, gathering my army to eventually destroy the known world.
- Contact:
Re: Feasibility of customising return guardian micro ai
I have seen scenarios function normally with around 120 guardian type MAI so this should be a "no issue". You can put the micro ai code in the [unit][ai] tag btw.Trouble with multiple micro ais (mais) is that these units will be created by player action (although not player controlled) and I don't really want to limit them to a preset number of units... hmm ... will have a think. Should be possible to dynamically spawn multiple mais in WML, bit not sure if this will impact gameplay/performance if the player creates several units...
Nothing is stopping you from making a customized return guardian MAI for your campaign and use that.Great - just to be crystal clear the only code I need to change is the stuff I posted and nowhere else (i.e. there are no dependencies)?
Creator of "War of Legends"
Creator of the Isle of Mists survival scenario.
Maintainer of Forward They Cried
User:Knyghtmare | My Medium
Creator of the Isle of Mists survival scenario.
Maintainer of Forward They Cried
User:Knyghtmare | My Medium
- Spannerbag
- Posts: 978
- Joined: December 18th, 2016, 6:14 pm
- Location: Yes
Re: Feasibility of customising return guardian micro ai
Thanks again for the advice, much appreciated. 
I think I'll look into multiple mais first as this seems the saner approach.
Cheers!
I think I'll look into multiple mais first as this seems the saner approach.
Cheers!
Re: Feasibility of customising return guardian micro ai
You'll probably need to create your own AI eventually anyway then?Spannerbag wrote: August 30th, 2026, 3:56 pm And, maybe, tweak the behaviour (not sure until I playtest which is a long way off).
The Micro AIs are really just some pre-defined behaviors with a limited number of tweakable parameters... I think if you really want to customize the AI beyond that, it's generally expected that you'll create your own AI with Lua.
https://wiki.wesnoth.org/Creating_Custom_AIs#Creating_Custom_Candidate_Actions
- Spannerbag
- Posts: 978
- Joined: December 18th, 2016, 6:14 pm
- Location: Yes
Re: Feasibility of customising return guardian micro ai
Thanks for the info, I have several options and am presently scoping out the complexity of each.gnombat wrote: August 30th, 2026, 7:08 pm You'll probably need to create your own AI eventually anyway then?...
Ideally I would - at present anyway - prefer to have a custom/micro ai solution as I feel this would maximise gameplay interest and enjoyment IMHO.
However I'm not sure the additional effort is worth it given I can employ other implementations that would be a lot easier/simpler if also less close to what I envisage.
I'm not great at lua but will have a poke around and see what I can totally muck up cobble together.
Cheers!
Re: Feasibility of customising return guardian micro ai
It wouldn't be much additional effort since you would just copy the entire ca_return_guardian.lua file to your add-on. Then the only thing you would need to change (at first) would be the lines that callSpannerbag wrote: August 31st, 2026, 10:55 am However I'm not sure the additional effort is worth it given I can employ other implementations that would be a lot easier/simpler if also less close to what I envisage.![]()
AH.get_named_loc_xy('return', cfg) since that is what looks for return_x and return_y, so you could replace that with your own logic.https://github.com/wesnoth/wesnoth/blob/1.18.8/data/ai/micro_ais/cas/ca_return_guardian.lua#L18
https://github.com/wesnoth/wesnoth/blob/1.18.8/data/ai/micro_ais/cas/ca_return_guardian.lua#L31
- Spannerbag
- Posts: 978
- Joined: December 18th, 2016, 6:14 pm
- Location: Yes
Re: Feasibility of customising return guardian micro ai
Having done a tiny bit of digging myself I'd come to a very similar conclusion; basically extend the existing logic by having the return guardian micro ai work as it does now plus enabling unit specific return x,y values that override the "global" values
So in both
If both exist and are on-map then use these otherwise fallback to existing
However, it's been awhile since I worked with lua and I've forgotten a fair bit but it'll hopefully come back to me once I look into things a bit more.
Presently I think the logic would be something like:
If not, this isn't anywhere near as complex as I'd imagined.
Thanks for the info, much appreciated!
Cheers!
return_x,return_y / return_loc.So in both
:evaluation and :execution I'd need to test if the current guardian unit had unit variables set; probably unit.variables.return_guardian.return_x and unit.variables.return_guardian.return_y.If both exist and are on-map then use these otherwise fallback to existing
return_loc = AH.get_named_loc_xy('return', cfg).However, it's been awhile since I worked with lua and I've forgotten a fair bit but it'll hopefully come back to me once I look into things a bit more.
Presently I think the logic would be something like:
- Test unt variables, if either is null/undefined fallback to default/global values.
Presumably these values would be visible in lua asguardian.return_guardian.return_xandguardian.return_guardian.return_y? - Test unit x,y values on map (presumably
wesnoth.current.map.special_locations[loc_id]? Not explored options for this yet).
If not on map then again fallback to default/global values as in 1. above. - Otherwise use unit values.
If not, this isn't anywhere near as complex as I'd imagined.
Thanks for the info, much appreciated!
Cheers!
Re: Feasibility of customising return guardian micro ai
Custom unit variables should be inSpannerbag wrote: September 1st, 2026, 9:49 am Test unt variables, if either is null/undefined fallback to default/global values.
Presumably these values would be visible in lua asguardian.return_guardian.return_xandguardian.return_guardian.return_y?
guardian.variables:https://wiki.wesnoth.org/LuaAPI/types/unit#Unit_sub-tables
That's if you are using a named locationSpannerbag wrote: September 1st, 2026, 9:49 am Test unit x,y values on map (presumablywesnoth.current.map.special_locations[loc_id]? Not explored options for this yet).
loc_id to identify the location.If you're using x and y values and you just want to check that they are valid, you could use
wesnoth.current.map:on_board(x, y).https://github.com/wesnoth/wesnoth/blob/1.18.8/data/ai/lua/ai_helper.lua#L776
- Spannerbag
- Posts: 978
- Joined: December 18th, 2016, 6:14 pm
- Location: Yes
Re: Feasibility of customising return guardian micro ai
Forgot the "variables" bit.gnombat wrote: September 1st, 2026, 12:57 pm Custom unit variables should be inguardian.variables:
https://wiki.wesnoth.org/LuaAPI/types/unit#Unit_sub-tables
Yes, that would be much simpler, thanks!gnombat wrote: September 1st, 2026, 12:57 pm ...If you're using x and y values and you just want to check that they are valid, you could usewesnoth.current.map:on_board(x, y).
https://github.com/wesnoth/wesnoth/blob/1.18.8/data/ai/lua/ai_helper.lua#L776
Thanks for the very helpful advice and links, much appreciated!
Cheers!
- Spannerbag
- Posts: 978
- Joined: December 18th, 2016, 6:14 pm
- Location: Yes
Re: Feasibility of customising return guardian micro ai
Hi,
making progress but have a couple of queries.
None of this has been tested yet, responses to this post will determine if I test current code or mess things up even further simplify (if sensible) first
First I created a new mai
ORIGINAL ca_return_guardian:evaluation
My abomination:
However the thought occurs that a simpler method would be to simply reassign
This would be passed back as a return value to overwrite the value specified in the definition.
As these are local variables they wouldn't (I presume) have any effect on the initial
Would this approach work and if so have I missed anything?
Thanks in advance!
Cheers!
making progress but have a couple of queries.
None of this has been tested yet, responses to this post will determine if I test current code or mess things up even further simplify (if sensible) first
First I created a new mai
return_guardian_uv (_uv for unit variables).
Code: Select all
-- mai_return_guardian_uv.lua
-- Modified return guardian mai with unit specific return co-ordinates
-- Many thanks to gnombat for advice and assistance
-- https://forums.wesnoth.org/viewtopic.php?t=60912
-- https://wiki.wesnoth.org/LuaAPI/types/unit#Unit_sub-tables
-- https://github.com/wesnoth/wesnoth/blob/1.18.8/data/ai/lua/ai_helper.lua#L776
-- If specified, unit variables can override return location specified in [micro_ai] tag.
-- These are: unit.variables.return_guardian_uv.return_x and unit.variables.return_guardian_uv.return_y
local AH = wesnoth.require "ai/lua/ai_helper.lua"
function wesnoth.micro_ais.return_guardian_uv(cfg)
if (cfg.action ~= 'delete') then
if (not cfg.id) and (not wml.get_child(cfg, "filter")) then
wml.error("Return Guardian UV [micro_ai] tag requires either id= key or [filter] tag")
end
AH.get_named_loc_xy('return', cfg, 'Return guardian UV [micro_ai] tag')
end
local required_keys = {}
local optional_keys = { id = 'string', filter = 'tag',
return_loc = 'string', return_x = 'integer', return_y = 'integer' -- May be overridden by unit variables
}
local CA_parms = {
ai_id = 'mai_return_guardian_uv',
{ ca_id = 'move', location = 'ca_return_guardian_uv.lua', score = cfg.ca_score or 100100 }
}
return required_keys, optional_keys, CA_parms
endCode: Select all
function ca_return_guardian:evaluation(cfg)
local guardian = get_guardian(cfg)
if guardian then
local return_loc = AH.get_named_loc_xy('return', cfg)
if (guardian.x == return_loc[1]) and (guardian.y == return_loc[2]) then
return cfg.ca_score - 200
else
return cfg.ca_score
end
end
return 0
endCode: Select all
local AH = wesnoth.require "ai/lua/ai_helper.lua"
local function get_guardian_uv(cfg)
local filter = wml.get_child(cfg, "filter") or { id = cfg.id }
local guardian_uv = AH.get_units_with_moves {
side = wesnoth.current.side,
{ "and", filter }
}[1]
return guardian_uv
end
local ca_return_guardian_uv = {}
function ca_return_guardian_uv:evaluation(cfg)
local guardian_uv = get_guardian_uv(cfg)
if guardian_uv then
if guardian.variables.return_guardian.return_x and guardian.variables.return_guardian.return_y then
if wesnoth.current.map:on_board(guardian.variables.return_guardian.return_x, guardian.variables.return_guardian.return_y) then
if (guardian_uv.x == guardian.variables.return_guardian.return_x) and (guardian_uv.y == guardian.variables.return_guardian.return_y) then
return cfg.ca_score - 200
else
return cfg.ca_score
end
else
wml.error("Unit return location not on map: guardian.variables.return_guardian.return_x,y=" .. guardian.variables.return_guardian.return_x .. ',' .. guardian.variables.return_guardian.return_y .. " " .. (required_for or ''))
end
else
local return_loc = AH.get_named_loc_xy('return', cfg)
if (guardian_uv.x == return_loc[1]) and (guardian_uv.y == return_loc[2]) then
return cfg.ca_score - 200
else
return cfg.ca_score
end
end
end
return 0
endreturn_loc in get_guardian_uv if valid (on map) locations are specified in the current guardian_uv.This would be passed back as a return value to overwrite the value specified in the definition.
As these are local variables they wouldn't (I presume) have any effect on the initial
return_loc value passed from the definition?Would this approach work and if so have I missed anything?
Thanks in advance!
Cheers!
Re: Feasibility of customising return guardian micro ai
I'm not sure exactly what you have in mind... I would probably recommend just creating a new function, like this:Spannerbag wrote: September 2nd, 2026, 3:07 pm However the thought occurs that a simpler method would be to simply reassignreturn_locinget_guardian_uvif valid (on map) locations are specified in the currentguardian_uv.
This would be passed back as a return value to overwrite the value specified in the definition.
As these are local variables they wouldn't (I presume) have any effect on the initialreturn_locvalue passed from the definition?
Code: Select all
local function get_guardian_uv_xy(cfg, guardian_uv)
...
end
function ca_return_guardian_uv:evaluation(cfg)
local guardian_uv = get_guardian_uv(cfg)
if guardian_uv then
local return_loc = get_guardian_uv_xy(cfg, guardian_uv)
if (guardian_uv.x == return_loc[1]) and (guardian_uv.y == return_loc[2]) then
return cfg.ca_score - 200
else
return cfg.ca_score
end
end
return 0
end
- Spannerbag
- Posts: 978
- Joined: December 18th, 2016, 6:14 pm
- Location: Yes
Re: Feasibility of customising return guardian micro ai
Heh, at first glance your structure does pretty much what I was trying to express - and in a more elegant way.gnombat wrote: September 2nd, 2026, 7:39 pm ...I'm not sure exactly what you have in mind... I would probably recommend just creating a new function...
To me, it does the same basic thing: assign the unit's return values to
return_loc and leave the original logic more or less unchanged?However your example clarifies a few structural uncertainties I had.
Will hopefully wreck things completely get this working over the next few days as time permits (rl is busy as ever
Thanks again for your help, much appreciated as always!
Cheers!
- Spannerbag
- Posts: 978
- Joined: December 18th, 2016, 6:14 pm
- Location: Yes
Re: Feasibility of customising return guardian micro ai
Well, got it working much quicker (and more easily) than expected. 
Not exhaustively tested but seems to work as expected plus no errors.
Only niggle was lua didn't like testing for the nonexistence of a variable inside a nonexistent container (fair enough I suppose) so I just tested for the container.
So, instead of:
I used
Only other minor query: I've not been able to find the internal structure of 
I don't think I'll bother with error trapping for where
Thanks again for your help and patience, really helpful.
Cheers!
Not exhaustively tested but seems to work as expected plus no errors.
Only niggle was lua didn't like testing for the nonexistence of a variable inside a nonexistent container (fair enough I suppose) so I just tested for the container.
So, instead of:
if guardian_uv.variables.return_guardian.return_x and guardian_uv.variables.return_guardian.return_y thenif guardian_uv.variables.return_guardian thenloc so guessed at how to assign return_loc_uv the relevant x,y values - is there a better way than what I did (line 6 of code below)? Just curious. Code: Select all
local function get_guardian_uv_xy(cfg, guardian_uv)
local return_loc_uv = AH.get_named_loc_xy('return', cfg)
-- if guardian_uv.variables.return_guardian.return_x and guardian_uv.variables.return_guardian.return_y then
if guardian_uv.variables.return_guardian then
if wesnoth.current.map:on_board(guardian_uv.variables.return_guardian.return_x, guardian_uv.variables.return_guardian.return_y) then
return_loc_uv[1], return_loc_uv[2] = guardian_uv.variables.return_guardian.return_x, guardian_uv.variables.return_guardian.return_y
end
end
return return_loc_uv
endvariables.return_guardian exists but doesn't contain return_x and/or return_y and just let the logic silently fallback to the return values specified in micro_ai].Thanks again for your help and patience, really helpful.
Cheers!