Dixie's Lua Thread

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

Moderators: Forum Moderators, Developers

User avatar
Dixie
Posts: 1756
Joined: February 10th, 2010, 1:06 am
Location: $x1,$y1

Re: Dixie's Lua Thread

Post by Dixie » August 13th, 2010, 7:00 pm

Thanks again for all your answers :) It's no biggie, but I think you missed my edit this morning (it was a close call, it's okay). I'm in no hurry and I really appreciate your support so I won't hold it against you.

Anyway, I've been correcting some other errors, debugging and trying a bunch of stuff, but I haven't managed to fix the problem so far.

So I always get this error:
20100813 14:38:17 error scripting/lua: ...esnoth.app/Contents/Resources/.//data/lua/helper.lua:220: bad argument #2 to 'set_variable' (WML table or scalar expected, got table)
stack traceback:
Which is basically saying that my second argument in wrong. It is caused by this line:

Code: Select all

helper.set_variable_array("inventory", generate_inventory())

-- I also tried this one, but it gives the same results:
wesnoth.set_variable("inventory", generate_inventory())
And the faulty argument two calls this function:

Code: Select all

generate_inventory = function()
  local inv_var = {}
  for i,v in ipairs(item) 
  do
    table.insert(inv_var, { amount=0, equip=0, stats=v })
-- v is a table, by the way, as the variable item called in ipairs is an array of tables
  end
return inv_var
end
Anonymissimus wrote:EDIT2
Regarding your problem, you probably create subtables instead of named fields so I'd try leaving away the {} when inserting the fields. That's what I call table confusion, it's somehow hard to get a good debug message of inv_var (in your case) that shows the structure of the table.
Was this aimed at this particular problem? Are you suggesting I do this:

Code: Select all

generate_inventory = function()
  local inv_var = {}
  for i,v in ipairs(item) 
  do
    table.insert(inv_var, ( amount=0, equip=0, stats=v) )
-- I was not sure about the parenthesis, but if I leave them out, won't the function interpret equip= and stats= as extra arguments and ignore them?
  end
return inv_var
end
But I want inv_var to be an array containing tables, which in turn contains amount=0, equip=0 and the "stats" table. I can maybe find a more elegant way of doing this, though. For instance, maybe I could add the "amount" and "equip" keys to my "v" table, and just insert "v" directly in the array...

I thought you guys told me that sub_tables and stuff were fine in WML variables... Am I somehow overdoing it? Have I missed something?

Anyway, thanks again for your invaluable support :)
Jazz is not dead, it just smells funny - Frank Zappa
Current projects: Internet meme Era, The Settlers of Wesnoth

silene
Posts: 1109
Joined: August 28th, 2004, 10:02 pm

Re: Dixie's Lua Thread

Post by silene » August 13th, 2010, 7:10 pm

Dixie wrote:Which is basically saying that my second argument in wrong.
From the look of your code, the argument is a table, so you did get correctly things like functions, local variables, and so on.

But it is not an array of WML tables. I suggest that you read again LuaWML#Encoding_WML_objects_into_Lua_tables to get a clear understanding of the format the engine expects.

The inner code should somehow look like:

Code: Select all

