Working lua need advice deciding which method is best

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

Moderator: Forum Moderators

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

Re: Working lua need advice deciding which method is best

Post by Spannerbag »

gnombat wrote: April 10th, 2024, 8:52 pm
Spannerbag wrote: April 10th, 2024, 7:52 pm * - What is the correct term for doing a {...} btw?
A table constructor.

Ah... eyes glazed over and attention failed before I got that far into the lua manual... :oops:
Can't take too much manual-ploughing before brain packs in.
Thanks for the link and explanation, very helpful and enlightening.

gnombat wrote: April 10th, 2024, 8:52 pm _ is a function which should always take as its argument a single literal quoted string, which should generally be a complete sentence rather than a fragment of a sentence.

Suppose you have two variables you want to use in a sentence:

Code: Select all

local color = "red"
local species = "dragon"
local sentence = "There is a " .. color .. " " .. species .. "."
If you want to make that translatable, you should not use concatenation:

...

Really the only way to do it is to avoid the concatenation operator (..):

Code: Select all

# THIS WORKS: the argument to _() is a single literal quoted string which represents a complete sentence
local sentence = stringx.vformat(_("There is a $color $species."), {color=color,species=species})
Y'know, I think I actually understand this part of lua now. :D
Many thanks as ever for your patience and taking the trouble to explain in detail, really appreciated.

