monochromatic's lua thread

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

Moderator: Forum Moderators

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

Re: elvish_sovereign and Lua

Post by Anonymissimus »

1. yes
2. yes
3. right
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
monochromatic
Posts: 1549
Joined: June 18th, 2009, 1:45 am

Re: elvish_sovereign and Lua

Post by monochromatic »

What do you mean by "right"?
Anonymissimus
Inactive Developer
Posts: 2461
Joined: August 15th, 2008, 8:46 pm
Location: Germany

Re: elvish_sovereign and Lua

Post by Anonymissimus »

(Isn't that clear ?)
It means I didn't notice the radius issue when glancing over your code.
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
monochromatic
Posts: 1549
Joined: June 18th, 2009, 1:45 am

Re: elvish_sovereign and Lua

Post by monochromatic »

OH :doh: of course. Somehow I didn't interpret it that way... Strange.
User avatar
Elvish_Hunter
Posts: 1575
Joined: September 4th, 2009, 2:39 pm
Location: Lintanir Forest...

Re: elvish_sovereign and Lua

Post by Elvish_Hunter »

elvish_sovereign wrote:

Code: Select all

while placed_units < number do
		...
		placed_units = placed_units + 1
	end
end
You may be interested to know that such while ... do cycle could be replaced with a repeat ... until cycle. :) Untested, but it will look like this:

Code: Select all

repeat
		...
		placed_units = placed_units + 1
	until  placed_units >= number
end
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)
monochromatic
Posts: 1549
Joined: June 18th, 2009, 1:45 am

Re: elvish_sovereign and Lua

Post by monochromatic »

Hm..interesting. Would repeat be processed faster or would while be processed faster?
User avatar
pauxlo
Posts: 1047
Joined: September 19th, 2006, 8:54 pm

Re: elvish_sovereign and Lua

Post by pauxlo »

The main difference between the both forms (pre-condition loop and post-condition loop) is that the second one always executes at least one time (before the condition is first tested), while the second one may not execute at all (if the condition is false at the beginning).

I think any speed differences would be marginal.
monochromatic
Posts: 1549
Joined: June 18th, 2009, 1:45 am

Re: elvish_sovereign and Lua

Post by monochromatic »

:!: This post is not valid anymore. See below.
Last edited by monochromatic on January 21st, 2011, 6:42 pm, edited 1 time in total.
monochromatic
Posts: 1549
Joined: June 18th, 2009, 1:45 am

Re: elvish_sovereign and Lua

Post by monochromatic »

So this is not working, and I can't seem to quite figure out what's wrong. The stderr is saying something about the helper.rand functions, but I'm not getting it. Could someone help me?

Code: Select all

helper = wesnoth.require "lua/helper.lua"

function wesnoth.wml_actions.scatter_units(cfg)
	-- replacement for macro SCATTER_UNITS
	local filter = ( helper.get_child( cfg , "filter" ))
	local side = cfg.side or helper.wml_error("Missing required 'side' attribute in [scatter_units]")
	local type = cfg.type or helper.wml_error("Missing required 'type' attribute in [scatter_units]")
	local number = cfg.number or helper.wml_error("Missing required 'number' attribute in [scatter_units]")
	-- radius separating units, default 1
	local padding_radius = cfg.padding_radius or "1"
	local unit_wml = ( helper.get_child( cfg, "unit_modifications" ))

	local placed_units = 0
	local possible_locations = wesnoth.get_locations(filter)

	while placed_units < number do
		local rand_position = helper.rand("1..#possible_locations")
		wesnoth.put_unit( possible_locations[rand_position][1] , possible_locations[rand_position][2] , { type = helper.rand("cfg.type") , side = cfg.side , unit_wml })
		local possible_locations = wesnoth.get_locations( filter_location , { "not" , { possible_locations[rand_position][1] , possible_locations[rand_position][2] , radius = padding_radius } })
		placed_units = placed_units + 1
	end
end
Its usage should be (if it works):

Code: Select all

[scatter_units]
    [filter]
        # SLF
    [/filter]
    side = # unit side
    type = # list of unit type(s)
    number = # number of units
    padding_radius = # amount of hexes between placed units
    [unit_modifications]
        # unit modifications
    [/unit_modifications]
