Crendgrim's Lua Thread

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

Moderators: Forum Moderators, Developers

User avatar
Crendgrim
Moderator Emeritus
Posts: 1328
Joined: October 15th, 2010, 10:39 am
Location: Germany

Re: Crendgrim's Lua Thread

Post by Crendgrim » August 17th, 2011, 4:29 pm

Ah, maybe that's it, Luther. Now I'll test why I tried helper.get_variable_proxy_array at all (there was some kind of other bug before). Thanks :)

On an unrelated note, but this bugs me as well: Is there any way to store all [item]s on the map?


Crend
UMC Story Images — Story images for your campaign!

Anonymissimus
Inactive Developer
Posts: 2458
Joined: August 15th, 2008, 8:46 pm
Location: Germany

Re: Crendgrim's Lua Thread

Post by Anonymissimus » August 17th, 2011, 4:34 pm

Luther wrote:My guess is that the proxy table needs special non-WML data in order to work, hence the incorrect element 1. Maybe you could use helper.get_variable_array instead of get_variable_proxy_array.

Ninja'd, but am I right?
Almost I think. Untested:

Code: Select all

function wml_actions.cg_inv_add(cfg)
  local id = cfg.id or helper.wml_error("Missing required id= attribute in [cg_inv_add]")
  local name = cfg.name or helper.wml_error("Missing required name= attribute in [cg_inv_add]")
  local image = cfg.image or helper.wml_error("Missing required image= attribute in [cg_inv_add]")
  local description = cfg.description or helper.wml_error("Missing required description= attribute in [cg_inv_add]")

  local item = wesnoth.create_unit { type = "CG Item", id = id, name = name, image = image, description = description }
  -- yes, it's a unit type I want to store

  local debug_utils = wesnoth.require("~add-ons/Wesnoth_Lua_Pack/debug_utils.lua")

  local inventory = helper.get_variable_array "cg_inventory"
  wesnoth.set_variable "qow_inventory"
  table.insert(inventory, item.__cfg )
  debug_utils.dbms(inventory)
  -- and here is the weird thing:
  -- in the first tag call, dbms will verify that it's a WML table, but in the second call not.
  -- however, in both cases there is an error with the following command
  helper.set_variable_array("cg_inventory", inventory)

end
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
Crendgrim
Moderator Emeritus
Posts: 1328
Joined: October 15th, 2010, 10:39 am
Location: Germany

Re: Crendgrim's Lua Thread

Post by Crendgrim » August 17th, 2011, 5:01 pm

Yes, that works!
Thanks a lot :)


Crend
UMC Story Images — Story images for your campaign!

User avatar
Crendgrim
Moderator Emeritus
Posts: 1328
Joined: October 15th, 2010, 10:39 am
Location: Germany

Re: Crendgrim's Lua Thread

Post by Crendgrim » January 14th, 2012, 10:49 am

Okay, I'm back with another problem.
I'm trying to translate the ugly WML mess into Lua code, and right now I'm at the dynamic map change in my add-on. However, I've got the problem now that I need to read a plain text file with Lua. Is there *any* way to do so without the io library available, or do I have to use some workaround?

EDIT: Okay, I used a (ugly) workaround: I am now reading all map files at startup and save them to a WML container.
UMC Story Images — Story images for your campaign!

Exasperation
Posts: 462
Joined: June 8th, 2006, 3:25 am

Re: Crendgrim's Lua Thread

Post by Exasperation » January 14th, 2012, 9:55 pm

You pretty much have to use some workaround. The workaround I used in Wesband was to convert all of the mapfiles that would need to be dynamically loaded (masks and the like) into Lua files like so:

Code: Select all

return [=[
border_size=0
usage=mask

_f, _f, _f, _f, _f, _f, _f, _f, _f, _f, _f, Aa, _f
_f, _f, _f, _f, _f, _f, _f, _f, _f, Aa, Aa, Aa, Aa
_f, _f, _f, _f, _f, _f, _f, Aa, Aa, Aa, Aa, Aa, Aa
_f, _f, _f, _f, _f, Aa, Aa, Aa, Aa, Aa, Aa, _f, _f
_f, _f, _f, Aa, Aa, Aa, Aa, Aa, Aa, _f, _f, _f, _f
_f, Aa, Aa, Aa, Aa, Aa, Aa, _f, _f, _f, _f, _f, _f
Aa, Aa, Aa, Aa, Aa, _f, _f, _f, _f, _f, _f, _f, _f
Aa, Aa, Aa, _f, _f, _f, _f, _f, _f, _f, _f, _f, _f
]=]
Then the following Lua would dynamically load the map data, without having to read in all the map files whether they're needed or not.

Code: Select all

local mask_data = wesnoth.dofile("~/add-ons/add-on-name/masks/mask-name.lua")

