Probably stupid lua question

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

Moderator: Forum Moderators

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

Probably stupid lua question

Post by Spannerbag »

Hi,
I'm trying to make a version of [message] that can accept a list of unit ids to simplify (remove) WML to winnow down choices.
The first unit in the list that exists on the map issues the message then the routine quits.
If no unit is found it does nothing (like normal [message]).

Ideally in time I'd like to generalise this to accept a [filter] (that can return more than one unit).

If there's some way to do this within [message] please let me know because I tried (despite the wiki!) specifying multiple ids and it didn't work.

Here's what I have:

_main.cfg

Code: Select all

  [lua]
    code="wesnoth.require '~add-ons/stub18/lua/msglist.lua'"
  [/lua]
Path is correct.

WML:

Code: Select all

[message]
  speaker=SMtest
  message=_"SMtest sanity test, next message has 2 ids"
[/message]
[message]				# This does not work (didn't expect it to)
  speaker=Goody,SMtest
  message=_"This message has 2 ids"
[/message]
[msglist]
  message=_"msglist test message!"
  id=SMtest,notfound,Goody
[/msglist]
[message]
  speaker=SMtest
  message=_"Done msglist"
[/message]
The first and last ids exist (are on the map), the middle one does not.
The two normal [message]s work fine.

lua:

Code: Select all

-- [msglist]
--  message=_"translatable string"
--  id=id1,id2,...

function wesnoth.wml_actions.msglist(cfg)
  local msg = cfg.message or wml.error "[msglist] missing required message= attribute."
  local msgids = cfg.id or wml.error "[msglist] missing required id= attribute."

  for index, msgid in ipairs(msgids) do
    local thisid=wesnoth.units.find_on_map{id=msgid}
    if thisid ~= nil then
      wml.fire.message{speaker=thisid,message=msg} end
  end
end

No errors on screen or in logs.
lua console (last few lines for brevity):

Code: Select all

...
Running preload scripts...
$ 
wesnoth.dofile 'lua/wml-tags.lua'
wesnoth.dofile 'lua/feeding.lua'
wesnoth.dofile 'lua/diversion.lua'
wesnoth.dofile 'lua/stun.lua'

$ wesnoth.require '~add-ons/stub18/lua/dbck.lua'
$ wesnoth.require '~add-ons/stub18/lua/gold_min.lua'
$ wesnoth.require '~add-ons/stub18/lua/bannermsg.lua'
$ wesnoth.require '~add-ons/stub18/lua/msglist.lua'
Even if I just specify a single id (SMtest) it does nothing.

I guess that the logic isn't finding any units despite the first and last existing on-map.
I don't know lua that well and in the absence of error messages am out of my depth.
Could someone point out what I'm doing wrong please (I'm sure it'll be something stupid)?

Thanks in advance.

Cheers!
-- Spannerbag
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...
white_haired_uncle
Posts: 1456
Joined: August 26th, 2018, 11:46 pm
Location: A country place, far outside the Wire

Re: Probably stupid lua question

Post by white_haired_uncle »

Pretty sure you can do this in wml (why?). According to https://wiki.wesnoth.org/InterfaceActio ... message.5D [message] takes a standard unit filter, so how about using foo,bar instead of speaker=foo,bar ?

As for lua, wesnoth.units.find_on_map returns an array, so you probably just need to use wesnoth.units.find_on_map{id=msgid}[1].

I'm not sure what you're passing as msgids, but it's possible you want msgid.id instead of msgid.

I'd probably add something like

wesnoth.interface.add_chat_message(string.format("%d\t%s",index,type(msgid))

right inside your for loop so you can see what you're working with. You might need to run wesnoth with --log-debug=scripting/lua for that, I don't remember because I just always do.

Also, you're passing a list, not an array. Unless some sort of automagic conversion goes on that I don't know about, I can't see how ipairs will work here. Hint:

Code: Select all

 for msgid in string.gmatch(msgids,"[%w]+") do
 print(msgid)
end
I don't think it matters here, but it seems you're using require when you should be using dofile. Maybe someone else can help us both understand if that matters.
Last edited by white_haired_uncle on June 9th, 2024, 12:53 pm, edited 1 time in total.
Speak softly, and carry Doombringer.
User avatar
Ravana
Forum Moderator
Posts: 3313
Joined: January 29th, 2012, 12:49 am
Location: Estonia
Contact:

Re: Probably stupid lua question

Post by Ravana »

https://wiki.wesnoth.org/LuaAPI/stringx#Functions is useful if you want to implement splitting. But as last post says, [message] already does most of what you need. Difference would be about priority of units, in that case you would need custom implementation.

With priority I would implement it like

Code: Select all

local old = wesnoth.wml_actions.message

function wesnoth.wml_actions.message(cfg)
	if cfg.id ~= nil then
		for index, msgid in ipairs(stringx.split(cfg.id)) do
			local thisid=wesnoth.units.find_on_map{id=msgid}
			if thisid ~= nil then
				cfg.id=thisid.id
				return old(cfg)
			end
		end
	else
		return old(cfg)
	end
end
User avatar
Celtic_Minstrel
Developer
Posts: 2371
Joined: August 3rd, 2012, 11:26 pm
Location: Canada
Contact:

Re: Probably stupid lua question

Post by Celtic_Minstrel »

white_haired_uncle wrote: June 9th, 2024, 12:30 pm As for lua, wesnoth.units.find_on_map returns an array, so you probably just need to use wesnoth.units.find_on_map{id=msgid}[1].
Or use wesnoth.units.get(msgid).
white_haired_uncle wrote: June 9th, 2024, 12:30 pm Also, you're passing a list, not an array. Unless some sort of automagic conversion goes on that I don't know about, I can't see how ipairs will work here.
He's passing a string. If the loop does anything at all, it's probably going to loop over the string one character at a time.
white_haired_uncle wrote: June 9th, 2024, 12:30 pm I don't think it matters here, but it seems you're using require when you should be using dofile. Maybe someone else can help us both understand if that matters.
They do essentially the same thing, but require caches the loaded module somewhere so that a subsequent call just returns the cache without loading it again. Also, if I recall correctly, require doesn't support passing arguments in to the loaded function.
Author of The Black Cross of Aleron campaign and Default++ era.
Former maintainer of Steelhive.
User avatar
Spannerbag
Posts: 759
Joined: December 18th, 2016, 6:14 pm
Location: Yes

Re: Probably stupid lua question

Post by Spannerbag »

Thanks for all your help, much appreciated.
Y'know I'm going (more) crazy; I thought I'd tested id=id1,id2... in [message] and thought it failed.
However tried again just now... and it worked. :doh:
I much prefer working in WML if possible so I'll stick with [message] with multiple ids for now.
I'll see how I get on using [message]'s filtering as well.
However I'll keep the lua in back pocket just in case. :)

Sorry for wasting your time - I really thought I'd tested id=!

Many thanks for your time and trouble.

Cheers!
-- Spannerbag
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