Wesnoth Lua Pack: Development Thread

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

Moderator: Forum Moderators

Post Reply
User avatar
melinath
Posts: 1298
Joined: May 20th, 2009, 7:42 am

Wesnoth Lua Pack: Development Thread

Post by melinath »

EDIT: This add-on is available on the 1.16 add-ons server and on the following Github repo: https://github.com/Elvish-Hunter/Wesnoth_Lua_Pack.

The idea behind the WLP is to collect bits of Lua written by various people that will help supplement the helper library and WML. There are two aspects to WLP:

1. The utilities. These are meant to help people debug WML and Lua. Currently, the only scripts in this category are: utils.extract_side, utils.extract_unit, and utils.extract_cfg. Basically, the first two scripts let you look at the raw data for a unit or side while running wesnoth instead of having to wrangle with a save file in another window. The information is displayed in a message window and printed to stderr.txt or the equivalent. The third... is a bit more general-purpose and requires some knowledge of Lua to use. Documentation will be coming shortly, so you can get more details there.

2. The new tags! This is a great thing about Lua: you can make new WML tags! For example, instead of a nasty long MODIFY_UNIT macro, you can now use a trim [modify_unit] tag. Or you can use tags that have never-before-seen functionality. The pack currently includes [store_shroud] and [set_shroud], which store and set the shroud of a side, respectively. Hopefully more will be added in the future!

If you have Lua that you've written that you think should (or could) be included in this pack, post it here. If you have feedback, that goes in the Feedback/Request thread.
Last edited by Elvish_Hunter on November 22nd, 2021, 9:56 pm, edited 2 times in total.
Reason: Availability of add-on for 1.16
User avatar
melinath
Posts: 1298
Joined: May 20th, 2009, 7:42 am

Re: Wesnoth Lua Pack: Development Thread

Post by melinath »

silene on the current modify_unit code:
silene wrote:
melinath wrote:I'd like to include this code in a Lua Pack Add-on, if that's all right.
As it stands, it doesn't do much. You may want to improve it a bit beforehand. For instance,
  • remove the need for the [variables] subtag, to make the usage of the tag lighter,
  • allow subtags inside [variables], so that in-depth modification of a unit are possible (e.g. [status]poisoned=yes[/status]),
  • allow not only modifying but also adding and removing parts of the unit, e.g. [attacks] (but with which syntax?).
I can't get to upgrading it for the next few days (Plan to spend some time with friends and family) but if anyone wants to give it a stab, feel free!
silene
Posts: 1109
Joined: August 28th, 2004, 10:02 pm

Re: Wesnoth Lua Pack: Development Thread

Post by silene »

melinath wrote:The idea behind the WLP is to collect bits of Lua written by various people that will help supplement the helper library and WML.
Nice.

Concerning wlp_tags.lua, you should put the local keywords before all the variables (that is, "helper", "T", and "W"). Same thing for the functions. Indeed, your definitions overwrite user definitions (or vice versa, depending on who is last), and the user may as well have decided that "W" was something completely different, for instance a global shortcut to the "wesnoth" table.

Similarly, _main.cfg, the "require" part should not be enabled by default, and hence polluting the global environment of any scenario for users who have downloaded the addon. (But due to the comment above, this may just have been an oversight.)

By the way, why are you suggesting users to define a textdomain?
melinath wrote:If you have Lua that you've written that you think should (or could) be included in this pack, post it here.
Here are some tags I had posted elsewhere as examples. The [save_map] and [load_map] tags store and restore map data from a WML variable; useful for dealing with dynamically modified yet persistent maps. The [narrate] tags is just a shortcut for the commonly encountered [message] tag with a narrator speaker.

Code: Select all

local H = wesnoth.require "lua/helper.lua"
wesnoth.register_wml_action("save_map", function(cfg)
  local w, h, b = wesnoth.get_map_size()
  local t = {}
  for y = 1 - b, h + b do
    local r = {}
    for x = 1 - b, w + b do
      r[x + b] = wesnoth.get_terrain(x, y)
    end
    t[y + b] = table.concat(r, ',')
  end
  local s = table.concat(t, '\n')
  local v = cfg.variable or H.wml_error "save_map missing required variable= attribute."
  wesnoth.set_variable(v, string.format("border_size=%d\nusage=map\n\n%s", b, s))
end)
wesnoth.register_wml_action("load_map", function(cfg)
  local v = cfg.variable or H.wml_error "load_map missing required variable= attribute."
  wesnoth.fire("replace_map", { map = wesnoth.get_variable(v), expand = true, shrink = true })
end)
wesnoth.register_wml_action("narrate", function(cfg)
  local content = cfg.__literal
  content.speaker = "narrator"
  content.image = content.image or "wesnoth-icon.png"
  wesnoth.fire("message", content)
end)
User avatar
melinath
Posts: 1298
Joined: May 20th, 2009, 7:42 am

