enclave's Lua thread

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

Moderator: Forum Moderators

Post Reply
enclave
Posts: 936
Joined: December 15th, 2007, 8:52 am

enclave's Lua thread

Post by enclave »

Hello everyone,
Im using wesnoth 1.10.7

I would really like to learn Lua, and it is not very easy, because it is poorly documented..
I have couple of questions to start with:

1) How do I add options (with all show_if, not, and, or) and commands into this message code using Lua:

Code: Select all

wesnoth.wml_actions.message {
image="units/human-loyalists/peasant.png",
speaker="narrator",
side_for="1",
caption="not a caption",
message="not a message at all"
}
by the way I think narrator was working without "" also.. maybe shouldn't have.. or maybe I never noticed difference.

2) The code in wesnoth.synchronize_choice example http://wiki.wesnoth.org/LuaWML:Misc#wes ... ize_choice
didnt work for me after I removed some fragments, Im trying to figure out why.

Code: Select all

[event]
  name = "start"
  [lua]
  code = <<
    wesnoth.set_variable("input1",nil)
    local result = wesnoth.synchronize_choice(
    function()
      local option1 = T.option { message = "No", T.command { T.set_variable { name = "input1", value = "No"}}}
      local option2 = T.option { message = "Yes", T.command { T.set_variable { name = "input1", value = "Yes"}}}
      wesnoth.fire(T.message{ message =  "Are you sure you want to play this game?", option1, option2})
      return { value = wesnoth.get_variable("input1") }
    end,
    function()
      return { value = math.random(30) }
    end)
    wesnoth.set_variable("input1",nil)
    wesnoth.message("Player 1 wants to play: " .. result.value)
  >>
  [/lua]
[/event]
Im trying to use it for prestart choice of options, it says something about input nil value.. works without errors if i remove "wesnoth.message("Player 1 wants to play: " .. result.value)" but doesnt give any options to me..

3) Need to use right-click options or be able to show players [message] when not your turn, like in age of high sorcery.
If anyone has ideas, please let me know how to do it. Otherwise I need to find it in 1000s of lines of EoHS code.

Thank you!
gfgtdf
Developer
Posts: 1431
Joined: February 10th, 2013, 2:25 pm

Re: enclave's Lua thread

Post by gfgtdf »

enclave wrote:Hello everyone,
Im using wesnoth 1.10.7

I would really like to learn Lua, and it is not very easy, because it is poorly documented..
I have couple of questions to start with:

1) How do I add options (with all show_if, not, and, or) and commands into this message code using Lua:

Code: Select all

wesnoth.wml_actions.message {
image="units/human-loyalists/peasant.png",
speaker="narrator",
side_for="1",
caption="not a caption",
message="not a message at all"
}
by the way I think narrator was working without "" also.. maybe shouldn't have.. or maybe I never noticed difference.
you do teh same as in wml, assuming that you have T = helper.set_wml_tag_metatable {} somewhere it with code:

Code: Select all

[message]
  attribute1 = value1
  attribute2 = value2
  [option]
    attribute3 = value3
  [/option]
  [some_other_tag]
    attribute4 = value4
    [some_subtag]
    [/some_subtag]
  [/some_other_tag]
[/message]
becomes

Code: Select all

wesnoth.wml_actions.message {
  attribute1 = "value1",
  attribute2 = "value2",
  T.option {
    attribute3 = value3,
    T.some_subtag {
    }
  },
  T.some_other_tag {
    attribute4 = value4,
  }
}
enclave wrote: 2) The code in wesnoth.synchronize_choice example http://wiki.wesnoth.org/LuaWML:Misc#wes ... ize_choice
didnt work for me after I removed some fragments, Im trying to figure out why.

Code: Select all

[event]
  name = "start"
  [lua]
  code = <<
    wesnoth.set_variable("input1",nil)
    local result = wesnoth.synchronize_choice(
    function()
      local option1 = T.option { message = "No", T.command { T.set_variable { name = "input1", value = "No"}}}
      local option2 = T.option { message = "Yes", T.command { T.set_variable { name = "input1", value = "Yes"}}}
      wesnoth.fire(T.message{ message =  "Are you sure you want to play this game?", option1, option2})
      return { value = wesnoth.get_variable("input1") }
    end,
    function()
      return { value = math.random(30) }
    end)
    wesnoth.set_variable("input1",nil)
    wesnoth.message("Player 1 wants to play: " .. result.value)
  >>
  [/lua]
