[engine] Design of [query_location]
Moderator: Forum Moderators
Forum rules
Before posting a new idea, you must read the following:
Before posting a new idea, you must read the following:
- Celtic_Minstrel
- Developer
- Posts: 2207
- Joined: August 3rd, 2012, 11:26 pm
- Location: Canada
- Contact:
Re: [engine] Design of [query_location]
Yeah, that's why I think something other than a click would be better for finishing early. Alternatively, you could maybe try a different mouse button? (ie right-click to finish early, all left-clicks either select or deselect)
Re: [engine] Design of [query_location]
I don't think so. There are many conceivable use cases where any map hex is valid. Therefore, there's no good reason to force the author to write that empty tag out.Ravana wrote: I guess normal use cases would add at least some filter, so might be worth logging notice that filter is expected.. like [kill] should warn if [filter] encountered.
http://www.wesnoth.org/wiki/User:Sapient... "Looks like your skills saved us again. Uh, well at least, they saved Soarin's apple pie."
Re: [engine] Design of [query_location]
Is there way to catch rightclick event with Lua?
Re: [engine] Design of [query_location]
Seems that all below only applies when there is another query_location in current execution queue. Still, without way to detect control changes I dont think I can avoid such problem.
Current code with some more debug messages about control change issue
Problems then
Code: Select all
--<<
-- Parameters
-- [filter_location] location filter - error if matches no location, if missing matches all locations
-- max_count - optional default 1, how many locations player may select, not allowed to be 0, not allowed to be less than min_count
-- min_count - optional default 1, how many locations player needs to select
-- allow_fog - optional default false
-- allow_shroud - optional default false. If you allow both shroud and fog here, you can include custom vision location filter
-- variable - WML variable for result - optional default location
-- confirm_message - optional, if used then there is dialog to finish selection, with min_count=0 cancel, reseting selection
-- overlay_selected, overlay_selectable, overlay_unselectable - custom overlay - optional, use "" to not display
-- overlay_message - optional printed while selecting
function wesnoth.wml_actions.query_location(cfg)
local is_choosing_side = wesnoth.sides[wesnoth.current.side].is_local
wesnoth.message("Im local: "..tostring(is_choosing_side))
local _ = wesnoth.textdomain "wesnoth"
local variable = cfg.variable or "location"
local helper = wesnoth.require "lua/helper.lua"
-- local utils = wesnoth.require "lua/wml-utils.lua"
local T = helper.set_wml_tag_metatable {}
local location_set = wesnoth.require "lua/location_set.lua"
-- local overlay_choosable = cfg.overlay_selectable or "terrain/alphamask.png~O(0.2)~CS(255,255,0)"
local overlay_choosable = cfg.overlay_selectable or "misc/hover-hex.png"
-- local overlay_chosen = cfg.overlay_selected or "terrain/alphamask.png~O(0.2)~CS(0,255,0)"
local overlay_chosen = cfg.overlay_selected or "misc/blank-hex.png~BLIT(misc/hover-hex-enemy-bottom.png)~BLIT(misc/hover-hex-enemy-top.png)"
local overlay_unselectable = cfg.overlay_unselectable or "terrain/alphamask.png~O(0.4)~CS(127,127,127)"
local allow_fog = cfg.allow_fog or false
local allow_shroud = cfg.allow_shroud or false
local max_count = cfg.max_count or 1
local min_count = cfg.min_count or 1
local confirm_message = cfg.confirm_message
local overlay_message = cfg.overlay_message or _"Click on location to choose."
local filter = helper.literal(helper.get_child(cfg, "filter_location")) or {}
filter.include_borders = false -- prevent getting stuck when only way to get required amount of locations would be with borders, which are not selectable
-- TODO testing shows that wesnoth.game_events.on_mouse_action is nil, find out what it is supposed to be
local old_callback = wesnoth.game_events.on_mouse_action
local res = wesnoth.synchronize_choice(_"selecting location", function()
if not is_choosing_side then
wesnoth.message("synchronize_choice function fired for nonlocal side")
wesnoth.game_events.on_mouse_action = old_callback
return {}
end
if not is_choosing_side then
wesnoth.message("synchronize_choice function fired again despite return, for nonlocal side")
wesnoth.game_events.on_mouse_action = old_callback
return {}
end
if allow_fog and not allow_shroud then
table.insert(filter, T.filter_vision{side=wesnoth.current.side,respect_fog=false})
elseif not allow_fog and not allow_shroud then
table.insert(filter, T.filter_vision{side=wesnoth.current.side})
end
local allowed_locations = wesnoth.get_locations(filter)
if #allowed_locations < min_count then helper.wml_error("query_location matches less locations than min_count "..#allowed_locations.."<"..min_count) end
if min_count > max_count then helper.wml_error("query_location min_count is higher than max_count "..min_count..">"..max_count) end
if max_count == 0 then helper.wml_error("query_location called with max_count=0") end
if #allowed_locations == 0 and min_count == 0 then return end
local disabled_locations = location_set.create()
if overlay_unselectable then
for i, loc in ipairs(wesnoth.get_locations({{[1]="not",[2]=filter}})) do
x = loc[1]
y = loc[2]
disabled_locations:insert(x, y)
if is_choosing_side then
wesnoth.add_tile_overlay(x, y, { image = overlay_unselectable })
end
end
end
wesnoth.wml_actions.disallow_end_turn()
local finished = false
local adding = true -- not used for now
local candidates = location_set.create()
local chosen_locations = location_set.create()
for i, loc in ipairs(allowed_locations) do
x = loc[1]
y = loc[2]
candidates:insert(x, y)
wesnoth.add_tile_overlay(x, y, { image = overlay_choosable })
end
wesnoth.redraw{}
function wesnoth.game_events.on_mouse_action(x,y)
if adding and candidates:get(x,y) then
if chosen_locations:size() < max_count then
chosen_locations:insert(x,y)
candidates:remove(x,y)
wesnoth.remove_tile_overlay(x, y, { image = overlay_choosable })
wesnoth.add_tile_overlay(x, y, { image = overlay_chosen })
end
elseif adding and chosen_locations:get(x,y) then
if chosen_locations:size() >= min_count then
finished = true
end
elseif not adding and candidates:get(x,y) then
finished = true
elseif not adding and chosen_locations:get(x,y) then
if chosen_locations:size() > min_count then
candidates:insert(x,y)
chosen_locations:remove(x,y)
wesnoth.remove_tile_overlay(x, y, { image = overlay_chosen })
wesnoth.add_tile_overlay(x, y, { image = overlay_choosable })
else
finished=true
end
elseif not candidates:get(x,y) and not chosen_locations:get(x,y) then
if chosen_locations:size() >= min_count then
finished = true
end
end
if chosen_locations:size() == max_count then
finished = true
end
end
local function print_current_count()
wesnoth.print{text=overlay_message .. _" Selected "..chosen_locations:size().."/ ("..min_count..".."..max_count..")",size=24}
wesnoth.print{text="Im local: "..tostring(is_choosing_side), size=24}
end
local function clear_selection()
chosen_locations:iter(function(x,y,data)
wesnoth.remove_tile_overlay(x, y, { image = overlay_chosen })
end)
chosen_locations:clear()
end
local function reset_selection()
chosen_locations:iter(function(x,y,data)
wesnoth.remove_tile_overlay(x, y, { image = overlay_chosen })
wesnoth.add_tile_overlay(x, y, { image = overlay_choosable })
candidates:insert(x,y)
end)
chosen_locations:clear()
finished = false
end
while not finished do
while not finished do
print_current_count()
wesnoth.delay(10)
if not is_choosing_side then
finished = true
wesnoth.message("I am not choosing side!")
wesnoth.game_events.on_mouse_action = old_callback
end
wesnoth.redraw{}
end
print_current_count()
if confirm_message then
local options = {_"Finish", _"Choose again", _"Quit"}
if min_count ~= 0 then
table.remove(options, 3)
end
local result = helper.get_user_choice({ speaker = "narrator", message = confirm_message }, options)
if result == 1 then
elseif result == 2 then
reset_selection()
elseif result == 3 then
clear_selection()
end
end
if not is_choosing_side then
finished = true
wesnoth.game_events.on_mouse_action = old_callback
end
end
wesnoth.game_events.on_mouse_action = old_callback
candidates:iter(function(x,y,data)
wesnoth.remove_tile_overlay(x, y, { image = overlay_choosable })
end)
chosen_locations:iter(function(x,y,data)
wesnoth.remove_tile_overlay(x, y, { image = overlay_chosen })
end)
disabled_locations:iter(function(x,y,data)
wesnoth.remove_tile_overlay(x, y, { image = overlay_unselectable })
end)
disabled_locations:clear()
local wml_object = {}
for i,v in ipairs(chosen_locations:to_pairs()) do
wml_object[i] = {"value",{x=v[1],y=v[2]}}
end
wesnoth.redraw{}
return wml_object
end, function()
return helper.wml_error("query_location used with AI side")
end)
local normal_object = {}
for i=1,#res do
normal_object[i] = res[i][2]
end
wesnoth.wml_actions.allow_end_turn()
helper.set_variable_array(variable, normal_object)
return normal_object
end
function ql()
return wesnoth.wml_actions.query_location({T.filter_location{terrain="Cud"}})
end
function qi()
return wesnoth.wml_actions.query_location({T.filter_location{terrain="Cud"}, overlay_selectable=""})
end
function qo()
return wesnoth.wml_actions.query_location({T.filter_location{T["not"]{terrain="Cud"}}})
end
function qk()
return wesnoth.wml_actions.query_location({T.filter_location{terrain="Cud"}, confirm_message="qk"})
end
function qj()
return wesnoth.wml_actions.query_location({T.filter_location{terrain="Cud"}, max_count=3})
end
function qh()
return wesnoth.wml_actions.query_location({T.filter_location{terrain="Cud"}, max_count=3,allow_fog=true})
end
function qh()
return wesnoth.wml_actions.query_location({T.filter_location{terrain="Cud"}, max_count=3,allow_fog=true})
end
-->>
Re: [engine] Design of [query_location]
I found that chat is not synced while selecting, which takes away purpose of this implementation. https://i.imgur.com/a8yB5mK.jpg
It should still be useful in singleplayer content, but as I focus only on mp, I leave this issue.
It should still be useful in singleplayer content, but as I focus only on mp, I leave this issue.
- Celtic_Minstrel
- Developer
- Posts: 2207
- Joined: August 3rd, 2012, 11:26 pm
- Location: Canada
- Contact:
Re: [engine] Design of [query_location]
I'm not sure. My instinct would've been that on_mouse_action tells you the button clicked, but I guess that's not the case?Ravana wrote:Is there way to catch rightclick event with Lua?
What about my other idea of using
[set_menu_item]
to install a hotkey for finishing selection?Re: [engine] Design of [query_location]
[set_menu_item] is wml-only, so Lua variables responsible for query_location state are not be visible to it.
https://github.com/wesnoth/wesnoth/comm ... d4f42a29e8 shows there is also on_mouse_move.
https://github.com/wesnoth/wesnoth/comm ... d4f42a29e8 shows there is also on_mouse_move.
- Celtic_Minstrel
- Developer
- Posts: 2207
- Joined: August 3rd, 2012, 11:26 pm
- Location: Canada
- Contact:
Re: [engine] Design of [query_location]
Hmm. I don't think the underlying Lua call for
[set_menu_item]
supports Lua callbacks at the moment... so you'd need to set a WML variable if you wanted to use [set_menu_item]
. It could simply call into Lua though, I think?Re: [engine] Design of [query_location]
you said that i somwhow doesnt work in multiplayer, but i don't realy see what could go wrong, maybe you coudl explain what your problems were?
ok i just saw you said chat doesn't work, that's basicially https://github.com/wesnoth/wesnoth/issues/1856 and nothing you can fix in lua. Was there something else.
ok i just saw you said chat doesn't work, that's basicially https://github.com/wesnoth/wesnoth/issues/1856 and nothing you can fix in lua. Was there something else.
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: [engine] Design of [query_location]
That part too
From discordSeems that all below only applies when there is another query_location in current execution queue. Still, without way to detect control changes I dont think I can avoid such problem.
I find that when leaving game during selection and having side assigned to player/ai, game gets stuck, unable to do anything other than leaving.
Investigating shows that wesnoth.game_events.on_mouse_action is nil.
2p game: p1 calls query_location. p1 leaves game. p2 sets 1 as local side.
Result is that for p2 the tag function is called twice - first when p1 call is synced upon his leaving, and then after taking control of 1. That second call is what breaks game.
situation is that wesnoth.game_events.on_mouse_action is assigned to location selecting for one player. That player leaves game. New host takes control of leavers side. Active location selecting is canceled, but next one in queue starts immediately - so that display of side assignment is still visible
then player can only interact with game by pressing esc (and leaving), and using rightclick to enter help menu
immediately after replacing with local player: https://i.imgur.com/Q5JG92W.jpg
rightclick on map after last screen: https://i.imgur.com/JuNGFPy.jpg
Re: [engine] Design of [query_location]
ok i noticed that i looked at an outdated version from page 2 before, why do you ahve all this is_local_side checks in the new code? they actually looks like they will break more than they'll fix, sync_choice shodul do all this stuff for you an call the passed function only for the currently active side.
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: [engine] Design of [query_location]
Page 2 is more correct indeed, new code is what I got to when trying to work around that issue. Though that version has some UI code that should be in sync_choice outside it still.
Re: [engine] Design of [query_location]
i i am now testing a modified version fo the page2 code that has the
if overlay_unselectable then
blöock moved into sync_choice, what exactly does not work? i tried leaving on that side that is currently selecting locations ('2p game: p1 calls query_location. p1 leaves game. p2 sets 1 as local side.'
) and it worked as expected (the new side now had to choose a location)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: [engine] Design of [query_location]
When you have multiple query_location in execution queue - like you call and leave during first choosing.
Code: Select all
[query_location]
[/query_location]
[query_location]
[/query_location]
Re: [engine] Design of [query_location]
hmm just tested that withotu any problems (the overlay has some problems with fog but that is a different issue, or maybe that one is already fixed in a later wesnoth version).
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.