Re: Wesnoth Lua Pack: Development Thread

Post by melinath »

silene wrote:Concerning wlp_tags.lua, you should put the local keywords before all the variables (that is, "helper", "T", and "W"). Same thing for the functions. Indeed, your definitions overwrite user definitions (or vice versa, depending on who is last), and the user may as well have decided that "W" was something completely different, for instance a global shortcut to the "wesnoth" table.
Oh... yeah... that would make sense. :? Will be fixed with the next upload. (W and T are taken out since they never actually get used...)
silene wrote:Similarly, _main.cfg, the "require" part should not be enabled by default, and hence polluting the global environment of any scenario for users who have downloaded the addon. (But due to the comment above, this may just have been an oversight.)
The problem is that I do want those things globally available personally, just in case, but I'll try to be more careful about commenting that section out when I upload.
silene wrote:By the way, why are you suggesting users to define a textdomain?
LuaWML wrote:The function fires a [[InterfaceActionsWML#[message]|[message]]] action and passes a WML object containing the usual two fields to it. The second field is initialized by concatenating the function argument with another string. Both strings are prefixed by the _ symbol to mark them as translatable. (Note that _ is just a unary function, not a keyword.) Again, this is made possible by a specific line of the prelude:

Code: Select all

_ = wesnoth.textdomain "wesnoth-tutorial"
My understanding of this wiki section was that a textdomain had to be defined in order to have translatable strings used in a Lua script. Since the textdomain depends on the add-on where the script is being used, it seemed to make more sense for the user to define it. Although none of the scripts currently in use require translatable strings, I think this is one area where it's easier to have users add the line when they install the add-on than to make them install it if textdomains ever do become necessary.
silene wrote:

Code: Select all

wesnoth.register_wml_action("load_map", function(cfg)
  local v = cfg.variable or H.wml_error "load_map missing required variable= attribute."
  wesnoth.fire("replace_map", { map = wesnoth.get_variable(v), expand = true, shrink = true })
end)
I'm modifying the code you posted slightly (helper instead of H, since that's how the rest of the scripts are written. Though I guess I could switch it the other way. What is the advantage of H?) With this one, though - it seems to require the replace_map script from LoW. Do you know who I should ask about including that, as well?
silene
Posts: 1109
Joined: August 28th, 2004, 10:02 pm

Re: Wesnoth Lua Pack: Development Thread

Post by silene »

melinath wrote:
silene wrote:By the way, why are you suggesting users to define a textdomain?
My understanding of this wiki section was that a textdomain had to be defined in order to have translatable strings used in a Lua script. Since the textdomain depends on the add-on where the script is being used, it seemed to make more sense for the user to define it. Although none of the scripts currently in use require translatable strings, I think this is one area where it's easier to have users add the line when they install the add-on than to make them install it if textdomains ever do become necessary.
I think you are misunderstanding what "_" means (and this may explain why you have a broken ID_MESSAGE macro in Brent). Be it in WML or in Lua, "_" doesn't perform a translation; it only marks the following literal string as translatable, and it indicates where the translation should be searched if needed. The actual translation happens much later, for instance when performing a WML variable substitution or when calling "tostring" in a Lua script. In other words, you don't need to have built a textdomain before manipulating a translatable string.

If some scripts of WLP need to have translatable strings, they will use their own local variable "_" that points to a specific textdomain. Indeed, there is no reason for finding translations of WLP strings inside a random add-on. So, it makes sense for a campaign to define its own global "_", but it doesn't make sense for WLP to rely on a global "_" set by someone else.
melinath wrote:I'm modifying the code you posted slightly (helper instead of H, since that's how the rest of the scripts are written. Though I guess I could switch it the other way. What is the advantage of H?)
No advantage except for being shorter. It's just a matter of taste.
melinath wrote:With this one, though - it seems to require the replace_map script from LoW. Do you know who I should ask about including that, as well?
[replace_map] is a standard tag; the LoW script only improves it. But [load_map] doesn't need the improved [replace_map], the standard one is sufficient for it to work.

As for duplicating the one from LoW, you don't need to. Just load it (dofile) directly from its standalone file in LoW. Still, to answer your question, the first (non-working) version of [replace_map] is mine, which was then tested, fixed, and committed, by fendrin/fabi.
User avatar
melinath
Posts: 1298
Joined: May 20th, 2009, 7:42 am

