enclave's Lua thread

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

Moderator: Forum Moderators

Post Reply
gfgtdf
Developer
Posts: 1432
Joined: February 10th, 2013, 2:25 pm

Re: enclave's Lua thread

Post by gfgtdf »

Elvish_Hunter wrote: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.
I think it is still wrong, the original code did not contain a bracket too much, instead there was bracket missing.
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 »

wow, thats a lot of text there ;) Thank you! Very informative :)

I used lua because I was expecting to need synchronized.choice... so I thought that if i'm going to need it then I won't have to convert my code into anything and do double work :) glad to find that it didnt need synchronised choice.. happy happy :)
I dont really understand tables at the moment I guess, I will better use T. for some time :)

I'd like to learn lua for 3 reasons at the moment:
Spoiler:
Back to my questions,
I have only 1 left at the moment.. If i had to enable right click option when not my turn, where do I start?
EoHS shows popup when moving mouse from one unit to another.. works when not player's turn.
Any ideas what lua code would look like if it had to be "on_mouse_move"... function() ... sort of thing.. any ideas?
EoHS is very hard to read for me.. I will be searching the right code there for another year probably :D
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 think it is still wrong, the original code did not contain a bracket too much, instead there was bracket missing.
:doh: Tested and fixed:

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:lua was the only way to find out what version of wesnoth every player has, there is no tag for synchronized choice, or wesnoth version in WML.
That's not completely correct: WML has two preprocessor directives, called #ifver and #ifnver. By using them, you can implement code that is conditionally enabled depending on the player's Wesnoth version.
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)
User avatar
iceiceice
Posts: 1056
Joined: August 23rd, 2013, 2:10 am

Re: enclave's Lua thread

Post by iceiceice »

The main benefits to use lua + wml rather than just wml in my opinion are these:
  • lua has a proper grammar and a nice parser -- if you make a typo, it is more likely to be able to give you a useful explanation with pointers to line numbers than WML is. Full grammar is here: http://www.lua.org/manual/5.3/manual.html#9
  • lua has a better type system than wml. You can assign tables in lua to their children just like they were strings or numbers. Assigning entries to arrays in WML by contrast requires a totally different syntax that is very verbose and painful. You generally have to use the [set_variables] tag, and if you don't get the variable names exactly right, it won't necessarily flag an error, it might just ignore your tag and pretend nothing bad happened. You don't often need to do manipulate arrays or complex data structures in scenario or campaign code but if you have to do it a lot, your code might be more readable and maintainable in lua.
  • lua has some features that wml lacks. In wml you cannot define functions. You can define custom events and fire them, but this is not a complete substitute. In lua functions are first class data types -- you can pass a function to another function as an argument, and call a function which is stored in a variable. Sometimes code is much simpler if you can manipulate functions this way. In WML you can define macros which take other macros as arguments, but this approach has many drawbacks. lua also makes a lot of use of this feature to make iterators, which make it simpler to manipulate a data structure. If you have such a usecase, I would suggest to use lua rather than WML.
  • lua has access to features like "wesnoth.synchronize_choice". If you need to do certain things in mp, you need to use this, and you can't use just WML. This partly stems from lack of ability to write functions in wml -- synchronize_choice most naturally takes as an argument the function that is supposed to be run in a synchronized way. I don't think there's a good way that we could extend WML to allow you to use synchronize_choice without using lua.
  • lua has access to features like theme_items. If you ever played Bob's Galactic Empires add-on -- the "custom" ui displays, for instance that show HQ stats and nicer displays for transporters, were written by me in lua. They allow you to do comptuations and fancy things to adjust UI displays, without requiring an event to be fired or to get synchronization. They also don't block you from undoing a move. There's no way to make stuff like that in WML. Also you can look at gfgtdf's Scenario with robots for more sophisticated uses of this.
  • lua can be used to *define new WML tags*. Indeed, about half of all of the WML tags are actually implemented in lua, not directly in C++. If you have a scenario or campaign with special custom mechanics, a good way to organize it is to define new WML tags in lua that implement the mechanics you want. Then write your scenario in pure WML, plus the custom WML you made. You can look at After the Storm, or Shadows of Deception, for examples of this style. IMO it can make complicated things a lot more readable once you get used to it.