table.insert(inv_var, { amount=0, equip=0, { "stats", v } })
(Note that I'm assuming that v is a WML table.)

User avatar
Dixie
Posts: 1756
Joined: February 10th, 2010, 1:06 am
Location: $x1,$y1

Re: Dixie's Lua Thread

Post by Dixie » August 13th, 2010, 9:00 pm

Augh, this thing is so complicated! It has been an arduous 3 hour battle, but alast, rejoice, for I have succeeded in putting my WML object together! Thank you very much for your help with this :D
Jazz is not dead, it just smells funny - Frank Zappa
Current projects: Internet meme Era, The Settlers of Wesnoth

User avatar
Dixie
Posts: 1756
Joined: February 10th, 2010, 1:06 am
Location: $x1,$y1

Re: Dixie's Lua Thread

Post by Dixie » August 15th, 2010, 2:48 am

silene wrote:

Code: Select all

local u = wesnoth.get_units { id = unit_id }
u[1].hitpoints = u[1].hitpoints - damage_var
Note that "hitpoints" is read-only in 1.8, so the above code works on 1.9 only. On 1.8, you need to recover the whole WML of the unit, modify it, and then put it back on the map:

Code: Select all

local u = wesnoth.get_units { id = unit_id }
local u_wml = u[1].__cfg
u_wml.hitpoints = u_wml.hitpoints - damage_var
wesnoth.put_unit(u_wml)
I've been doing some code and it is mostly going smoothly, but I just realised I might have been doing some dumb stuff. I'd really test it and get the answer by myself, but I wasn't able to build a trunk (~1.9) version of Wesnoth because my OS is a bit outdated. Anyway, this is another matter entirely. So, I was doing something like this:

Code: Select all

  local unit = wesnoth.get_units { unit_id }
  local variables = helper.get_child(unit, "variables")
  local resistance = helper.get_child(unit, "resistance")

  resistance.light = 100 - variables[2][2].karma
  resistance.dark = 100 + variables[2][2].karma
I originally thought that resistance became a shortcut to unit[2][2]. But I am doubting: I realised it might be a read-only short-cut, and if I change it afterward (as per above example), I might only change the shortcut, and not the actual resistance. So I basically just want you to confirm or infirm my doubt. If my suspicions are right, I believe I should then change the last two lines for the following:

Code: Select all

  unit[2][2].light = 100 - variables[2][2].karma
  unit[2][2].dark = 100 + variables[2][2].karma
Is that right?

By the way, I verified with the print function and my console to find out that the resistance subtable was the second subtable ([2][2]), but I don't suppose this order changes randomly from unit to unit, or worse yet, from wesnoth.get_units to wesnoth.get_units, right? It ought to always be the same order, else I really don't know how I could reference and modify this stuff, if the above shortcuts are read-only, as I suspect... :hmm:

Also, I am not 100% sure, but seeing the above quote from silene:
Should local variables = helper.get_child(unit, "variables") actually be local variables = helper.get_child(unit[1], "variables")? Likewise, should unit[2][2] really be unit[1][2][2]? Since I use the ID and I'm fairly certain it'll be unique, I thought it might be implicit, but maybe it's still required, or more foolproof. I can especially imagine unit[2][2 returning an error for calling a nil value :?

Thanks again! :)

Edit:
In the surprising and unlikely case that you'd say my first code is legal, would something hypothetic and impractical such as this also work (I'm asking it this way to reuse the example, but with more subtables, such as in variables, it could be handy)? :

Code: Select all

  local unit = wesnoth.get_units { unit_id }
  local variables = helper.get_child(unit, "variables")
  local resistance = helper.get_child(unit, "resistance")
  local light_resist = resistance.light

  light_resist = 100 - variables[2][2].karma
Jazz is not dead, it just smells funny - Frank Zappa
Current projects: Internet meme Era, The Settlers of Wesnoth

silene
Posts: 1109
Joined: August 28th, 2004, 10:02 pm

Re: Dixie's Lua Thread

Post by silene » August 15th, 2010, 5:41 am

Dixie wrote:

Code: Select all

  local unit = wesnoth.get_units { unit_id }
  local variables = helper.get_child(unit, "variables")
  local resistance = helper.get_child(unit, "resistance")
This is wrong on three points. First, unless "unit_id" is a pair (a table with two unnamed elements), "{ unit_id }" won't represent a WML object. Perhaps you meant "{ id = unit_id }"? Second, your local variable "unit" is an array of units, so calling "get_child" on it won't work. Third, even if it was a unit, it still wouldn't work, since a Lua unit doesn't represent a WML object, but a unit. You get the corresponding WML object by querying the special field "__cfg". Note that querying this field is costly (as costly as calling [store_unit]), that's why the code below is written in such a way that the query is done only once:

Code: Select all