User avatar
Crendgrim
Moderator Emeritus
Posts: 1328
Joined: October 15th, 2010, 10:39 am
Location: Germany

Re: Crendgrim's Lua Thread

Post by Crendgrim » January 14th, 2012, 10:24 pm

The problem about that is that I'm not able anymore to directly edit the map in the Wesnoth editor.
Now I'm using something like the following:

Code: Select all

  [lua_tag]
    map="{~add-ons/MyAddon/maps/dynamicmap.map}"
  [/lua_tag]
This I do for all maps I have and save them with their respective keys in a WML container. Not the best solution, but it works.
UMC Story Images — Story images for your campaign!

Exasperation
Posts: 462
Joined: June 8th, 2006, 3:25 am

Re: Crendgrim's Lua Thread

Post by Exasperation » January 14th, 2012, 10:42 pm

Yeah, you have to paste the map in and out of files to edit it. For me, that's a better trade-off than having to load all the maps regardless of whether they're used or not, but that depends on how often you need to edit your maps.

Anonymissimus
Inactive Developer
Posts: 2458
Joined: August 15th, 2008, 8:46 pm
Location: Germany

Re: Crendgrim's Lua Thread

Post by Anonymissimus » January 14th, 2012, 11:03 pm

Exasperation wrote:Yeah, you have to paste the map in and out of files to edit it. For me, that's a better trade-off than having to load all the maps regardless of whether they're used or not, but that depends on how often you need to edit your maps.
However, a major drawback of loading maps like wesnoth.dofile("~/add-ons/add-on-name/masks/mask-name.lua") is that every client in the game is required to have the file/the addon, while Crendgrim's map loading also works if the remote client doesn't have the file. Important for "no download needed" mode. 8)
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

Exasperation
Posts: 462
Joined: June 8th, 2006, 3:25 am

Re: Crendgrim's Lua Thread

Post by Exasperation » January 14th, 2012, 11:55 pm

Well, since it's loaded as a string, you could just do something like

Code: Select all

function get_dynamic_map_data(map_file) 
    return wesnoth.synchronize_choice(function() return { map_data = wesnoth.dofile(map_file) } end).map_data
end

mask_data = get_dynamic_map_data("~/add-ons/add-on-name/masks/mask-name.lua")
and ta-da, the map data is sent to the other clients.

Not an issue with Wesband, since all clients need to have it for the custom graphics anyway, but not a terribly difficult fix.

Anonymissimus
Inactive Developer
Posts: 2458
Joined: August 15th, 2008, 8:46 pm
Location: Germany

Re: Crendgrim's Lua Thread

Post by Anonymissimus » January 15th, 2012, 12:10 am

That does indeed work, but
-Only for strings, it wouldn't work for arbitrary lua files, which would return a table with functions and such. I imagine one could create a complicated workaround involving loadstring() though.
-It's only executed on the active client, so to load a map like this, you would need a full game turn and try to load the map on each of the clients (in a side turn event). At least one of the clients should have the file (the host). And one usually doesn't know which side is the host. After that game turn is over, one can start using the map/the data.
-Only in events >= turn 1 since sync_choice fails earlier.
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
Crendgrim
Moderator Emeritus
Posts: 1328
Joined: October 15th, 2010, 10:39 am
Location: Germany

Re: Crendgrim's Lua Thread

Post by Crendgrim » January 22nd, 2012, 8:52 am

So, I'm back yet again with another problem. This time, I started using Lua/GUI2 to create a shinier quest log for my add-on. However, I'm stuck at implementing a scrollable area which consists of the quests. The documentation in the wiki doesn't really help me here.

The lines in question are the following:

Code: Select all

  local dialogue = {
    T.helptip { id = "tooltip_large" }, -- mandatory field
    T.tooltip { id = "tooltip_large" }, -- mandatory field
    maximum_height = 320,
    maximum_width = 480,
    T.grid {
      T.row { T.column { vertical_alignment = "center", horizontal_alignment = "center", border = "all", border_size = 5, T.label { id = "title" } } },
      T.row { T.column { open_closed_quests_buttons } },
      T.row { T.column { T.scrollbar_panel { definition = "scroll_quests", T.grid(quest_list) } } },
      T.row { T.column { T.button { id = "close_button", return_value = 1 } } },
    }
  }
quest_list is an array which consists of multiple rows, one per quest.
If I remove the line with the scrollbar_panel, the dialogue is displayed. If I only remove the scrollbar_panel and put the grid directly inside the column, it works as well. However, I have no idea how to use the scrollbar_panel correctly. The way I posted above it gives me the following message:

Code: Select all

20120122 09:49:31 error general: An error due to possibly invalid WML occurred
The error message is :
No list defined.
 