The main drawbacks are
  • Two languages = more stuff = more complicated.
  • Confusion about state, what is persistent. Variables just sitting in the lua environment are not synchronized across the network, and are not saved to savegame files or replays. For state that should be persistent this way, you have to write to a WML variable. There is a wesnoth "vars metatable" that makes this very succinct, but the reasons that you have to use this are ... well its not that complicated, I mean I just explained it to you. But it's still adding some complexity.
enclave
Posts: 936
Joined: December 15th, 2007, 8:52 am

Re: enclave's Lua thread

Post by enclave »

to Elvish_Hunter:
didnt know about #ifver :) stupid me.. but well.. my code in lua looked like:
Spoiler:
I was looking for right-click menu when not player's turn and came across lua help on compare versions.. so I thought "here it is! just what I also need!" and never read about #ifver :) I guess my approach is not the right one, - not reading full texts, but only what I'm looking for in particular cases.. And the result - missed #ifver... :) Anyway I'm happy with my lua results :)

To iceiceice:
wow, didnt know lua variables are not transferable in network :) thanks a lot.. you gave me some ideas on my right-click menu!
enclave
Posts: 936
Joined: December 15th, 2007, 8:52 am

Re: enclave's Lua thread

Post by enclave »

iceiceice wrote: If you ever played Bob's Galactic Empires add-on -- the "custom" ui displays, for instance that show HQ stats and nicer displays for transporters, were written by me in lua.
very nice idea in that era.. nice graphics.. strange nobody playing it..
enclave
Posts: 936
Joined: December 15th, 2007, 8:52 am

Re: enclave's Lua thread

Post by enclave »

This is actually giving OOSes wihout syncronized choice.. I dont think that reason of OOS is anything else.

Code: Select all

wesnoth.wml_actions.message {
image="portraits/humans/transparent/peasant.png",
speaker="narrator",
side_for="1",
caption="Choose Game Settings",
message="Would you like comparison of players progress to be OFF or ON?",
T.option {
    message = "ON",
    T.command { 
T.set_variable { name = "input1", value="ON" }
    }
  },
T.option {
    message = "OFF",
    T.command { 
T.set_variable { name = "input1", value="OFF" }
    }
  }
}
local lua_starting_top9=wesnoth.get_variable("input1")
wesnoth.set_variable("showtop9",wesnoth.get_variable("input1"))
I dont see problems to remake the code above into synchronized choice, BUT i see big problems and I hardly know where to start with the code below:

Code: Select all

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                                  (Recommended)",
    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                  (Not Recommended)",
    T.command { 
T.set_variable { name = "input5", value="true" }
    }
  }
}
local lua_starting_resources=wesnoth.get_variable("input1")
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"))
I guess i have to shorten it all into just 1 value.. I knew I would have to remake it all into sync choice!
enclave
Posts: 936
Joined: December 15th, 2007, 8:52 am

Re: enclave's Lua thread

Post by enclave »

changed into synchronized choice, still causing OOS on start..

can this cause OOS?

Code: Select all

wesnoth.wml_actions.print {
text="Starting resources: " .. tostring(lua_starting_resources) .. "\n" .. "First turn Help: " .. tostring(lua_starting_help) .. 
"\n" .. "Player Comparison: " .. tostring(lua_starting_top9),
size="40",
duration="250",
red="0",
green="100",
blue="255"
}
or its somewhere there:

Code: Select all

local result = wesnoth.synchronize_choice(
function()
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                                  (Recommended)",
    T.command { 
T.set_variable { name = "input1", value="15" },
    }
  },
T.option {
    message = "45",
    T.command { 
T.set_variable { name = "input1", value="45" },
    }
  },