Re: Wesnoth Lua Pack: Development Thread

Post by melinath »

silene wrote:So, it makes sense for a campaign to define its own global "_", but it doesn't make sense for WLP to rely on a global "_" set by someone else.
So basically if there are translatable strings, they would be set in a specific text domain (possibly wesnoth-WLP) rather than having to be translated in every single campaign where they were used...?
silene wrote:[replace_map] is a standard tag
Ah, so it is... Now I feel silly. :-)

Gah. I've been trying to get the modify_unit script tweaked, but it's not going well. I need to let it sit. Perhaps someone will notice something I'm doing wrong.

The problem I'm having is the recursion on attack tags - if you're going to be removing them, you need to be able to filter for them. But for some reason, the filter isn't catching matching attack tags. (Pardon all the extra print tags.)
Spoiler:
EDIT:: Okay, seem to have solved replace and remove... though I'm sure there's a lot I can improve on. Add can wait until tomorrow. Here's the code w/ documentation and debugging prints; I'll upload a new version.
Spoiler:
silene
Posts: 1109
Joined: August 28th, 2004, 10:02 pm

Re: Wesnoth Lua Pack: Development Thread

Post by silene »

melinath wrote:
silene wrote:So, it makes sense for a campaign to define its own global "_", but it doesn't make sense for WLP to rely on a global "_" set by someone else.
So basically if there are translatable strings, they would be set in a specific text domain (possibly wesnoth-WLP) rather than having to be translated in every single campaign where they were used...?
Exactly. And it works both way. For instance, if a custom unit in one of your campaign or era is using a "sword", just change the text domain to "wesnoth-units" before the weapon definition, and the weapon will automatically get a translation in any language.
User avatar
melinath
Posts: 1298
Joined: May 20th, 2009, 7:42 am

Re: Wesnoth Lua Pack: Development Thread

Post by melinath »

mkay. New version posted. Modify_unit now replaces, removes, and adds variables. Documentation coming soon at WLPDocs.

EDIT:: Perhaps this thread should be in the Coder's Corner?

EDIT EDIT::
A good tag to add would be an event tag that correctly handles sighted events.
Also, a tag that does a looping message menu more efficiently.
Anonymissimus
Inactive Developer
Posts: 2461
Joined: August 15th, 2008, 8:46 pm
Location: Germany

Re: Wesnoth Lua Pack: Development Thread

Post by Anonymissimus »

silene wrote:As for duplicating the one from LoW, you don't need to. Just load it (dofile) directly from its standalone file in LoW.
Makes the thing where it is used dependent on LoW's files, which are not necessarily installed on Linux systems.
melinath wrote:A good tag to add would be an event tag that correctly handles sighted events.
Yes. But remember that our crowd of developers are not able to implement this functionality correctly in C++...and don't forget to deal with the "delay shroud update" option. Maybe you can write the wml version for the semi-competent replacement that I've posted more easily...
Also...the tag you'd need to create is the [event]name=sighted tag, but lua custom tags aren't valid in [scenario]...I don't think that it is possible...other than using the existing moveto and/or sighted events.
projects (BfW 1.12):
A Simple Campaign: campaign draft for wml startersPlan Your Advancements: mp mod
The Earth's Gut: sp campaignSettlers of Wesnoth: mp scenarioWesnoth Lua Pack: lua tags and utils
updated to 1.8 and handed over: A Gryphon's Tale: sp campaign
User avatar
melinath
Posts: 1298
Joined: May 20th, 2009, 7:42 am

Re: Wesnoth Lua Pack: Development Thread

Post by melinath »

Anonymissimus wrote:
melinath wrote:A good tag to add would be an event tag that correctly handles sighted events.
Yes. But remember that our crowd of developers are not able to implement this functionality correctly in C++...and don't forget to deal with the "delay shroud update" option. Maybe you can write the wml version for the semi-competent replacement that I've posted more easily...
semi-component replacement? What do you mean?
I was thinking of modifying the moveto event tag to check if a unit becomes visible to enemies after a move, and if so, fire a sighted event. You would have to use global variables to keep track of which units could be seen and which could not... could be a bit of a pain. And I don't know how it would deal with delay shroud.
Anonymissimus wrote:Also...the tag you'd need to create is the [event]name=sighted tag, but lua custom tags aren't valid in [scenario]...I don't think that it is possible...other than using the existing moveto and/or sighted events.
The following section of the wiki seems (to me) to indicate that something like this could be possible. But I've been quite wrong before, so.
LuaWML wrote:For instance, if you cannot stand any longer the fact that first_time_only is set to yes by default for the [event] tag, you can redefine it. But we have to be careful not to cause variable substitution, since the engine would perform a second variable substitution afterwards.

