Feasibility of customising return guardian micro ai

Discussion of Lua and LuaWML support, development, and ideas.

Moderator: Forum Moderators

User avatar
Spannerbag
Posts: 968
Joined: December 18th, 2016, 6:14 pm
Location: Yes

Feasibility of customising return guardian micro ai

Post by Spannerbag »

Hi,

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
end
Ideally return_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!
SP Campaigns: After EI (v1.14) Leafsea Burning (v1.18, v1.16)
I suspect the universe is simpler than we think and stranger than we can know.
Also, I fear that beyond a certain point more intelligence does not necessarily benefit a species...
User avatar
Lord-Knightmare
Discord Moderator
Posts: 2545
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

Post by Lord-Knightmare »

to specify different return_x,return_y for each unit?
Yes, this is possible.
(other than defining multiple micro_ais) of doing this?
This is the way to do it.
Creator of "War of Legends"
Creator of the Isle of Mists survival scenario.
Maintainer of Forward They Cried
User:Knyghtmare | My Medium
User avatar
Spannerbag
Posts: 968
Joined: December 18th, 2016, 6:14 pm
Location: Yes

Re: Feasibility of customising return guardian micro ai

Post by Spannerbag »

Lord-Knightmare wrote: August 30th, 2026, 4:03 pm
to specify different return_x,return_y for each unit?
Yes, this is possible.
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 pm
(other than defining multiple micro_ais) of doing this?
This is the way to do it.
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...

Will consider my options.

Thanks for the reply, appreciated!
SP Campaigns: After EI (v1.14) Leafsea Burning (v1.18, v1.16)
I suspect the universe is simpler than we think and stranger than we can know.
Also, I fear that beyond a certain point more intelligence does not necessarily benefit a species...
User avatar
Lord-Knightmare
Discord Moderator
Posts: 2545
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

Post by Lord-Knightmare »

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...
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.
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)?
Nothing is stopping you from making a customized return guardian MAI for your campaign and use that.
Creator of "War of Legends"
Creator of the Isle of Mists survival scenario.
Maintainer of Forward They Cried
User:Knyghtmare | My Medium
User avatar
Spannerbag
Posts: 968
Joined: December 18th, 2016, 6:14 pm
Location: Yes

Re: Feasibility of customising return guardian micro ai

Post by Spannerbag »

Thanks again for the advice, much appreciated. :D

I think I'll look into multiple mais first as this seems the saner approach.

Cheers!
SP Campaigns: After EI (v1.14) Leafsea Burning (v1.18, v1.16)
I suspect the universe is simpler than we think and stranger than we can know.
Also, I fear that beyond a certain point more intelligence does not necessarily benefit a species...
gnombat
Posts: 1097
Joined: June 10th, 2010, 8:49 pm

Re: Feasibility of customising return guardian micro ai

Post by gnombat »