local unit = wesnoth.get_units { id = unit_id }
local unit_cfg = unit[1].__cfg
local variables = helper.get_child(unit_cfg, "variables")
local resistance = helper.get_child(unit_cfg, "resistance")
Dixie wrote:I might only change the shortcut, and not the actual resistance.
That's right. It's probably more visible in the code I rewrote: the "resistance" name points to a part of the table stored in "unit_cfg". This table is no longer related to the original unit. In plain WML, you would have to perform [unstore_unit]; this is similar in Lua:

Code: Select all

resistance.light = 100 - variables[2][2].karma
resistance.dark = 100 + variables[2][2].karma
-- resistance points to a part of unit_cfg, so modifying the content of resistance modifies the content of unit_cfg (but not of unit)
wesnoth.put_unit(unit_cfg)
Dixie wrote:but I don't suppose this order changes randomly from unit to unit, or worse yet, from wesnoth.get_units to wesnoth.get_units, right? It ought to always be the same order, else I really don't know how I could reference and modify this stuff
The order is deterministic and depends only on what you (engine+addons) are doing. Relying on numerical indices is nonetheless fragile and you should use "get_child" to find the proper one. For instance, assuming that the value is stored in [variables][karma_storage]karma=, the code would be:

Code: Select all

local k = helper.get_child(variables, "karma_storage")
resistance.light = 100 - k.karma
If it is directly stored in [variables]karma=, the code is a bit simpler:

Code: Select all

resistance.light = 100 - variables.karma

User avatar
Dixie
Posts: 1756
Joined: February 10th, 2010, 1:06 am
Location: $x1,$y1

Re: Dixie's Lua Thread

Post by Dixie » August 15th, 2010, 3:03 pm

Hm... After some tests, there's apparently still something I haven't got right. At first, I was working with this quote in mind:
silene wrote:

Code: Select all

local u = wesnoth.get_units { id = unit_id }
u[1].hitpoints = u[1].hitpoints - damage_var
Note that "hitpoints" is read-only in 1.8, so the above code works on 1.9 only. On 1.8, you need to recover the whole WML of the unit, modify it, and then put it back on the map:

Code: Select all

local u = wesnoth.get_units { id = unit_id }
local u_wml = u[1].__cfg
u_wml.hitpoints = u_wml.hitpoints - damage_var
wesnoth.put_unit(u_wml)
I had written the following thinking about using the 1.9 shortcut, which apparently allowed me to access and modify wesnoth.get_units's returned user_data directly:

Code: Select all

local unit = wesnoth.get_units { id = unit_id }
  local variables = helper.get_child(unit, "variables")
  local resistance = helper.get_child(unit, "resistance")
But then, you give me the following code, saying that helper.get_child doesn't work on user_data:

Code: Select all

local unit = wesnoth.get_units { id = unit_id }
local unit_cfg = unit[1].__cfg
local variables = helper.get_child(unit_cfg, "variables")
local resistance = helper.get_child(unit_cfg, "resistance")
resistance.light = 100 - variables[2][2].karma
resistance.dark = 100 + variables[2][2].karma
wesnoth.put_unit(unit_cfg)
What you gave me there, above, looks like the 1.8 compliant code from the first quote. So I take it using helper.get_child works basically the same way in 1.8 and 1.9. The 1.9 shortcut from the first quote is mostly only useful for accessing a unit's direct stats (such as "hitpoints"), and not subtables accessible with helper.get_child, then. Right or wrong?

But I'm not sure: is the last bit of code I copied intended for 1.9, 1.8 or both? Because unless there has been some changes in the way helper.get_child works in 1.9 to sync it with the actual table it points to, this is not working properly (not in 1.8, at least). Let me explain: I tried a variation of the previous code. resistance.light was changed alright, but when I unstored the unit with wesnoth.put_unit, I'd find out that the actual wml variable unit.resistance.light was back to its previous value. Which leads me to the conclusion that, at least under 1.8, variables accessed through helper.get_child are not synced with the actual table they point to, and are thus read-only. If they are over-written, the variable is changed, but not the unit's variable. And, as you said, using numeric indexes is confusing and unreliable. So, how am I actually supposed to modify such sub_tables without rebuilding the whole thing? Am I lacking a code or something to unstore the helper.get_child variable in the unit variable before unstoring the unit? Or is it because I'm on 1.8 and it'll be fixed by 1.9?