Code: Select all

local old_event_handler
old_event_handler = register_wml_action("event",
    function(cfg)
        -- Get the plain text from the user.
        local new_cfg = cfg.__literal
        -- The expression below is equivalent to cfg.__parsed.first_time_only,
        -- only faster. It is needed, since the first_time_only attribute may
        -- reference variables.
        local first = cfg.first_time_only
        -- Modify the default behavior of first_time_only.
        if first == nil then first = false end
        new_cfg.first_time_only = first
        -- Call the engine handler.
        old_event_handler(new_cfg)
    end
)
silene
Posts: 1109
Joined: August 28th, 2004, 10:02 pm

Re: Wesnoth Lua Pack: Development Thread

Post by silene »

Anonymissimus wrote:
melinath wrote:A good tag to add would be an event tag that correctly handles sighted events.
Yes. But remember that our crowd of developers are not able to implement this functionality correctly in C++...and don't forget to deal with the "delay shroud update" option.
Both things are linked: the reason that prevents us from fixing it is precisely the delayed shroud update. If it weren't for this option, the event would have been fixed already.
Anonymissimus wrote:Maybe you can write the wml version for the semi-competent replacement that I've posted more easily...
Not only more easily (perhaps), but also more correctly. One thing you can do in Lua but not in plain WML is to correctly compute distance between units. In particular, I seem to remember your code is assuming that units move at maximum speed whatever the terrain; this assumption is not needed for Lua-based implementation.
Anonymissimus wrote:Also...the tag you'd need to create is the [event]name=sighted tag, but lua custom tags aren't valid in [scenario]...I don't think that it is possible...other than using the existing moveto and/or sighted events.
I don't understand what you mean. New event handlers can be created from other event handlers. And events can be fired from event handlers. So WML in general, and Lua in particular, have no troubles dealing with events.
Anonymissimus
Inactive Developer
Posts: 2461
Joined: August 15th, 2008, 8:46 pm
Location: Germany

Re: Wesnoth Lua Pack: Development Thread

Post by Anonymissimus »

melinath wrote: semi-component replacement? What do you mean?
I was thinking of modifying the moveto event tag to check if a unit becomes visible to enemies after a move, and if so, fire a sighted event. You would have to use global variables to keep track of which units could be seen and which could not... could be a bit of a pain. And I don't know how it would deal with delay shroud.
competent, not component
It has some disadvantages, see e.g. the assumption mentioned by silene.
thread:
http://forums.wesnoth.org/viewtopic.php ... c0#p389087
Don't read too much there, it causes headache. The current and tested version of the replacement macro is in my campaign, file sides_and_unit-utils.cfg. It is about what you want to do, replacing sighted with moveto, and all in wml. Be warned, the problem is way more complex than people tend to think...
Anonymissimus wrote:Also...the tag you'd need to create is the [event]name=sighted tag, but lua custom tags aren't valid in [scenario]...I don't think that it is possible...other than using the existing moveto and/or sighted events.
I don't understand what you mean. New event handlers can be created from other event handlers. And events can be fired from event handlers. So WML in general, and Lua in particular, have no troubles dealing with events.
Sorry, I was wrong here.
But still, lua can't get around the problems with delay shroud, if even C++ can't...
projects (BfW 1.12):
A Simple Campaign: campaign draft for wml startersPlan Your Advancements: mp mod
The Earth's Gut: sp campaignSettlers of Wesnoth: mp scenarioWesnoth Lua Pack: lua tags and utils
updated to 1.8 and handed over: A Gryphon's Tale: sp campaign
User avatar
melinath
Posts: 1298
Joined: May 20th, 2009, 7:42 am

Re: Wesnoth Lua Pack: Development Thread

Post by melinath »

Ah, yes, it would help if I read things right. I should be able to make a lua version of your macro that's hopefully faster and will definitely take less WML - and if I can figure out how to reliably test a unit's movement radius (which silene said was possible with Lua) then it'll even eliminate one of the bugs you had. A full fix might be difficult, but this should be doable and better than what we've got now.

The one thing I'm a little worried about is that first_time_only=no issue... hum.

List of tags I now think might be useful:
--fixing "sighted" event
--looping message menu
--unstore set so that it doesn't plop things on impassable terrain by default.
--a tag to store all locations in a unit's movement radius. (with possible option of limiting it to just those places the unit can actually move to.)
--a tag that does a looping message menu more efficiently.
Anonymissimus
Inactive Developer
Posts: 2461
Joined: August 15th, 2008, 8:46 pm
Location: Germany

Re: Wesnoth Lua Pack: Development Thread