Spannerbag wrote: August 30th, 2026, 3:56 pm And, maybe, tweak the behaviour (not sure until I playtest which is a long way off :( ).
You'll probably need to create your own AI eventually anyway then?

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
User avatar
Spannerbag
Posts: 968
Joined: December 18th, 2016, 6:14 pm
Location: Yes

Re: Feasibility of customising return guardian micro ai

Post by Spannerbag »

gnombat wrote: August 30th, 2026, 7:08 pm You'll probably need to create your own AI eventually anyway then?...
Thanks for the info, I have several options and am presently scoping out the complexity of each.
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!
SP Campaigns: After EI (v1.14) Leafsea Burning (v1.18, v1.16)
I suspect the universe is simpler than we think and stranger than we can know.
Also, I fear that beyond a certain point more intelligence does not necessarily benefit a species...
gnombat
Posts: 1097
Joined: June 10th, 2010, 8:49 pm

Re: Feasibility of customising return guardian micro ai

Post by gnombat »

Spannerbag 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. :?
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 call 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
User avatar
Spannerbag
Posts: 968
Joined: December 18th, 2016, 6:14 pm
Location: Yes

Re: Feasibility of customising return guardian micro ai

Post by Spannerbag »

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 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. :fingers_crossed:

Presently I think the logic would be something like:
  1. Test unt variables, if either is null/undefined fallback to default/global values.
    Presumably these values would be visible in lua as guardian.return_guardian.return_x and guardian.return_guardian.return_y?
  2. 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.
  3. Otherwise use unit values.
Think I've missed anything?

If not, this isn't anywhere near as complex as I'd imagined. :D

Thanks for the info, much appreciated!

Cheers!
SP Campaigns: After EI (v1.14) Leafsea Burning (v1.18, v1.16)
I suspect the universe is simpler than we think and stranger than we can know.
Also, I fear that beyond a certain point more intelligence does not necessarily benefit a species...
gnombat
Posts: 1097
Joined: June 10th, 2010, 8:49 pm

Re: Feasibility of customising return guardian micro ai

Post by gnombat »

Spannerbag 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 as guardian.return_guardian.return_x and guardian.return_guardian.return_y?
Custom unit variables should be in guardian.variables:

https://wiki.wesnoth.org/LuaAPI/types/unit#Unit_sub-tables
Spannerbag wrote: September 1st, 2026, 9:49 am Test unit x,y values on map (presumably wesnoth.current.map.special_locations[loc_id]? Not explored options for this yet).
That's if you are using a named location 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
User avatar
Spannerbag
Posts: 968
Joined: December 18th, 2016, 6:14 pm
Location: Yes

Re: Feasibility of customising return guardian micro ai

Post by Spannerbag »

gnombat wrote: September 1st, 2026, 12:57 pm Custom unit variables should be in guardian.variables:

https://wiki.wesnoth.org/LuaAPI/types/unit#Unit_sub-tables
Forgot the "variables" bit. :doh:

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 use wesnoth.current.map:on_board(x, y).

https://github.com/wesnoth/wesnoth/blob/1.18.8/data/ai/lua/ai_helper.lua#L776
Yes, that would be much simpler, thanks!

Thanks for the very helpful advice and links, much appreciated!

Cheers!
SP Campaigns: After EI (v1.14) Leafsea Burning (v1.18, v1.16)
I suspect the universe is simpler than we think and stranger than we can know.
Also, I fear that beyond a certain point more intelligence does not necessarily benefit a species...
User avatar
Spannerbag
Posts: 968
Joined: December 18th, 2016, 6:14 pm
Location: Yes

Re: Feasibility of customising return guardian micro ai

Post by Spannerbag »

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 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
end
ORIGINAL ca_return_guardian:evaluation

Code: 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
end
My abomination:

Code: 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
end
However the thought occurs that a simpler method would be to simply reassign return_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!
SP Campaigns: After EI (v1.14) Leafsea Burning (v1.18, v1.16)
I suspect the universe is simpler than we think and stranger than we can know.
Also, I fear that beyond a certain point more intelligence does not necessarily benefit a species...
gnombat
Posts: 1097
Joined: June 10th, 2010, 8:49 pm

Re: Feasibility of customising return guardian micro ai

Post by gnombat »

Spannerbag wrote: September 2nd, 2026, 3:07 pm However the thought occurs that a simpler method would be to simply reassign return_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?
I'm not sure exactly what you have in mind... I would probably recommend just creating a new function, like this:

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
User avatar
Spannerbag
Posts: 968
Joined: December 18th, 2016, 6:14 pm
Location: Yes

Re: Feasibility of customising return guardian micro ai

Post by Spannerbag »

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...
Heh, at first glance your structure does pretty much what I was trying to express - and in a more elegant way.
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. :D

Will hopefully wreck things completely get this working over the next few days as time permits (rl is busy as ever :augh: ).

Thanks again for your help, much appreciated as always!

Cheers!
SP Campaigns: After EI (v1.14) Leafsea Burning (v1.18, v1.16)
I suspect the universe is simpler than we think and stranger than we can know.
Also, I fear that beyond a certain point more intelligence does not necessarily benefit a species...
User avatar
Spannerbag
Posts: 968
Joined: December 18th, 2016, 6:14 pm
Location: Yes

Re: Feasibility of customising return guardian micro ai

Post by Spannerbag »

Well, got it working much quicker (and more easily) than expected. ^_^

Not exhaustively tested but seems to work as expected plus no errors. :shock:

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 then
I used
if guardian_uv.variables.return_guardian then
Only other minor query: I've not been able to find the internal structure of loc 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
end
I don't think I'll bother with error trapping for where variables.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. :D
Cheers!
SP Campaigns: After EI (v1.14) Leafsea Burning (v1.18, v1.16)
I suspect the universe is simpler than we think and stranger than we can know.
Also, I fear that beyond a certain point more intelligence does not necessarily benefit a species...
Post Reply