[/event]
Im trying to use it for prestart choice of options, it says something about input nil value.. works without errors if i remove "wesnoth.message("Player 1 wants to play: " .. result.value)" but doesnt give any options to me..
The code you quoted is from a "version 1.13 and later" section, so it is unlikeley to work in 1.10.x. But actually you do not need a wesnoth.synconize_choice if you want to use [message][option]. The original code in the wiki uses wesnoth.synconize_choice becasue it wants to show messages with option to sides different that the currently playing side in mp which is not posible with normal [message].
Scenario with Robots SP scenario (1.11/1.12), allows you to build your units with components, PYR No preperation turn 1.12 mp-mod that allows you to select your units immideately after the game begins.
enclave
Posts: 936
Joined: December 15th, 2007, 8:52 am

Re: enclave's Lua thread

Post by enclave »

gfgtdf thank you very much for your quick reply!

I tried to use your code from (1) of my questions, worked flawlessly so far:

Code: Select all

[lua]
code = <<
wesnoth.wml_actions.message {
image="units/human-peasants/peasant.png",
speaker="narrator",
side_for="1",
caption="not a caption",
message="not a message at all",
T.option {
    message = "option1",
    T.command {
    }
  },
T.option {
    message = "option2",
    T.command {
    }
  },
}
>>
[/lua]
it gives exactly what i want, - some options. I have more understanding on the T.option thing now.. Is there any documentation on "T" anywhere? Why "T"?

Now I may be able to work from this code into my question (2) synchronize choice.. since originally shown in documentation didnt work. And it should have worked on 1.10.7 because I removed fragments intended for 1.13 use.. (at least I believe so, but i'm not experienced enough to say for 100% sure).

I need to try synchronized choice because the code written above works flawlessly in a local game, but as soon as I go on any type of multiplayer server, the game kicks me out back to lobby as soon as it starts. Message Options are not allowed in preload, prestart and start events.. My goal is to give host (or player1) options for starting game settings (starting gold, level of help, etc) as a prestart or start event. It may be not a problem to do it on turn 1 event.. I haven't tried yet, but I simply need to know if I can do it on prestart or not (maybe using synchronized choice can help, I need to try).

If you understand the lua well, could you please check the code of synchronized choice i wrote in question (2) for basic mistakes.. maybe something with T.option or wesnoth.fire or "nil" or anything else really basic? (and not even related to synchronize choice itself) I would really appreciate because for me it's not basic yet.. I may not see something what for you may be obvious mistake.

Thank you very much for looking into my problem again!
gfgtdf
Developer
Posts: 1431
Joined: February 10th, 2013, 2:25 pm

Re: enclave's Lua thread

Post by gfgtdf »

enclave wrote: it gives exactly what i want, - some options. I have more understanding on the T.option thing now.. Is there any documentation on "T" anywhere? Why "T"?
most likeley becasue somehwere else is written "T = helper.set_wml_tag_metatable {}" see the documentation here http://wiki.wesnoth.org/LuaWML:Misc#hel ... _metatable
enclave wrote: I need to try synchronized choice because the code written above works flawlessly in a local game, but as soon as I go on any type of multiplayer server, the game kicks me out back to lobby as soon as it starts. Message Options are not allowed in preload, prestart and start events..
in 1.10.7 none of the functions that use mp sync work in prestart or start events. This includes [message][option], wesnoth.synchronize_choice, [unstore_unit] with advancements and [get_global_variable], using any of those in 1.10.7 in a prestart/start event in mp will end the game.

In 1.12/1.13 it is possible to use mp sync in start and prestart events but still it is reccomended not to use it in prestart events becasue it will casue the players who are not making the decision to wait with a black window. (because prestart events are fired 'before anything is shown on the screen at all').
Scenario with Robots SP scenario (1.11/1.12), allows you to build your units with components, PYR No preperation turn 1.12 mp-mod that allows you to select your units immideately after the game begins.
User avatar
iceiceice
Posts: 1056
Joined: August 23rd, 2013, 2:10 am

Re: enclave's Lua thread

Post by iceiceice »

enclave:

- If you look at the LuaWML page, who wrote it was I guess a fan of very short identifiers to save typing. So they suggested to make many of these "frequently useful" lua objects as single capital letters, like "W" = wesnoth action metatable, for simulating WML commands directly in lua, "H" the lua helper library, and also "T" this table constructor helper. If you can get used to this then use it by all means, if you get confused by the letters, just give them longer more descriptive names. Most code examples you'll see though probably use the letters, although I think I've seen "helper" instead of "H".

None of these things is strictly necessary, their source code is all written in lua and found in the data folder. The only fundamental thing is the "wesnoth" proxy table, which contains direct hooks into the engine. Anything that these things will be doing to affect the game state will ultimately boil down to some calls to "wesnoth.something".

- In 1.13, there is a lua console which lets you interact with the in-game lua through an interpreter. So you can type "wesnoth.get_unit({...})" and it will print interactively the result for you to look at. You can also use tab-completion here, so you can explore what functions and data are available, and what their children are etc. I think its a decent tool to play around with if you are trying to get used to how the game will interpret your lua code.

It is reachable from the "gamestate inspector" via the "lua console" button, or via a hotkey.
enclave
Posts: 936
Joined: December 15th, 2007, 8:52 am

Re: enclave's Lua thread

Post by enclave »

Huge thanks to you gfgtdf, I didn't know these things. I will put my options into turn 1 then or wherever else I can.. without much fuss around. I really wanted it on black screen, on preload, makes more sense for options.. while all other players could get message like "host is choosing settings" on same black screen.. I don't see problems with it, rather the opposite, but it doesn't matter too much.

thank you very much iceiceice for explanations on these T things and other stuff, will play around with it some day:)