Cheers!
-- Spannerbag
SP Campaigns: After EI (v1.14) Leafsea Burning (v1.17, 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: 537
Joined: December 18th, 2016, 6:14 pm
Location: Yes

Re: Working lua need advice deciding which method is best

Post by Spannerbag »

Ravana wrote: April 10th, 2024, 9:03 pm If you used global variables then stringx.vformat(_("There is a $color $species."), _G) something of this idea will work. _G is table of global variables.

With local you need to explicitly add them.

Or use local v={}, v.color = "red", v.species = "dragon", stringx.vformat(_("There is a $color $species."), v)
Thanks for taking the trouble to reply.
Amazingly, I'd actually stumbled across _G.
I assume there is no relationship between _G and [set_global_variable]?
That is, manipulating one doesn't affect the other?

Cheers!
-- Spannerbag
SP Campaigns: After EI (v1.14) Leafsea Burning (v1.17, 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
Ravana
Forum Moderator
Posts: 3018
Joined: January 29th, 2012, 12:49 am
Location: Estonia
Contact:

Re: Working lua need advice deciding which method is best

Post by Ravana »

_G is about Lua variables, [set_global_variable] is about WML variables which are stored in file.
User avatar
Spannerbag
Posts: 537
Joined: December 18th, 2016, 6:14 pm
Location: Yes

Re: Working lua need advice deciding which method is best

Post by Spannerbag »

Ravana wrote: April 11th, 2024, 9:25 am _G is about Lua variables, [set_global_variable] is about WML variables which are stored in file.
Yep, got that - and I think you've answered my question but, to be crystal clear, if something is created by [set_global_variable], that variable/data will not automagically appear in _G?
That is, they are totally separate data spaces?

Thanks again for your patience,
cheers!
-- Spannerbag
SP Campaigns: After EI (v1.14) Leafsea Burning (v1.17, 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: 710
Joined: June 10th, 2010, 8:49 pm

Re: Working lua need advice deciding which method is best

Post by gnombat »

Spannerbag wrote: April 11th, 2024, 9:32 am
Ravana wrote: April 11th, 2024, 9:25 am _G is about Lua variables, [set_global_variable] is about WML variables which are stored in file.
Yep, got that - and I think you've answered my question but, to be crystal clear, if something is created by [set_global_variable], that variable/data will not automagically appear in _G?
That is, they are totally separate data spaces?
Yes, those are two entirely different things, despite the similarity in the name.

Actually even the name is not really the same, since the documentation for [set_global_variable] uses the term "Persistent Variables". It probably would have been better to name the tag [set_persistent_variable].
User avatar
Celtic_Minstrel
Developer
Posts: 2241
Joined: August 3rd, 2012, 11:26 pm
Location: Canada
Contact:

Re: Working lua need advice deciding which method is best

Post by Celtic_Minstrel »

Let me just repeat myself: passing _G to stringx.vformat will not work.
gnombat wrote: April 11th, 2024, 4:44 am
Celtic_Minstrel wrote: April 11th, 2024, 4:11 am
white_haired_uncle wrote: April 11th, 2024, 2:14 am

Code: Select all

_("There is a $color $species.")
I only speak American, not even English, but that looks like a pain for translators. Would they re-order $color and $species as necessary (in which case this appears to be a preferable alternative to string.format, which I find much more readable)? What about gender (a -> un or una depending on the unknown gender of $species). And even in American, a could be an for color=azure (I know I ran into a tool that handles that, though not in wesnoth, strings in Qt I think?).
None of that is handled, which is why you shouldn't construct translatable strings in this way. The only things that are safe to be substituted into a translatable sentence are numbers and proper nouns, and in the latter case you still need to have two copies of the string – one feminine and one masculine. (Substituting whole paragraphs into a string, or in some case full sentences, may also be fine.)
I'm not sure what you mean by "none of that is handled" - the point I was trying to make with that example is that re-ordering the variables is handled, which is why using a formatting function may be preferable to simply using the concatenation operator. Of course, there may be other translation issues that are not so easy to solve.
The stuff that isn't handled is things like gender and verb declension, which is what white_haired_uncle was talking about. There's nothing that automatically pluralizes the verb or automatically inserts the correct article or automatically makes adjectives agree with their noun in gender.
Author of The Black Cross of Aleron campaign and Default++ era.
Former maintainer of Steelhive.
User avatar
Spannerbag
Posts: 537
Joined: December 18th, 2016, 6:14 pm
Location: Yes

Re: Working lua need advice deciding which method is best

Post by Spannerbag »

gnombat wrote: April 11th, 2024, 12:16 pm
Spannerbag wrote: April 11th, 2024, 9:32 am ...to be crystal clear, if something is created by [set_global_variable], that variable/data will not automagically appear in _G?
That is, they are totally separate data spaces?
Yes, those are two entirely different things, despite the similarity in the name.

Actually even the name is not really the same, since the documentation for [set_global_variable] uses the term "Persistent Variables". It probably would have been better to name the tag [set_persistent_variable].
Thanks for the clarification.
I got consufed about persistence because I got this muddled with (player) side "persistence" and used the wrong term. :doh:

Uh, while I've got you I've another (sort of) syntax question to ask if I may?
I'm probably trying to run before I can walk, but what I want to do is apply an externally specified (in WML) string repesenting a [filter to a specific unit which by the time the logic gets to this point will have confirmed that said unit exists.

The parameters concerning this logic are passed to lua here:

Code: Select all

-- Pass values from WML to lua 
function wesnoth.wml_actions.dbck_setup(cfg)
  local event_name  = cfg.event_name     or wml.error "[dbck_setup] missing required event_name= attribute."
  local side_candc  = tonumber(cfg.side) or wml.error "[dbck_setup] missing required side= attribute."
  local unit_filter = cfg.unit_filter    or wml.error "[dbck_setup] missing required unit_filter= attribute."
end
Part of the verification logic:

Code: Select all

  if not dbck_unit[1] then return end				-- No unit at location
  if not wml.eval_conditional{wml.variable{name = "side_number", numerical_not_equals = side_candc}} then return end	-- Not correct side turn
Then I get to the filter.
I plan to use have_unit.

The wiki gives this example:

Code: Select all

local result = wml.eval_conditional {
  wml.have_unit { id = "hero" },
  wml.variable { name = "counter", numerical_equals = "$old_counter" }
}
I've also seen this syntax whilst going through other lua code:

if wml.variables['boolean_wml_variable'] then ...

I.e. do something if variable is true?

Now here I can't simply and two have_unit tests because:
  • The first test alone will always be true, and
  • The second will test all units thereby likely producing false positives.
So I need to and the conditions in a single have_unit (unless there's a better way?).
(If you're curious why this isn't all specified in the WML filter unit_filter it's because I want to cater for multiple concurrent uses of this logic which I don't need right now, but if I get it working this way, will be very handy in future applications.)


It would save me a lot of frustration and keyboard bashing if I could narrow down my options here, so below are the two approaches I've thought of.
I'd just like to know if:
  1. There's a better way I've not thought of (highly likely), and
  2. If I have stumbled across the optimal strategy how to actually produce working code.
However, at this point I'm more interested in knowing which is the correct approach rather than necessarily have working code (though that would be very nice!).

The problem is that both the ways I thought of doing this require lua to be able to "dig inside" variables and recognise "embedded" commands such as and or side=1 etc. which it probably can't do as it doesn't know WML...

Anyway, my flawed ideas should describe what I'm trying to do.


First possible method I thought of
Prepend the unit's id (dbck_unit[1].id I presume) to the unit_filter string (which is the contents of a [filter]), i.e. something like:
unit_filter=dbck_unit[1].id .. "and (" .. unit_filter ..")" and then use something like:

if not wml.eval_conditional{ wml.have_unit['unit_filter'] } then return end -- Unit failed filter specified


Second possible method I thought of
Explicitly and these conditions inside have_unit... but I've no idea how to do this.
I.e. something like:
wml.have_unit{ id = wml.variables.dbck_unit[1].id and wml.variables.unit_filter }


Hope this all makes sense and if you're bored answering basic questions, no worries.

Heh, once I have all this working then - even though it's for single player use - I'll probably have to make it replay safe by synchronising everything <shudder>...

Cheers!
-- Spannerbag
SP Campaigns: After EI (v1.14) Leafsea Burning (v1.17, 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: 710
Joined: June 10th, 2010, 8:49 pm

Re: Working lua need advice deciding which method is best

Post by gnombat »

I'm not sure I understand what you have in unit_filter.
Spannerbag wrote: April 11th, 2024, 2:04 pm the unit_filter string (which is the contents of a [filter])
I'm still not clear on what unit_filter is expected to contain.

It might help if you posted the WML code.
User avatar
Spannerbag
Posts: 537
Joined: December 18th, 2016, 6:14 pm
Location: Yes

Re: Working lua need advice deciding which method is best

Post by Spannerbag »

gnombat wrote: April 11th, 2024, 3:02 pm I'm not sure I understand what you have in unit_filter.
Spannerbag wrote: April 11th, 2024, 2:04 pm the unit_filter string (which is the contents of a [filter])
I'm still not clear on what unit_filter is expected to contain.

It might help if you posted the WML code.
Sorry, wasn't clear.

This lua code:

Code: Select all

-- Pass values from WML to lua 
function wesnoth.wml_actions.dbck_setup(cfg)
  local event_name  = cfg.event_name     or wml.error "[dbck_setup] missing required event_name= attribute."
  local side_candc  = tonumber(cfg.side) or wml.error "[dbck_setup] missing required side= attribute."
  local unit_filter = cfg.unit_filter    or wml.error "[dbck_setup] missing required unit_filter= attribute."
end
Allows this in WML a scenario:

Code: Select all

    [dbck_setup]
      event_name  = "dbck_test"		# name of event to fire
      side        = 1			# Only enabled on this side's turn
      unit_filter = "x,y=4,4"
    [/dbck_setup]
So the lua variable unit_filter contains the relevant filter (in this case x,y=4,4).
The unit to be filtered against is determined by a separate mechanism (double clicking a unit).
What I don't know how to do is how to get lua to parse or eval or otherwise treat the contents of unit_filter as a WML filter not a simple data string.

Edit: forgot to add:

Somewhere else in the scenaerio is the event named above.
Here it's basically a placeholder as I need to get the lua working first.

Code: Select all

  [event]
    name=dbck_test
    first_time_only=no
    [message]
      id=$unit.id
      message=_"Well, did it work or what?"
    [/message]
  [/event]
Hope this clarifies?
If I can get this working (big if!) it'll function in a manner similar to the context menu.

[off_topic]
The reason why I'm doing this is that for me, at least, gameplay is disrupted by the context menu.
Whilst it's fine for information and start-of-game recruitment, in the "heat of battle" doubleclicking a unit to get it to do something feels more natural to me than right clicking it then selecting a menu option.
I know, I'm weird. :)

Besides, in my next campaign I already use the context menu for quite a few things so having an alternative for certain unit actions would be handy.
Heh, it was was about 70% complete but since I've started reworking chunks of Leafsea Burning - of which this is a part - I fear it's more like 40% complete. :doh:
[/off_topic]

Anyway, hope this all makes sense, but if I've still not been clear please let me know!

Thanks again,
cheers!
-- Spannerbag
SP Campaigns: After EI (v1.14) Leafsea Burning (v1.17, 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
Ravana
Forum Moderator
Posts: 3018
Joined: January 29th, 2012, 12:49 am
Location: Estonia
Contact:

Re: Working lua need advice deciding which method is best

Post by Ravana »

Code: Select all

    [dbck_setup]
      event_name  = "dbck_test"		# name of event to fire
      side        = 1			# Only enabled on this side's turn
[unit_filter]
      x,y=4,4
[/unit_filter]
    [/dbck_setup]
would make it much easier to parse.
User avatar
Spannerbag
Posts: 537
Joined: December 18th, 2016, 6:14 pm
Location: Yes

Re: Working lua need advice deciding which method is best

Post by Spannerbag »

Ravana wrote: April 11th, 2024, 3:40 pm

Code: Select all

    [dbck_setup]
      event_name  = "dbck_test"		# name of event to fire
      side        = 1			# Only enabled on this side's turn
[unit_filter]
      x,y=4,4
[/unit_filter]
    [/dbck_setup]
would make it much easier to parse.
Thanks!

I hadn't thought of doing it all in WML [event][filter].
I suppose it would be feasible to have something like:

Code: Select all

[filter]
  id=$unit.id    # Primary unit set in lua
  [and]
    ... other conditions, using WML variables (also possibly set in lua) ...
  [/and]
[/filter]
That's a lot simpler (at least to me).

Great suggestion, will explore.

Thanks!
Really helpful... just wish I'd thought of that myself - too busy trying to learn lua to see alternatives! :doh:

Cheers!
-- Spannerbag
SP Campaigns: After EI (v1.14) Leafsea Burning (v1.17, 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: 537
Joined: December 18th, 2016, 6:14 pm
Location: Yes

Re: Working lua need advice deciding which method is best

Post by Spannerbag »

Just got stuck on another bit of logic where I want to test WML side_number against a lua variable and the syntax is wrong (I think).

Code: Select all

  wml.fire("message",
  { speaker = "narrator", message = stringx.vformat(_ "In game events dbck_setup values in lua:\nevent_name=$eventname\nside_candc=$sidecandc",{eventname=event_name,sidecandc=side_candc})})
  wml.fire("message",
  { speaker = "narrator", message = stringx.vformat(_ "In game events side_number=$side_number",wml.all_variables)})
  local dbck_unit = wesnoth.units.find_on_map{ x=x, y=y }
  if wml.variables['dbck_disabled'] then return end		-- Doubleclick detect disabled
  if not dbck_unit[1] then return end				-- No unit at doubleclicked location
  if wml.eval_conditional{wml.variable{ name = "side_number", numerical_not_equals = 'side_candc'}} then return end	-- Not correct side turn
side_number is displayed correctly in the message but the last line (#29 in the code) gives an error:

Code: Select all

error scripting/lua: ~add-ons/stub18/lua/dbck.lua:29: attempt to call a nil value (field 'variable')
stack traceback:
	~add-ons/stub18/lua/dbck.lua:29: in function <~add-ons/stub18/lua/dbck.lua:21>
Even if I replace 'side_candc' with the number 1 the error doesn't change.
My code seems to be of the same form as the wiki...

Code: Select all

local result = wml.eval_conditional {
  wml.have_unit { id = "hero" },
  wml.variable { name = "counter", numerical_equals = "$old_counter" }
}
... but I can't find any documentation for wml.variable, though I haven't looked absolutely everywhere yet.
(So maybe the error is actually about the variable statement itself, not the contents?)

I've spent hours on this and am beginning to lose the will to live so will post this and leave it for awhile to calm down.
I hope someone can enlighten me - I've not even got to the tricky stuff yet!

Thanks in advance for your time and patience.

Cheers!
-- Spannerbag
SP Campaigns: After EI (v1.14) Leafsea Burning (v1.17, 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: 710
Joined: June 10th, 2010, 8:49 pm

Re: Working lua need advice deciding which method is best

Post by gnombat »

Are you sure that's not supposed to be wml.tag.variable?
User avatar
Ravana
Forum Moderator
Posts: 3018
Joined: January 29th, 2012, 12:49 am
Location: Estonia
Contact:

Re: Working lua need advice deciding which method is best

Post by Ravana »

wiki is wrong, wml.variable does not exist. It was supposed to be wml.tag.have_unit and wml.tag.variable.

Lua also knows some comparison operators, so you can use for example wesnoth.current.side ~= side_candc
User avatar
Spannerbag
Posts: 537
Joined: December 18th, 2016, 6:14 pm
Location: Yes

Re: Working lua need advice deciding which method is best

Post by Spannerbag »

@gnombat
gnombat wrote: April 11th, 2024, 10:16 pm Are you sure that's not supposed to be wml.tag.variable?
Heh, I trusted the wiki and didn't know about wml.tag.variable...
Thanks for pointing this out!


@Ravana
Ravana wrote: April 11th, 2024, 10:16 pm wiki is wrong, wml.variable does not exist. It was supposed to be wml.tag.have_unit and wml.tag.variable.

Lua also knows some comparison operators, so you can use for example wesnoth.current.side ~= side_candc

Ditto, also... wow, wesnoth.current looks really useful and I totally missed it in the wiki. As I learn new stuff I'm realising how wrong-headed my original code design and approach was, am revising this on-the-fly.
At least I feel the various bits and pieces are coming together, many thanks for your time and effort, both of you, it's really appreciated.

I'm not there yet and am still blundering in the fog, but at least I now can see a few road signs...

Cheers!
-- Spannerbag
SP Campaigns: After EI (v1.14) Leafsea Burning (v1.17, 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