When reporting the bug please include the following error message :
Condition 'definition' failed at src/gui/auxiliary/window_builder/scrollbar_panel.cpp:42 in function 'tbuilder_scrollbar_panel'.
It's probably a very simple problem, but I don't understand GUI2 enough to see what's wrong there. I even might have had a better code, but I tried really a lot and don't remember anymore what exactly.

Any help would be very appreciated. :)
UMC Story Images — Story images for your campaign!

User avatar
Elvish_Hunter
Forum Moderator
Posts: 1394
Joined: September 4th, 2009, 2:39 pm
Location: Lintanir Forest...

Re: Crendgrim's Lua Thread

Post by Elvish_Hunter » January 22nd, 2012, 10:41 am

In T.scrollbar_panel, definition= must not be a string, but it must be the grid for one row of the list. Remove "scroll_quests" and try putting quest_list between {} instead of (). If you put here also the code of quest_list, it will be useful. :)
Current maintainer of these add-ons:
1.14: The Sojournings of Grog, A Rough Life, The White Troll (co-author), Wesnoth Lua Pack
1.12: Children of Dragons

User avatar
Crendgrim
Moderator Emeritus
Posts: 1328
Joined: October 15th, 2010, 10:39 am
Location: Germany

Re: Crendgrim's Lua Thread

Post by Crendgrim » January 23rd, 2012, 12:24 pm

Elvish_Hunter wrote:In T.scrollbar_panel, definition= must not be a string, but it must be the grid for one row of the list. Remove "scroll_quests" [...]
How do I do this, then? I tried some things (from removing the definition= completely to creating a subtag [definition]), but I don't really understand what I am supposed to do.
Do you have a code example?
Elvish_Hunter wrote:[...] and try putting quest_list between {} instead of (). If you put here also the code of quest_list, it will be useful. :)
I doubt it works then:
quest_list is an array consisting of rows which is dynamically generated:
(code simplified, I actually test the quest before adding it, but here's not the problem: the array gets properly populated)

Code: Select all

  local quest_list = {}
  local quests = helper.get_variable_array "qow_quest"
  for index = 1, #quests, 1 do
    table.insert(quest_list, T.row {
      T.column { horizontal_alignment = "right", border = "all", border_size = 5, T.label { label = quests[index].name } },
      T.column { horizontal_alignment = "left", border = "all", border_size = 5, T.button { return_value = index + 3, label = tostring( _"Details") } }
    })
  end
UMC Story Images — Story images for your campaign!

Exasperation
Posts: 462
Joined: June 8th, 2006, 3:25 am

Re: Crendgrim's Lua Thread

Post by Exasperation » January 23rd, 2012, 7:20 pm

I think what you actually want is a [listbox], which is a specialized form of a [scrollbar_panel]. For example, you could do something like the following (simplified version of your dialog, but including usage of list_definition and list_data):

Code: Select all

local quest_list = {}
local quests = helper.get_variable_array "qow_quest"
for index = 1, #quests do
	table.insert(quest_list, T.row { T.column { label = quests[index].name } })
end
local dialog = {
	T.helptip { id = "tooltip_large" }, -- mandatory field
	T.tooltip { id = "tooltip_large" }, -- mandatory field
	T.linked_group { id = "labels", fixed_width = "yes" },
	maximum_height = 320,
	maximum_width = 480,
	T.grid {
		T.row { T.column { T.listbox { id = "scroll_quests",
			T.list_definition { T.row { T.column { T.toggle_button { definition = "listbox_text", linked_group = "labels" } } } },
			T.list_data(quest_list)
		} } },
		T.row { T.column { T.scroll_label { id = "quest_details", label = "", linked_group = "labels" } } },
		T.row { T.column { T.button { id = "close_button", return_value = 1, label = "Close" } } }
	}
}
local function preshow()
	local function display_selected_quest_details()
		local i = wesnoth.get_dialog_value("scroll_quests")
		wesnoth.set_dialog_value(quests[i].details, "quest_details")
	end
	wesnoth.set_dialog_callback(display_selected_quest_details, "scroll_quests")
end

User avatar
Crendgrim
Moderator Emeritus
Posts: 1328
Joined: October 15th, 2010, 10:39 am
Location: Germany

Re: Crendgrim's Lua Thread

Post by Crendgrim » January 24th, 2012, 3:03 pm

... Awesome! That works very nice!
Thanks a lot, Exasperation :)

Now I do have a little problem, though. If I use your approach and "quests.details" is a t_string with more than 65 characters, Wesnoth crashes for me. Can anyone confirm this?
I don't have a testcase yet (and thus no bug report on gna), as I still try to find the actual cause and see when it crashes and when it doesn't.

Crash message:

Code: Select all

wesnoth: src/gui/widgets/grid.cpp:542: virtual void gui2::tgrid::place(const gui2::tpoint&, const gui2::tpoint&): Assertion `false' failed.
UMC Story Images — Story images for your campaign!

Post Reply