Anyone knows how prestart options are organized in conquest- add-on? I tried to read it but it all seems overcomplicated to me, functions only lead to more functions there.. just like if it was all encrypted for my brain :)

PS. maybe the code with synchronized choice (2) gave me error because it was using math.random(30) there? somehwere in documentation it says it was disabled for being OOS magnet, and should use helper.rand instead.. ?
enclave
Posts: 936
Joined: December 15th, 2007, 8:52 am

Re: enclave's Lua thread

Post by enclave »

I solved the problem below, please skip this post, please read next one first (this post will stay relevant to my next post)

Here we go, question #4 (4)

I have written the code

Code: Select all

[lua]
code = <<
wesnoth.set_variable("testing_mode","false")
wesnoth.set_variable("turn1help","ON")
wesnoth.set_variable("showtop9","ON")
wesnoth.wml_actions.message {
image="portraits/humans/transparent/peasant.png",
speaker="narrator",
side_for="1",
caption="Choose Game Settings",
message="How much resources would you like each player to start with?",
T.option {
    message = "15",
    T.command { 
wesnoth.set_variable("starting_food","15"),
wesnoth.set_variable("starting_wood","15"),
wesnoth.set_variable("starting_stone","15"),
wesnoth.set_variable("starting_gold","15")
    }
  },
T.option {
    message = "45",
    T.command { 
wesnoth.set_variable("starting_food","45"),
wesnoth.set_variable("starting_wood","45"),
wesnoth.set_variable("starting_stone","45"),
wesnoth.set_variable("starting_gold","45")
    }
  },
T.option {
    message = "90",
    T.command { 
wesnoth.set_variable("starting_food","90"),
wesnoth.set_variable("starting_wood","90"),
wesnoth.set_variable("starting_stone","90"),
wesnoth.set_variable("starting_gold","90")
    }
  },
T.option {
    message = "TEST MODE",
    T.command { 
wesnoth.set_variable("testing_mode","true")
    }
  },
}
>>
[/lua]
And of course it does not do what I want it to do.. because it is quite WML(ish).. and I guess Lua should work different way?
Basically I need to give choice of options.. and if the choice was "15" to set variables with "15"... but what my code does, it performs all of the "wesnoth.set_variable" that are in my code.. or only the last one, I'm not too sure.. could it be so?

I guess I should put some locals like "input", give them values, and then only in the end use "wesnoth.set_variable"? Or what am I doing wrong? Sorry I guess it looks too stupid, my code.. but I'm still trying to figure out how to use this "mutant" WML-Lua language.. :) nice experience from the other hand..
enclave
Posts: 936
Joined: December 15th, 2007, 8:52 am

Re: enclave's Lua thread

Post by enclave »

Regarding my question number (4) in my previous post..

Was the code below best way to solve my problem in a previous post?

Code: Select all