T.option {
    message = "90",
    T.command { 
T.set_variable { name = "input1", value="90" },
    }
  },
T.option {
    message = "TEST MODE                  (Not Recommended)",
    T.command { 
T.set_variable { name = "input1", value="test" }
    }
  }
}
return { value = wesnoth.get_variable("input1") }
end,
function()
return { value = "15" }
end)
local lua_starting_resources=result.value
if not (lua_starting_resources=="test") then
wesnoth.set_variable("starting_food",result.value)
wesnoth.set_variable("starting_wood",result.value)
wesnoth.set_variable("starting_stone",result.value)
wesnoth.set_variable("starting_gold",result.value)
else
wesnoth.set_variable("testing_mode","true")
end
Please Help ;)
User avatar
iceiceice
Posts: 1056
Joined: August 23rd, 2013, 2:10 am

Re: enclave's Lua thread

Post by iceiceice »

Simple way to check is to use :inspect dialog on both clients. If your wml variables aren't matching then you definitely got OOS.

I don't think print can cause an OOS, can't say for sure with the other one because it depends when it is fired. You are better off to post the whole scenario than code snippets.
enclave
Posts: 936
Joined: December 15th, 2007, 8:52 am

Re: enclave's Lua thread

Post by enclave »

print on its own didnt cause oos.. so it all is down into message options..

The full code is here:
Spoiler:
below is event..
Spoiler:
Only LUA_PRELOAD_OPTIONS1 is causing oos.. removing some parts of it making things back to normal..
with only this
Spoiler:
every player will report out of sync as soon as game begins (same without sync choice)

Otherwise in local game with only my computer (local player) no problems whatsoever..

Or maybe I need to move message options to more later event? (I mean message options not allowed for start/prestart/preload.. maybe turn 1 also not good?)
User avatar
iceiceice
Posts: 1056
Joined: August 23rd, 2013, 2:10 am

Re: enclave's Lua thread

Post by iceiceice »

So I would suggest you to try it at turn 2 and see if it is still OOS.

I don't remember exactly how stuff worked in 1.10, but I thought that in 1.10 both start and prestart are not really safe, so most add-ons would delay such menus until the time that P1 moves their first unit. I think that "start" is actually the same as "turn 1".

In 1.12 I think that this should work fine. I don't see anything wrong with your lua.
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 »

This is unrelated to your problem, but I noticed these lines in your code:

Code: Select all

wesnoth.set_variable("testing_mode","true")
end
------------------------------
if not (tostring(wesnoth.get_variable("testing_mode")) == "true") then
I assume that what you're attempting here is to set a boolean variable and check its value, right? In this case, there are a few useful tips to know:
  1. When setting a boolean variable, Lua has two special values available: true and false (nil also counts as false, everything else in Lua counts as true). Both of them must be used without quotes, otherwise "false" between quotes counts as a string value and is cast as true:

    Code: Select all

    Lua 5.2.3  Copyright (C) 1994-2013 Lua.org, PUC-Rio
    > if "false" then print("Value is true") end
    Value is true
    > if false then print("Value is true") end
    > 
    
  2. In WML, both "yes" and "true" count as true boolean values, and both "no" and "false" count as false boolean values. WML and Lua automatically take care of the appropriate castings. This code:

    Code: Select all

    		[set_variable]
    			name=test_0
    			value=true
    		[/set_variable]
    		[set_variable]
    			name=test_1
    			value=yes
    		[/set_variable]
    		[set_variable]
    			name=test_2
    			value=false
    		[/set_variable]
    		[set_variable]
    			name=test_3
    			value=no
    		[/set_variable]
    		[lua]
    			code=<<
    				local print = std_print
    				if wesnoth.get_variable("test_0") then
    					print("Variable test_0 is true")
    				end
    				if wesnoth.get_variable("test_1") then
    					print("Variable test_1 is true")
    				end
    				if not wesnoth.get_variable("test_2") then
    					print("Variable test_2 is false")
    				end
    				if not wesnoth.get_variable("test_3") then
    					print("Variable test_3 is false")
    				end
    			>>
    		[/lua]
    gives this output:

    Code: Select all

    Variable test_0 is true
    Variable test_1 is true
    Variable test_2 is false
    Variable test_3 is false
    
    Don't mind the fact that I'm using a std_print command, as it is a 1.13 function. Up to 1.12, the normal print is used.
  3. You can directly test variables for truth without first converting them as strings:

    Code: Select all

    wesnoth.set_variable("test_6",false)
    if not wesnoth.get_variable("test_6") then
    	print(tostring(wesnoth.get_variable("test_6")))
    end
    As expected, the output is false. If test_6 was true, print() would have been skipped.
  4. Given these facts, your code can be improved in this way:

    Code: Select all

    wesnoth.set_variable("testing_mode",true)
    end
    ------------------------------
    if not wesnoth.get_variable("testing_mode") then