Post by Anonymissimus »

melinath wrote:Ah, yes, it would help if I read things right. I should be able to make a lua version of your macro that's hopefully faster and will definitely take less WML - and if I can figure out how to reliably test a unit's movement radius (which silene said was possible with Lua) then it'll even eliminate one of the bugs you had. A full fix might be difficult, but this should be doable and better than what we've got now.
If you base your code on a moveto event, you need to calculate the visibility area for each of your units (the sum of them...). For that you need to take into account the surrounding terrain hexes and movement costs for these terrains for each of your units. This can probably be better implemented in lua, since it requires a lot of calculations. There was a noticable slowdown in an older version of my macro. The only terrain taken care of there is passable or impassable, but e.g. shallow water does not reduce the visibility area.

At some other place you've found out that you can access the current shroud data in lua, is that also possible for fog ? If yes, it is probably better to work with that to check whether unit(s) to be spotted have become visible as the result of the move, instead of this complex and difficult calculation.

@silene
1. Ok, lua lets me modify given event handlers. Is it possible to create a
[event]name=shroud update
with lua, which is fired whenever shroud is updated, in case that delay shroud is on ?
2. In my macro, I've made the restriction that the delay shroud option is simply ignored. That means, if the sighted event would have fired but shouldn't due to delay shroud, delay shroud is ignored, shroud is compulsorily updated and the event fires. Would that make it possible to "fix" the sighted event, if delay shroud is the only reason why it is broken ? It is an acceptible restriction imo since it happens quite seldom. (This also means that an [event]name=shroud update isn't needed since such an event can no longer reveal any unit(s) to be spotted.)
But I have the impression that there is more than one bug related to the sighted event like (mostly ?) not firing at all if unit(s) to be spotted have moved, not setting second_unit etc.

/edit
OK, I'm currently at my first attempt to create a lua version for the sighted replacement. I think that it is possible with find_path to calculate the visibility area exactly as it should be, removing one of the main disadvantages.
I'm confused about the old_event_handler code snippet quoted above by melinath; what does old_event_handler(new_cfg) at the bottom do, why is old_event_handler a variable as well as a function, and why is it called old_event_handler ? Is it possible to create new events with that, say, [event]name=spotted ? (But where is then determined when that event is fired ?)
And when is the function "function" called ? It seems it is a call to a function and its definition packed into one code piece.
In which order would a debug marker step through that code ?

/edit
I think I got it better now...the assignment to old_event_handler is done at the time the modified event is registered, but the function function is only called later at the time that the event is executed, that's why old_event_handler contains the previous event handler at that time. You should probably separate the definition and the call to the function "function" and insert some comments about the order of execution.
projects (BfW 1.12):
A Simple Campaign: campaign draft for wml startersPlan Your Advancements: mp mod
The Earth's Gut: sp campaignSettlers of Wesnoth: mp scenarioWesnoth Lua Pack: lua tags and utils
updated to 1.8 and handed over: A Gryphon's Tale: sp campaign
silene
Posts: 1109
Joined: August 28th, 2004, 10:02 pm

Re: Wesnoth Lua Pack: Development Thread

Post by silene »

Anonymissimus wrote:1. Ok, lua lets me modify given event handlers. Is it possible to create a
[event]name=shroud update
with lua, which is fired whenever shroud is updated, in case that delay shroud is on ?
No, it isn't possible. There is no hint about that from the engine. It could be added to the C++ code, but I don't see the need for it. The only time it would fire is at a time the "sighted" event already fires properly (I believe), so it wouldn't provide any new information.
Anonymissimus wrote:But I have the impression that there is more than one bug related to the sighted event like (mostly ?) not firing at all if unit(s) to be spotted have moved, not setting second_unit etc.
Do you have an example where second_unit is not set? I have taken a glance at the engine and "sighted" is never raised without specifying a second unit, so I'm a bit surprised.

As for your first bug, I don't understand it. If a unit that could have been spotted has moved, it was done by WML. So it seems sensible that the "sighted" event is not raised in that case. Oh! perhaps I see what you mean. Are you saying that it is a hindrance that "sighted" events are raised after "moveto" events when shroud updates are delayed, but the other way around when shroud updates are realtime? But then again, it is just yet another unfortunate consequence of the existence of the "delay shroud update" option.
Anonymissimus wrote:I think I got it better now...the assignment to old_event_handler is done at the time the modified event is registered, but the function function is only called later at the time that the event is executed, that's why old_event_handler contains the previous event handler at that time.
You got it right. When the new handler is registered, the previous one is returned and stored; and when the new handler is later executed, the stored handler is executed too.
Post Reply