[lua]
code = <<
wesnoth.set_variable("turn1help","ON")
wesnoth.set_variable("showtop9","ON")
wesnoth.wml_actions.message {
image="portraits/humans/transparent/peasant.png",
speaker="narrator",
side_for="1",
caption="Choose Game Settings",
message="How much resources would you like each player to start with?",
T.option {
    message = "15",
    T.command { 
T.set_variable { name = "input1", value="15" },
T.set_variable { name = "input2", value="15" },
T.set_variable { name = "input3", value="15" },
T.set_variable { name = "input4", value="15" },
T.set_variable { name = "input5", value="false" }
    }
  },
T.option {
    message = "45",
    T.command { 
T.set_variable { name = "input1", value="45" },
T.set_variable { name = "input2", value="45" },
T.set_variable { name = "input3", value="45" },
T.set_variable { name = "input4", value="45" },
T.set_variable { name = "input5", value="false" }
    }
  },
T.option {
    message = "90",
    T.command { 
T.set_variable { name = "input1", value="90" },
T.set_variable { name = "input2", value="90" },
T.set_variable { name = "input3", value="90" },
T.set_variable { name = "input4", value="90" },
T.set_variable { name = "input5", value="false" }
    }
  },
T.option {
    message = "TEST MODE",
    T.command { 
T.set_variable { name = "input5", value="true" }
    }
  }
}
wesnoth.set_variable("starting_food",wesnoth.get_variable("input1"))
wesnoth.set_variable("starting_wood",wesnoth.get_variable("input2"))
wesnoth.set_variable("starting_stone",wesnoth.get_variable("input3"))
wesnoth.set_variable("starting_gold",wesnoth.get_variable("input4"))
wesnoth.set_variable("testing_mode",wesnoth.get_variable("input5"))
>>
[/lua]
Thank you all very much, all help is very much appreciated!

PS. regarding my question (2) synchronised choice.. In this case I did not need it.. why? Is it because there was no variables like wesnoth.game_config.version involved? I dont understand when and why choice of options would need synchronised choice.. and when doesnt... I just want to make sure it wont cause any OOS.. Is it if each player would have to chose different option? No I still completely don't understand :)
User avatar
Ravana
Forum Moderator
Posts: 2933
Joined: January 29th, 2012, 12:49 am
Location: Estonia
Contact:

Re: enclave's Lua thread

Post by Ravana »

It would be better solution to just use http://wiki.wesnoth.org/OptionWML so that other players do not need to wait.
enclave
Posts: 936
Joined: December 15th, 2007, 8:52 am

Re: enclave's Lua thread

Post by enclave »

Thank you very much Ravana, but as far as I understand checkbox is only working starting from 1.11

My question (4) was more like "how could I optimise my lua code to make it any shorter? Or have I already done it best/short way possible?"
gfgtdf
Developer
Posts: 1431
Joined: February 10th, 2013, 2:25 pm

Re: enclave's Lua thread

Post by gfgtdf »

hm then why dont you use 1.12 ?
PS. regarding my question (2) synchronised choice.. In this case I did not need it.. why? Is it because there was no variables like wesnoth.game_config.version involved? I dont understand when and why choice of options would need synchronised choice.. and when doesnt... I just want to make sure it wont cause any OOS.. Is it if each player would have to chose different option?
[message][option] is has an automatic sync mechanism that works the same way as wesnoth.syncronized_choice (but with less configuration posibilities) if you put [message][option] in a wesnoth.syncronized_choice you will basicly use that sync mechanism twice, In 1.10 this causes OOS.

wesnoth 1.12 and later will notice that you use mp sync twice and simply ignore the second use of mp sync (that is [message][option]s sync meachnism if you put that inside a wesnoth.sync_choice).
In 1.13 wesnoth.sync_choice allows you to query multiple other players than the currently active player, which [message][option]s sync mechanism does not allow. The code from the wiki works around that 'drawback' by puting it insode a wesnoth.sync_hoice to that sync_hoices sync meanism is used instead of [mesage][options] sync mechanism.

There are some other non mp save functions most importantly wesnoith.show_dialog, they do not have a mp sync mechamism if you want to use them then in most cases you have to use wesnoth.sync_choice (in 1.10 and in 1.12)
Scenario with Robots SP scenario (1.11/1.12), allows you to build your units with components, PYR No preperation turn 1.12 mp-mod that allows you to select your units immideately after the game begins.
enclave
Posts: 936
Joined: December 15th, 2007, 8:52 am

Re: enclave's Lua thread

Post by enclave »

Thank you very much for information gfgtdf! Was very useful to know.

I still use 1.10 because I started my project there, I plan to change it to 1.12 soon, after I polish it a little bit more, so I could leave it with 1.10 in more or less complete state (while there are still a lot of players there).

For 1.12 I will have to change some things.. i noticed some picture pathes became different, i noticed that [ability] will have to work some other way.. and for some reason a random map generator also has different way of functioning (at the moment simply doesnt work the way i have it in my project).. So of course I will switch to 1.12, I already see a tendency of more players playing there in 1.12, so people started to switch.
Spoiler:
User avatar
Elvish_Hunter
Posts: 1575
Joined: September 4th, 2009, 2:39 pm
Location: Lintanir Forest...

Re: enclave's Lua thread

Post by Elvish_Hunter »

enclave wrote:1) How do I add options (with all show_if, not, and, or) and commands into this message code using Lua:
There are two ways to do it. The one that you're currently using is called a metatable, and to use it you must first assign said metatable to the T variable:

Code: Select all

local T = helper.set_wml_tag_metatable()
In this case, it allows you to write shorter code, but there are two problems: first, it partially hides how WML tags are handled in Lua; second metatables are one of the most complex paradigms in Lua (they're used to implement object-oriented programming), so usually one learns them later, not in the beginning.
The second way to implement sub-tags require the use of WML tables. At the time, I had serious troubles understanding them, because the wiki explanation wasn't that good. Now, however, the situation is much clearer: a WML table is just a regular table, where the first element is the tag name, and the second element is another table containing all the key/value pairs. Should one member of this second table be another sub-tag, it must be implemented as a WML table again.
In your case the code becomes:

Code: Select all

wesnoth.wml_actions.message {
    image="units/human-loyalists/peasant.png",
    speaker="narrator",
    side_for="1",
    caption="not a caption",
    message="not a message at all",
    { "show_if",
        { "have_unit", {
            id = "Elyssa"
            }
        }
    }
}
enclave wrote:by the way I think narrator was working without "" also.. maybe shouldn't have.. or maybe I never noticed difference.
Tip: uninitialized variable are automatically handled by Lua as if they contained the nil value. This has the tendency to create obscure bugs, and for this reason in the upcoming 1.13 series we implemented a strict mode, where using not initialized variables throws an error. So, in your case the speaker key was handled in this way:

Code: Select all

speaker = nil
enclave wrote:maybe something with T.option or wesnoth.fire or "nil" or anything else really basic?
wesnoth.fire is here for two reasons: backwards compatibility (it was the only way to call a WML tag in 1.8 ) and WML variable substitution (which isn't performed by the usual wesnoth.wml_actions, unless you access a special field called .__parsed - but that's a more advanced topic).
Except from these two cases, you usually call WML tags directly from wesnoth.wml_actions.
iceiceice wrote:If you look at the LuaWML page, who wrote it was I guess a fan of very short identifiers to save typing.
Yep, that was silene's style.
iceiceice wrote:Most code examples you'll see though probably use the letters, although I think I've seen "helper" instead of "H".
For sure you'll find it in every piece of documentation that I write: I always preferred to write long variable names, because the short ones confuse me. So, if somewhere you find helper, tag, unit, location, index, key, value instead of H, T, u, loc, i, k, v, you can be pretty sure who the culprit was :P Although some other devs may have followed my example, as it's true that one types more, but one needs to type less comments as well (the variable name itself counts as a form of comment) and it's more likely to catch mistakes.
enclave wrote:Regarding my question number (4) in my previous post..
Here you pretty much ended up writing Lua as if it was WML. The best solution, in this case, is to avoid Lua, and instead use directly WML code.
Personally, I use Lua mainly to implement new WML tags, which is done by creating new functions in the wesnoth.wml_actions table, and said functions should accept a cfg argument. Inside the function, you'll be able to access the WML content of the tag by reading the cfg table.
Current maintainer of these add-ons, all on 1.16:
The Sojournings of Grog, Children of Dragons, A Rough Life, Wesnoth Lua Pack, The White Troll (co-author)
gfgtdf
Developer
Posts: 1431
Joined: February 10th, 2013, 2:25 pm

Re: enclave's Lua thread

Post by gfgtdf »

I really reccomend to use T.tagname when creating wml tables, i think the error in elvish's code

Code: Select all

wesnoth.wml_actions.message {
    image="units/human-loyalists/peasant.png",
    speaker="narrator",
    side_for="1",
    caption="not a caption",
    message="not a message at all",
    { "show_if", {
        { "have_unit", {
            id = "Elyssa"
            }
        }
    }
}
makes it clear why.
Scenario with Robots SP scenario (1.11/1.12), allows you to build your units with components, PYR No preperation turn 1.12 mp-mod that allows you to select your units immideately after the game begins.
User avatar
Elvish_Hunter
Posts: 1575
Joined: September 4th, 2009, 2:39 pm
Location: Lintanir Forest...

Re: enclave's Lua thread

Post by Elvish_Hunter »

gfgtdf wrote:I really reccomend to use T.tagname when creating wml tables, i think the error in elvish's code
In that case, I accidentally added one more bracket after the "show_if". That's the downside of handling WML tables directly: it's quite easy to do add, miss or misplace some brackets - even more when one isn't using an exitor with syntax highlighting (I typed it directly in the forum's editor...). :(
Anyway, I edited my code to remove the issue.
Current maintainer of these add-ons, all on 1.16:
The Sojournings of Grog, Children of Dragons, A Rough Life, Wesnoth Lua Pack, The White Troll (co-author)
Post Reply