enclave's Lua thread
Moderator: Forum Moderators
Re: enclave's Lua thread
Hi, sorry, could somebody tell me what is wrong with the simple following code:
It does the first cycle no problem, but for the second one it gives error saying: "bad argument #1 to '__index' (unknown unit)"
I tried change i to j, Bowman to Mage.. same thing.. I feel stupid.. what is wrong??
Code: Select all
ns_all_kings_stored = wesnoth.get_units { canrecruit = true }
for i=1,#ns_all_kings_stored,1 do
wesnoth.put_unit(ns_all_kings_stored[i].x,ns_all_kings_stored[i].y,{type="Spearman", side=i})
end
for i=1,#ns_all_kings_stored,1 do
wesnoth.put_unit(ns_all_kings_stored[i].x,ns_all_kings_stored[i].y,{type="Bowman", side=i})
end
I tried change i to j, Bowman to Mage.. same thing.. I feel stupid.. what is wrong??
Re: enclave's Lua thread
after the first loop the units in ns_all_kings_stored don't exit anymore since they have been overwritten with newly created units, so using them results in an error.
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.
Re: enclave's Lua thread
What would I need to use/do in lua to remove kings from map and then put them anywhere I like?gfgtdf wrote:after the first loop the units in ns_all_kings_stored don't exit anymore since they have been overwritten with newly created units, so using them results in an error.
Is there any alternative for WML [store_unit][/unstore_unit]? I tried to do
Code: Select all
ns_all_kings_stored = wesnoth.get_units { canrecruit = true }
ns_all_kings_stored2 = wesnoth.get_units { canrecruit = true }
It's very important in my code to have all kings off the map because I then use radius or distance to other leaders to create new random leader positions based on minimal distance specified in settings... I could use
wesnoth.fire("store_unit", {})
but I just don't believe that lua has no better alternative options...?Ah sorry, now I found copy and extract.. I will try them, thanks for your help!
Re: enclave's Lua thread
lua wesnoth.copy_unit only works for 1 single unit?? so I can not copy all leaders in 1 go into array?
- Pentarctagon
- Project Manager
- Posts: 5565
- Joined: March 22nd, 2009, 10:50 pm
- Location: Earth (occasionally)
Re: enclave's Lua thread
The name is copy_unit, not copy_units, so that is what I would assume. The wiki documentation also supports that.enclave wrote:lua wesnoth.copy_unit only works for 1 single unit?? so I can not copy all leaders in 1 go into array?
99 little bugs in the code, 99 little bugs
take one down, patch it around
-2,147,483,648 little bugs in the code
take one down, patch it around
-2,147,483,648 little bugs in the code
Re: enclave's Lua thread
This seems to have worked for me:
Wesnoth creators could maybe create a function to make everyone's life easier? something like that? It probably has 1000 mistakes, but the idea is there..
Thanks for attention and advices..
Code: Select all
ns_copy_kings = {}
ns_count_kings = wesnoth.get_units { canrecruit = true }
for i=1,#ns_count_kings,1 do
ns_copy_kings[i] = wesnoth.copy_unit(wesnoth.get_units({ canrecruit=true})[i])
end
for i=1,#ns_copy_kings,1 do
wesnoth.put_unit(ns_copy_kings[i].x,ns_copy_kings[i].y,{type="Spearman"})
end
for i=1,#ns_copy_kings,1 do
wesnoth.put_unit(ns_copy_kings[i].x,ns_copy_kings[i].y,ns_copy_kings[i])
end
Code: Select all
function wesnoth.store_unit(filter_to_apply,name_of_variable)
name_of_variable = {}
ns_count_filtered_units = wesnoth.get_units { filter_to_apply }
for i=1,#ns_count_filtered_units,1 do
name_of_variable[i] = wesnoth.copy_unit(wesnoth.get_units({ filter_to_apply})[i])
end
return name_of_variable
end
Re: enclave's Lua thread
you cna probably just writeenclave wrote:This seems to have worked for me:
Code: Select all
ns_copy_kings = {} ns_count_kings = wesnoth.get_units { canrecruit = true } for i=1,#ns_count_kings,1 do ns_copy_kings[i] = wesnoth.copy_unit(wesnoth.get_units({ canrecruit=true})[i]) end for i=1,#ns_copy_kings,1 do wesnoth.put_unit(ns_copy_kings[i].x,ns_copy_kings[i].y,{type="Spearman"}) end for i=1,#ns_copy_kings,1 do wesnoth.put_unit(ns_copy_kings[i].x,ns_copy_kings[i].y,ns_copy_kings[i]) end
wesnoth.extract_unit(ns_copy_kings[i])
instead of ns_copy_kings[i] = wesnoth.copy_unit(wesnoth.get_units({ canrecruit=true})[i])
in the loop, but then again i don't really see what's the point of temporatiyl replacing it with a spearman in the first place.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.
Re: enclave's Lua thread
It was just my step by step test of code.. Needed to see if it works.. spearman is no needed.. and leaders not needed..gfgtdf wrote:you cna probably just writewesnoth.extract_unit(ns_copy_kings[i])
instead ofns_copy_kings[i] = wesnoth.copy_unit(wesnoth.get_units({ canrecruit=true})[i])
in the loop, but then again i don't really see what's the point of temporatiyl replacing it with a spearman in the first place.
today is exhausting.. I tried to convert my WML into lua to make it work faster but I meet obstacles on a flat surface whole day... Now seems like all my codes work separate.. or at least most of them.. but when I put them together even wesnoth.fire with message doesnt work after some point.. for no obvious reason.
This code:
Code: Select all
local ns_all_kings_stored = {}
ns_count_kings = wesnoth.get_units { canrecruit = true }
for i=1,#ns_count_kings,1 do
ns_all_kings_stored[i] = wesnoth.copy_unit(wesnoth.get_units({ canrecruit=true })[i])
end
wesnoth.fire("message",{message="#ns_all_kings_stored "..#ns_all_kings_stored})
for j=1,#ns_all_kings_stored,1 do
wesnoth.put_unit(ns_all_kings_stored[j].x,ns_all_kings_stored[j].y)
end
wesnoth.fire("message",{message="whatever"})
Re: enclave's Lua thread
I have noticed that you need to wrap numbers in tostring() before adding them to string. Also, I would suggest wesnoth.message() for testing, rather than calling [message].
Re: enclave's Lua thread
Thanks Ravana, at least it shows me the message now with wesnoth.fire.. thats a good start.. In my other code I think I was misusing theRavana wrote:I have noticed that you need to wrap numbers in tostring() before adding them to string. Also, I would suggest wesnoth.message() for testing, rather than calling [message].
local ns_test_locations = wesnoth.get_locations { {"not", { terrain = "W*,W*^*,Xv,_off^_usr" } }}
Where later I was trying to call for x,y coordinates via
ns_test_locations[i].x
, I guess it gives nil and requires me to use ipairs instead?Re: enclave's Lua thread
Hi again!
Could anyone show me any semi-working example of how you would extract
How would I read the x,y and terrain of 1st element of this table? Thanks!
Ok so, nobody replied so far.. and while I was waiting I was trying to make it work.. and I found the following stuff..
1)
2) You can use it like so:
Where later if you need to know terrain, you could use
3) I have no idea how I could extract coordinates of this "table" at index 39.. I can only assume that it would be like so:
4) But I guess no matter what.. I MUST use for loop.. otherwise this thing just doesnt work...
5) I finally figured out how to make my code work and it works! But it was a proper nightmare...
Could anyone show me any semi-working example of how you would extract
x
,y
and terrain
from table created via local my_table = wesnoth.get_locations { {"not", { terrain = "W*,W*^*,Xv,_off^_usr" } }}
?How would I read the x,y and terrain of 1st element of this table? Thanks!
Ok so, nobody replied so far.. and while I was waiting I was trying to make it work.. and I found the following stuff..
1)
wesnoth.get_locations
only saves x and y nothing else.. that's why it is in "pairs".. could specify it somewhere in https://wiki.wesnoth.org/LuaWML/Tiles#w ... _locations just.. to.. save.. people's time looking for something that doesn't exist.2) You can use it like so:
Code: Select all
local table_of_pairs_of_x_and_y = wesnoth.get_locations { {"not", { terrain = "W*,W*^*,Xv,_off^_usr" } }}
for i, your_new_array_of_2_elements in ipairs(table_of_pairs_of_x_and_y) do
wesnoth.message("x="..your_new_array_of_2_elements[1]..",".."y="..your_new_array_of_2_elements[2])
end
wesnoth.get_terrain(x, y)
3) I have no idea how I could extract coordinates of this "table" at index 39.. I can only assume that it would be like so:
Code: Select all
local table_of_pairs_of_x_and_y = wesnoth.get_locations { {"not", { terrain = "W*,W*^*,Xv,_off^_usr" } }}
for i, your_new_array_of_2_elements in ipairs(table_of_pairs_of_x_and_y) do
if i==39 then
wesnoth.message("Coordinates of 39th element of a table: x="..your_new_array_of_2_elements[1]..",".."y="..your_new_array_of_2_elements[2])
end
end
5) I finally figured out how to make my code work and it works! But it was a proper nightmare...
Re: enclave's Lua thread
enclave wrote:Hi again!
Could anyone show me any semi-working example of how you would extractx
,y
andterrain
from table created vialocal my_table = wesnoth.get_locations { {"not", { terrain = "W*,W*^*,Xv,_off^_usr" } }}
?
How would I read the x,y and terrain of 1st element of this table? Thanks!
I'm bit late noticing this.
Depending on use case location_set could improve the code. You could use wesnoth.fire("store_locations",...) and then location_set:of_wml_var. But I don't have any code doing that.
Following code should be fairly simple example how to get same information as store_locations provides for wml.
Code: Select all
local location_list = wesnoth.get_locations { terrain = "!,W*,W*^*,Xv,_off^_usr" }
for i,loc in ipairs(location_list) do
local location_info = {
x=loc[1],
y=loc[2],
terrain=wesnoth.get_terrain(loc[1], loc[2]),
} -- This would need to be inserted to table if processing requires more than single for loop
end
--Specific location can be read using array indexing like
local nth_location = {x=location_list[n][1], y=location_list[n][2]}
Code: Select all
local function highlight_ranged_enemies(unit)
local fn = "highlight_ranged_enemies"
clear_ranged_enemies()
if not unit then
ns.err(fn .. " nil unit passed")
return false
end
-- Check if adjacent enemy blocks ranged attacks
local adjenemies = wesnoth.match_location(unit.x, unit.y,
{ ns.WT.filter {
ns.WT.filter_adjacent {
is_enemy=true,
}
}})
if adjenemies then
-- There is adjacent enemy
ns.debug(fn .. " adjacent enemy blocks")
return false
end
-- Filter impassable terrains
local impassable_terrains = "!,Xv,*^Xo,*^Qov,*^_fme,_off^*,Xo*,Xu*,M*^Xm"
-- Get enemies inside range
local enemies = wesnoth.get_locations({
ns.WT['and'] {
x=unit.x, y=unit.y, radius=unit.variables.range,
ns.WT.filter_radius {
terrain=impassable_terrains,
},
},
ns.WT['and'] {
ns.WT.filter {
ns.WT.filter_side {
ns.WT.enemy_of {
side=unit.side,
}
}
}
}
})
if not enemies[1] then
-- No enemies in range -> no highlight
ns.debug(fn .. " No enemies in range")
return false
end
wesnoth.add_tile_overlay(unit.x, unit.y, { image=selectoverlay })
wesnoth.set_variable(selectedunit, {x=unit.x, y=unit.y})
for i, e in ipairs(enemies) do
wesnoth.add_tile_overlay(e[1], e[2], { image=enemyoverlay })
-- Make wml variable array that works in find_in filter in set_menu_item filter_location
wesnoth.set_variable(string.format("%s[%d]",enemylocation,i-1),
{x=e[1], y=e[2]})
end
ns.WA.redraw {}
return true
end
Inline lua code in wml files is nightmare to debug because wesnoth produces horrible debug messages for them. It even fails to report many parsing errors for inline lua code. That why I simple made a helper macro to load lua code with wesnoth.dofile when running wesnoth in debug mode (-d command line parameter)enclave wrote:5) I finally figured out how to make my code work and it works! But it was a proper nightmare...
Code: Select all
#define NS_LUA_DOFILE FILE
[lua]
#ifdef DEBUG_MODE
code = "wesnoth.dofile ""{FILE}"""
#else
code = {{FILE}}
#endif
[/lua]
#enddef
#define NS_LUA_MAIN
# Lua code loaded and run from era top level if wesnoth 1.13
# Older wesnoth requires era code to use preload
#ifver WESNOTH_VERSION < 1.13.0
[event]
name=preload
first_time_only=no
#endif
{NS_LUA_DOFILE (~add-ons/New_Settlers/lua/lua/main.lua)}
#ifver WESNOTH_VERSION < 1.13.0
[/event]
#endif
#enddef
Code: Select all
--<<
Any lua code can be put here
-->>
Re: enclave's Lua thread
Thanks Shrieker1, all that you have wrote here is quite high above my level of understanding wesnoth coding languages, but thanks anyway!
Re: enclave's Lua thread
Hello, could anyone tell me what is the best way to message users while in the loop?
I have a loop in my code and I tried to put wesnoth.message and wesnoth.fire("print"), but all the messages appear after the loop has been finished, which makes no sense to my idea of how it should be.
I'm generating random prestart things in lua and I would like users to be informed of progress (otherwise if it's long they may think that it's a big lag and just close wesnoth), but for some reason messages are executed last.. when loop is finished.. Any ideas?
My particular code example inside spoiler (if it makes any difference):
I'm thinking maybe I need to add another loop inside loop to make messages show.. or something..?
I have a loop in my code and I tried to put wesnoth.message and wesnoth.fire("print"), but all the messages appear after the loop has been finished, which makes no sense to my idea of how it should be.
I'm generating random prestart things in lua and I would like users to be informed of progress (otherwise if it's long they may think that it's a big lag and just close wesnoth), but for some reason messages are executed last.. when loop is finished.. Any ideas?
My particular code example inside spoiler (if it makes any difference):
Code: Select all
for i, ns_pairs_locations in ipairs(ns_test_locations) do
if ns_king_rand_start_counter<ns_all_kings_stored_length then
local ns_test_inner_locations = wesnoth.match_location(ns_pairs_locations[1], ns_pairs_locations[2], { radius=ns_min_dist , { "filter", { canrecruit=true } } })
if ns_test_inner_locations == false then
local ns_test_inner_locations_water_radius1 = wesnoth.match_location(ns_pairs_locations[1],ns_pairs_locations[2], { { "filter_adjacent_location", {terrain = "W*,W*^*,Xv,_off^_usr"} } })
if ns_test_inner_locations_water_radius1 == false then
local ns_store_inner_locations = wesnoth.get_locations { {"not", { terrain = "W*,W*^*,Xv,_off^_usr" }}, {"and", { x=ns_pairs_locations[1],y=ns_pairs_locations[2],radius=4 }}, {"and", { {"not", { x="0,"..tostring(w) }}}}, {"and", { {"not", { y="0,"..tostring(h) }}}} }
if #ns_store_inner_locations>=ns_min_island then
local arg2 = wesnoth.get_variable("ns_all_kings_stored.length")-1
local ns_rand_leader = math.random(0,arg2)
ns_rand_leader = wesnoth.synchronize_choice(function() return { value = ns_rand_leader } end).value
wesnoth.message("Attempt to shuffle sides with minimal distance "..ns_min_dist..":"..ns_king_rand_start_counter)
wesnoth.fire("unstore_unit",{animate=no,x=ns_pairs_locations[1],y=ns_pairs_locations[2],variable="ns_all_kings_stored["..tostring(ns_rand_leader).."]"})
-- wesnoth.fire("unstore_unit",{animate=no,x=ns_pairs_locations[1],y=ns_pairs_locations[2],variable="ns_all_kings_stored["..ns_king_rand_start_counter.."]"})
wesnoth.fire("clear_variable",{name="ns_all_kings_stored["..tostring(ns_rand_leader).."]"})
ns_king_rand_start_counter = ns_king_rand_start_counter + 1
end
end
end
end
end
Last edited by Ravana on September 13th, 2017, 10:57 pm, edited 1 time in total.
Reason: [code] does not look nice in [spoiler]
Reason: [code] does not look nice in [spoiler]
Re: enclave's Lua thread
Sorry I found answer to my question.. for some reason
wesnoth.delay(500)
after message has worked very well! I guess if i decrease it from 500 into 1 it will work same well.. Thanks everyone for attention.. However I'm not sure if this way it is the most efficient, so if anyone knows better way? Then please reply.