I hope I explained myself clearly :) Thanks again for your help!
Jazz is not dead, it just smells funny - Frank Zappa
Current projects: Internet meme Era, The Settlers of Wesnoth

User avatar
Dixie
Posts: 1756
Joined: February 10th, 2010, 1:06 am
Location: $x1,$y1

Re: Dixie's Lua Thread

Post by Dixie » August 15th, 2010, 6:48 pm

Double-post, sorry. So, I've continued doing tests and I have found the heart of the problem (which of course comes from me). I thought I was using an ingenious short-cut, while in fact I was just doing something stupid. You see, in order to chance all resistances in one call, I did this something like this:

Code: Select all

resistance = { blade = 100, pierce = 100, impact = 100 }
But doing this, I was in fact writing over the helper.get_child synced variable. Darn. So I guess I'll just do this instead:

Code: Select all

resistance.blade = 100
resistance.pierce = 100
resistance.impact = 100
-- etc.
I'm sorry, I hope I didn't have you test it aplenty and waste too much of your time :) I'm always telling myself I'll be more careful in my tests before asking for help every time, and I always (well, often) end up doing stupid stuff like this...

I am still wondering about something in 1.9's lua, though: If in that version I can modify the user_data directly like this (according to you):

Code: Select all

local u = wesnoth.get_units { id = unit_id }
u[1].hitpoints = u[1].hitpoints - damage_var
Can I do the following, or does helper.get_child still requires that the user_data is stored (converted into a table) and unstored (wesnoth.put_unit) at the end? :

Code: Select all

local unit = wesnoth.get_units { id = unit_id }
local variables = helper.get_child(unit[1], "variables")
local resistance = helper.get_child(unit[1], "resistance")
resistance.light = 100 - variables[2][2].karma
resistance.dark = 100 + variables[2][2].karma
Thanks again for your time :)

Edit:

Took me a while to figure out, but here is my final code. I'm sure it'll look very basic to you guys, but I am rather proud and happy with it :)

Code: Select all

    local u = wesnoth.get_units { id = "battle_" .. who }
    local new_member = u[1].__cfg
    local variables = helper.get_child(new_member, "variables")
    local resistance = helper.get_child(new_member, "resistance")
    local attr = helper.get_child(variables, "attr")
    for k,v in pairs(attr) do attr[k] = race[new_member.race][string.gsub(k, "max_", "")] end
    for k,v in pairs(resistance) do resistance[k] = race[new_member.race][k] end
Jazz is not dead, it just smells funny - Frank Zappa
Current projects: Internet meme Era, The Settlers of Wesnoth

silene
Posts: 1109
Joined: August 28th, 2004, 10:02 pm

Re: Dixie's Lua Thread

Post by silene » August 15th, 2010, 9:07 pm

Dixie wrote:Took me a while to figure out, but here is my final code.
Great.

I guess you have answers to all your questions then. I will just insist on the following point. The values returned by "wesnoth.get_units" are proxy units. That is a change of paradigm with respect to [store_unit] in plain WML. These proxies do not represent WML objects (neither in 1.8 nor in 1.9), so you can't call "helper.get_child" on them nor perform any kind of table operation. The only values from proxy units that you can read and/or write are the ones at the top of LuaWML:Units.