[/scatter_units]
Thanks again!
Last edited by monochromatic on January 21st, 2011, 7:22 pm, edited 1 time in total.
Luther
Posts: 128
Joined: July 28th, 2007, 5:19 pm
Location: USA

Re: elvish_sovereign and Lua

Post by Luther »

1. You seem to be using some unnecessary quotes. It's OK to quote WML variables, since they're not related to Lua syntax, but Lua variable names should never be quoted.

2. Change this:

Code: Select all

local rand_position = helper.rand("1..#possible_locations")
to this:

Code: Select all

local rand_position = helper.rand('1..' .. #possible_locations)
The first '..' is needed by rand to know that you're passing a range. The second '..' is Lua's string concatenation operator.

You can simplify it even further like so:

Code: Select all

local rand_position = possible_locations[helper.rand('1..' .. #possible_locations)]
That way, you can refer to 'rand_position[1]' and so on.
monochromatic
Posts: 1549
Joined: June 18th, 2009, 1:45 am

Re: elvish_sovereign and Lua

Post by monochromatic »

It's still not working :hmm: Here's the revised code:

Code: Select all

helper = wesnoth.require("lua/helper.lua")

function wesnoth.wml_actions.scatter_units(cfg)
	-- replacement for macro SCATTER_UNITS
	local filter = ( helper.get_child( cfg , "filter" ))
	local side = cfg.side or helper.wml_error("Missing required 'side' attribute in [scatter_units]")
	local type = cfg.type or helper.wml_error("Missing required 'type' attribute in [scatter_units]")
	local number = cfg.number or helper.wml_error("Missing required 'number' attribute in [scatter_units]")
	-- radius separating units, default 1
	local padding_radius = cfg.padding_radius or 1
	local unit_wml = ( helper.get_child( cfg, "unit_modifications" ))

	local placed_units = 0
	local possible_locations = wesnoth.get_locations(filter)

	while placed_units < number do
		local rand_position = possible_locations[helper.rand('1..' .. #possible_locations)]
		wesnoth.put_unit( rand_position[1] , rand_position[2] , { type = helper.rand(cfg.type) , side = cfg.side , unit_wml })
		local possible_locations = wesnoth.get_locations( filter_location , { "not" , { rand_position[1] , rand_position[2] , radius = padding_radius } })
		placed_units = placed_units + 1
	end
end
@Luther you said I have some unnecessary quotes? Could explain that a little bit? Because I'm not quite sure which quotes you are talking about.
silene
Posts: 1109
Joined: August 28th, 2004, 10:02 pm

Re: elvish_sovereign and Lua

Post by silene »

elvish_sovereign wrote:It's still not working :hmm: Here's the revised code:

Code: Select all

local possible_locations = wesnoth.get_locations( filter_location , { "not" , { rand_position[1] , rand_position[2] , radius = padding_radius } })
This line at least contains several errors. First it starts with "local", which means that it defines a fresh new variable that is not the one previously defined. Second, your filter is broken. You are passing two arguments, while wesnoth.get_locations expects only one. And even if both arguments were part of the filter, you would still have issues, since it is missing things like "x = " and "y = ".

The code should rather look like

Code: Select all

local i = helper.rand('1..' .. #possible_locations)
local pos = possible_locations[i]
... do something with pos ...
table.remove(possible_locations, i)
By the way, you will have the same issue with the table you are passing to put_unit. (Don't you have some error message stating that you are passing something that is not a WML table to wesnoth.put_unit?) You can't concat two WML tables by just putting one next to the other. So it should look like

Code: Select all

unit_wml.type = helper.rand(cfg.type)
unit_wml.side = cfg.side
wesnoth.put_unit(pos[1], pos[2], unit_wml)
Luther
Posts: 128
Joined: July 28th, 2007, 5:19 pm
Location: USA

Re: elvish_sovereign and Lua

Post by Luther »

Ninja'd, but this might make it more clear. :)

You'll need to combine type= and side= with unit_wml to make a single table.

Code: Select all

local unit_wml = helper.get_child( cfg, "unit_modifications" ) or {}
unit_wml.side = cfg.side

--Then, inside the loop:
unit_wml.type = helper.rand(cfg.type)
wesnoth.put_unit( rand_position[1] , rand_position[2] , unit_wml)
elvish_sovereign wrote: @Luther you said I have some unnecessary quotes? Could explain that a little bit? Because I'm not quite sure which quotes you are talking about.
It looks like you fixed it. Think of it this way: The string 'I am a string.' and the number 84 are both raw data that can be stored in a Lua variable. If you type them out explicitly in a program they're called literals. If you type a word without quotes, Lua will evaluate it as a variable.

Remember that Lua doesn't directly know about WML variables and tag names, so you often have to refer them with string literals. This problem can be mostly circumvented by the tools provided by Wesnoth. Please see my other thread.
monochromatic
Posts: 1549
Joined: June 18th, 2009, 1:45 am

Re: elvish_sovereign and Lua

Post by monochromatic »

Making up code seems to be my specialty. :mrgreen:
silene wrote:
elvish_sovereign wrote:It's still not working :hmm: Here's the revised code:

Code: Select all

local possible_locations = wesnoth.get_locations( filter_location , { "not" , { rand_position[1] , rand_position[2] , radius = padding_radius } })
This line at least contains several errors. First it starts with "local", which means that it defines a fresh new variable that is not the one previously defined. Second, your filter is broken. You are passing two arguments, while wesnoth.get_locations expects only one. And even if both arguments were part of the filter, you would still have issues, since it is missing things like "x = " and "y = ".

The code should rather look like

Code: Select all

local i = helper.rand('1..' .. #possible_locations)
local pos = possible_locations[i]
... do something with pos ...
table.remove(possible_locations, i)
cool! But how would you factor in the padding_radius? That's why I hesitated in using table.remove.
By the way, you will have the same issue with the table you are passing to put_unit. (Don't you have some error message stating that you are passing something that is not a WML table to wesnoth.put_unit?) You can't concat two WML tables by just putting one next to the other. So it should look like

Code: Select all

unit_wml.type = helper.rand(cfg.type)
unit_wml.side = cfg.side
wesnoth.put_unit(pos[1], pos[2], unit_wml)
OH. I get it. Gosh, should have known better...
Luther wrote:Ninja'd, but this might make it more clear. :)

You'll need to combine type= and side= with unit_wml to make a single table.

Code: Select all

local unit_wml = helper.get_child( cfg, "unit_modifications" ) or {}
unit_wml.side = cfg.side

--Then, inside the loop:
unit_wml.type = helper.rand(cfg.type)
wesnoth.put_unit( rand_position[1] , rand_position[2] , unit_wml)
elvish_sovereign wrote: @Luther you said I have some unnecessary quotes? Could explain that a little bit? Because I'm not quite sure which quotes you are talking about.
It looks like you fixed it. Think of it this way: The string 'I am a string.' and the number 84 are both raw data that can be stored in a Lua variable. If you type them out explicitly in a program they're called literals. If you type a word without quotes, Lua will evaluate it as a variable.

Remember that Lua doesn't directly know about WML variables and tag names, so you often have to refer them with string literals. This problem can be mostly circumvented by the tools provided by Wesnoth. Please see my other thread.
Awesome! Will look at that later.
silene
Posts: 1109
Joined: August 28th, 2004, 10:02 pm

Re: elvish_sovereign and Lua

Post by silene »

elvish_sovereign wrote:cool! But how would you factor in the padding_radius? That's why I hesitated in using table.remove.
Right, you can't. So you indeed have to use get_locations and you are back to how to concat WML tables. Here is a way to do it in your case:

Code: Select all

possible_locations = wesnoth.get_locations { { "and", filter }, { "not" , { x = pos[1] , y = pos[2] , radius = padding_radius } } }
Note that it might not do what you wanted: it removes only the tiles around the last unit, not the ones around all the units.

Another possibility would be to use location_set:

Code: Select all

local location_set = wesnoth.require "lua/location_set.lua"
local possible_locations = location_set.of_pairs(wesnoth.get_locations(filter))
while ...
  local pos = possible_locations:to_stable_pairs()[helper.rand('1..' .. possible_locations:size()]
  local ux,uy = pos[1],pos[2]
  ... put_unit ...
  possible_locations = possible_locations:filter(function(x,y) return helper.distance_between(ux, uy, x, y) > padding_radius end)
end
Post Reply