I know that WML and Lua variable interactions may be confusing, so let me know if there is something unclear :)
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)
enclave
Posts: 936
Joined: December 15th, 2007, 8:52 am

Re: enclave's Lua thread

Post by enclave »

thx iceiceice, I will try turn 2, will be easy change of code.. :)

thx Elvish_Hunter, i didnt know that string "false" equals to boolean true..
I was always trying to avoid "true" "false" without quotes to make sure that they are treated like strings..
I dont like the fact that true is same as yes and false is same as no.. because I was never sure if my code failed to work because machine expects "Yes" and my code expects "yes" or that machine expects "True" and my code expects "true" or my code expects "True" and machine converts my "True" into "yes" so my code doesnt work... How WML and Lua treating the code was always very confusing so I used quotes wherever I could.. now will just replace with "ON" "OFF"... will 100% remove all possible confusion...... I guess.. thx for a hint very much :) couldnt even nearly imagine that "false" could give true.. :D a lot easier to just get rid of booleans..
User avatar
iceiceice
Posts: 1056
Joined: August 23rd, 2013, 2:10 am

Re: enclave's Lua thread

Post by iceiceice »

Yes, WML and lua have different philosophies about some things. For instance, lua numbers arrays starting from one, because they think its easier for non-programmers. WML does almost everything to be as easy for nonprogrammers as possible, but did not do that one :p

WML isn't really focused on types. When we need to think of a value as a boolean, the strings "true" and "false" and "yes" and "no" will become boolean values. Other values... will get some default value which may depend on the exact context. It doesn't really make sense to say that a variable in wml is "boolean type" as opposed to a string -- its going to get written to the save file ultimately as "true" or "false" string most likely, or "yes" or "no" if you input it that way.

In lua, every expression has a precise type, which is from the list nil, boolean, number, string, userdata, function, thread, and table. You can query e.g. the type of "X" by calling the built-in function that tells you the type: "type(X)" (if I recall correctly).

Even though lua has a proper boolean type, for convenience most boolean operations also work with non-boolean objects and they won't call it an error. When interpretting objects as booleans, they take the convention that the false boolean type, and nil, are interpretted false, and everything else is true. So this one rule explains how lua "if" and also "or", "and", will behave. This idea is unique to lua, so you might have to get used to it. There are several idioms in lua that use this behavior to write certain things succinctly. http://lua-users.org/wiki/LuaStyleGuide
enclave
Posts: 936
Joined: December 15th, 2007, 8:52 am

Re: enclave's Lua thread

Post by enclave »

thx iceiceice :) I always considered arrays starting with 0 pain in the a.. :) I dont remember a single case when array[0] would be more useful than array[1], rather was always problematic and required some extra code to make it work the way you want.. adding to the code i-1 , i+1 :) etc.. wml is very nice regarding that you dont need to declare variables, array lengths and a lot of other things are really making life a lot easier. but I guess the largest tradeoff is speed of how fast it all works.. making optimisations harder.. but i never felt any differences yet in real wesnoth world :) everything is normaly working real quick.
Post Reply