More fields will be added as Wesnoth develops further, but for now they are about the only ones the core engine can access without going through a WML object. (So the Lua engine can't provide access to more of them yet.)

User avatar
Dixie
Posts: 1756
Joined: February 10th, 2010, 1:06 am
Location: $x1,$y1

Re: Dixie's Lua Thread

Post by Dixie » August 17th, 2010, 5:33 pm

I am still playing with the phenomenon, but I feel like the helper lacks a function: helper.get_child_array.

I originally thought that helper.child_range was it, but it seems that it only iterates over them, it doesn't actually store them. I thought of the following work around:

Code: Select all

local my_children_array = {}
for s in helper.child_range(table, "children_name") do
  table.insert( my_children_array, s )
end
With about any wml object, there would be no problem, but not with unit. The problem is that afaik, this table is not synced with it's unit-wml-object-in-a-lua-table in case I modify it. Depending on the cases, I could use helper.set_variable_array, but in my case, the array is actually in the following wml object: my_unit.variables.sub_section.my_array. I already went through the wesnoth.get_unit routine and all the necessary helper.get_child all the way up to my sub_section (which was called table in the lua code above), but afaik, helper.set_variable_array would require that my unit was stored in a wml variable - and I am trying to avoid using needless extra wml variables. Maybe I wouldn't need to store the unit, just put it in a variable and then unstore, but... it really makes me crave a nifty synced children array.

I also thought about helper.get_variable_array, which might simplify the table-creating code, but it would still not be synced and require that I unstore with a wml variable. Then, there's also helper.get_variable_proxy_array, which, if I understand it correctly, would be synced, but that one would require that my unit was pre-stored in a wml variable. Which, as said before, I am trying to avoid, for cleanlyness, simplicity and efficiency.

Anyway, as I said, I am still playing with the various tools at my disposal, and maybe I have overlooked one. I will continue trying stuff, thanks for any pointers :)

Edit:
After trying out a few stuff, I figured out I could probably just have my array like this: table[2].key. So I guess this kinda kills the purpose of a helper.get_child_array... Although I dunno if there are occasions it might still be useful? I'll have to think about it some more.
Jazz is not dead, it just smells funny - Frank Zappa
Current projects: Internet meme Era, The Settlers of Wesnoth

silene
Posts: 1109
Joined: August 28th, 2004, 10:02 pm

Re: Dixie's Lua Thread

Post by silene » August 17th, 2010, 7:29 pm

Dixie wrote:I originally thought that helper.child_range was it, but it seems that it only iterates over them, it doesn't actually store them. I thought of the following work around:

Code: Select all

local my_children_array = {}
for s in helper.child_range(table, "children_name") do
  table.insert( my_children_array, s )
end
With about any wml object, there would be no problem, but not with unit. The problem is that afaik, this table is not synced with it's unit-wml-object-in-a-lua-table in case I modify it.
Did you test it? "helper.child_range" doesn't perform any copy, so the content of the elements of "my_children_array" should be synced with the original tables. What are you trying to do?

User avatar
Dixie
Posts: 1756
Joined: February 10th, 2010, 1:06 am
Location: $x1,$y1

Re: Dixie's Lua Thread

Post by Dixie » August 17th, 2010, 8:32 pm

Yes, I ended up testing it and it works, much to my surprise. I think I basically misunderstood lua tables/variables. I thought assigning variables created non-synced copies:

Code: Select all

> array_one = { {key_one="value_one", key_two="value_two"}, {key_one="value_one", key_two="value_two"} }
> array_two = array_one
> array_two[1].key_one = "different value"

> print(array_one[1].key_one == array_two[1].key_one)
false
But it seems it returns true: the two tables are synced, array_two is effectively a read AND write short-cut to array_one. Well, I'm pretty sure you already know this, so no need to babble much longer.

So anyway, I wrote this quick lua function as a nice and easy short-cut to get a child array. It IS a pretty simple and probably superfluous short-cut, and there are other ways of achieving this, too, so maybe it's not even needed at all, except to the beginners of beginners. I'll let you judge if you deem it worthy of the helper file or not :P

Code: Select all

get_child_array = function(wml_object, subtag_array_name)

local my_children_array = {}
for i in helper.child_range(wml_object, subtag_array_name) do
  table.insert( my_children_array, i )
end

return my_children_array end
Jazz is not dead, it just smells funny - Frank Zappa
Current projects: Internet meme Era, The Settlers of Wesnoth

User avatar
Dixie
Posts: 1756
Joined: February 10th, 2010, 1:06 am
Location: $x1,$y1

Re: Dixie's Lua Thread

Post by Dixie » August 18th, 2010, 8:47 pm

Hey there once again for my daily lua-related query :geek: :lol2:

As I have laid the lowest ground bases for my project (character variable generation, inventory generation, etc.), I have started working on menus to allow players to manipulate all that. AFAIK, this would be relatively easy for me to set-up in wml since I already did something like it in Paintball Era. I would like to do it in lua, however, for three reasons: 1) the synced variables/tables attribute is really powerful and would save me a great deal of trouble, 2) I think it'll be more effecient and less wml-bloat-prone in the long run and 3) it should be a good exercise :)

In wml, I used the [while][do] combo to ensure that when the user would leave the sub-menus' pages, he would be brought back to the main menu, so I figured I'd do something similar in lua. It is easier said than done, however, because I somehow can't make my inventory change pages. If at least I got some Lua error or something, I would have an hint of where to look, but nada. I suppose there is something wrong with the way I call the following menus ( {"lua", { code=...} } ), but OTOH, it works fine to exit the menu. At some point, I thought maybe the lua while/do loop was more unescapable than the wml one, so I tried to make it false to change menus, but the menu would only quit (of course, since the loop was no longer true) and not show the next menu. Maybe the issue is with the sub-menu, though... Here's a truncated version of the code, I hope I didn't omit anything important:
Spoiler:
Also, I went reference hunting to find other ways of doing this. I looked at Era of High Sorcery (which is now done in lua) since I know it somewhat uses such menus and sub-menus, but the way elvish_pillager wrote it, he has his {"command" { ... } } store a wml variable, then he wesnoth.get_variable it and tests it with a lua if to see what menu to call next. I suppose I could do this, but to me it looks much, much heavier code and cpu-wise to constantly do wesnoth.set_variable/wesnoth.get_variable etc. then to use a nice while/do loop. Although maybe the worst of it is still wesnoth.fire, which I use.

Another option could possibly be to wait out for 1.9, which will have a wesnoth.message (which would maybe even have the added benefit of letting me costumize the dialog window's layout more), and I actually might try it out, but just looking at the widget-building code gave me headache. I guess I could still put myself to it and work through it, though, but it would be easier to figure out what does what and how if I had a 1.9 binary to test it. But for the time being I am hands tied in the back and that is another story anyway, I don,t want to sound like I'm whining or anything.

So, any ideas about that while/do loop? Thanks a ton! :D
Jazz is not dead, it just smells funny - Frank Zappa
Current projects: Internet meme Era, The Settlers of Wesnoth

silene
Posts: 1109
Joined: August 28th, 2004, 10:02 pm

Re: Dixie's Lua Thread

Post by silene » August 18th, 2010, 9:19 pm

Dixie wrote:So, any ideas about that while/do loop
I suggest not using [message] directly when programming in Lua. Take a look at LuaWML:Display#helper.get_user_choice. This function takes two tables. The first one contains the speaker= and caption= attributes. The second one is just an array of options. So your code would look like:

Code: Select all

local choices = {}
for i,v in ipairs(heroes) do
  ...
  table.insert(choices, string.format("&%s~SCALE(125,125)=<span weight='heavy'>%s</span>\nHPs:\t%d/%d\nTPs:\t%d/%d\nEXP:\t%d/%d", v.profile, v.name, v.hitpoints, v.max_hitpoints, v.experience, v.max_experience, misc[i].exp, misc[i].max_exp))
end
table.insert(choices, string.format("&%s=<span weight='heavy'>Return to game</span>", "icons/menus/back.png"))

while true do
  local result = helper.get_user_choice({speaker="narrator", caption="Main Menu"}, choices)
  if result > #heroes then break end
  -- do something otherwise
end

User avatar
Dixie
Posts: 1756
Joined: February 10th, 2010, 1:06 am
Location: $x1,$y1

Re: Dixie's Lua Thread

Post by Dixie » August 19th, 2010, 3:54 am

Oooh, nice! Thanks a lot! I must've missed it, all alone under all those (version 1.9 and later only)s! Seems like it has great potential, definitely better than wesnoth.fire ("message", {} ).

edit:

In light of my experiment and recent discoveries with helper.get_user_choice, I have decided to entirely rework my inventory referencing code (and the skills will likely follow). It must be like the 10th time, but boy did those 9 previous times make me learn, so it's all good.

So anyway, while I was at it, I decided to put myself to registering a wml handler to add/remove items from the inventory. I want my handler to have the following format:

Code: Select all

[manage_inventory]
    tonic=5
    potion=-2
[/manage_inventory]
The code should be taking each given keys, look up if they already exist in the inventory, create a new entry if needed and modifying it's amount according to the given value. Afterwards, if a given entry had an amount <= 0, the entry would be cleared. And I would prefer if the registered tag wouldn't limit the amount of keys. The inventory variable has this format, by the way:

Code: Select all

[inventory]
    [tonic]
        # A bunch of stats, including amount=
    [/tonic]
    [potion]
        # A bunch of stats, including amount=
    [/potion]
    # etc. for all items contained in the inventory
[/inventory]
So I have an actual problem, and a question I couldn't get to test and possibly answer because of said problem. Basically, the cfg part of wesnoth.register_wml_action("manage_inventory", function(cfg) ... end) is, as I understand it, userdata containing cfg.tonic=5 and cfg.potion=-2 (I am re-using the above example). So I wondered if there was a way access those key/values without limiting their numbers, dump the userdata in some way. It might be clearer if I show you the code I actually have (see the comment for more info):

Code: Select all

wesnoth.register_wml_action("manage_inventory", function(cfg)

	local inventory = wesnoth.get_variable("inventory")

-- At first, I had "for k,v in pairs(cfg) ...", but I got the error "bad argument #1 to 'pairs' (table expected, got nil)", that's what gave me the hint about the dump thing, and I tried the code below, but now I get the error "bad argument #1 to 'pairs' (table expected, got nil)". I thought about something with helper.get_variable_proxy_array, but I am not really sure how I'd use it in this context.

	local input = cfg.__cfg
	for k,v in pairs(input) do
		local key = helper.get_child(inventory, k)
		if not key then
			local key = fow_total_inventory[k]
			key.amount = 0
			key.equip = 0
			if #inventory < key.index then
				table.insert(inventory, { k, key })
			else
				table.insert(inventory, key.index, { k, key })
			end
		end
		local key = helper.get_child(inventory, k)
		key.amount = key.amount + v
		for itm in helper.child_range(inventory, k) do itm = nil end
	end
	wesnoth.set_variable("inventory", inventory)
	
end)
So, is this possible? If not, I'll fall back to having something like cfg.item = "item", cfg.amount = "amount", and modify a single item at a time, but it would have been quicker and cleaner, imo...

My second question is about clearing a child without knowing it's numerical index. since the lua wml_object of my inventory would be inventory = {{"tonic}, {amount=x, etc.}}, {"some other item", {amount=x, etc.}}, is the code I tried near the end (for itm in helper.child_range(inventory, k) do itm = nil end) a valid way of removing a child, which could be placed about anywhere in a numerous bunch of other children?

So hm, thanks again :)
Jazz is not dead, it just smells funny - Frank Zappa
Current projects: Internet meme Era, The Settlers of Wesnoth

silene
Posts: 1109
Joined: August 28th, 2004, 10:02 pm

Re: Dixie's Lua Thread

Post by silene » August 19th, 2010, 5:08 am

Dixie wrote:So, is this possible?
It is; just use the proper field: cfg.__parsed.
Dixie wrote:My second question is about clearing a child without knowing it's numerical index. since the lua wml_object of my inventory would be inventory = {{"tonic}, {amount=x, etc.}}, {"some other item", {amount=x, etc.}}, is the code I tried near the end (for itm in helper.child_range(inventory, k) do itm = nil end) a valid way of removing a child, which could be placed about anywhere in a numerous bunch of other children?
No, it won't work; you are just deleting the pointer, not the child itself. You have to look up for the absolute index of the child, and then remove it. Something like the following untested function:

Code: Select all

function remove_nth_child(cfg, name, n)
  for i, v in ipairs(cfg) do
    if v[1] == name then
      if n == 1 then
        table.remove(cfg, i)
        return
      end
      n = n - 1
    end
  end
end

Post Reply