
If there is an issue with to_x or to_y, such as a missmatching number of values, or none, then the function is aborted by the 2nd/3rd wml.error statement. At that place, current_unit:extract() was already called, so the function would not only fail, but also remove the unit. This commit unstores the unit prior to aborting. The alternative of extracting the unit later would break the tests, as it is then still using the hex, which is then not available to pathfinding.
125 lines
4 KiB
Lua
125 lines
4 KiB
Lua
|
|
local function path_locs(path)
|
|
if path.location_id then
|
|
local function special_locations()
|
|
return function()
|
|
for _,loc in ipairs(tostring(path.location_id):split()) do
|
|
loc = wesnoth.current.map.special_locations[loc]
|
|
if loc then coroutine.yield(loc[1], loc[2]) end
|
|
end
|
|
end
|
|
end
|
|
return coroutine.wrap(special_locations())
|
|
elseif path.dir then
|
|
local function relative_locations()
|
|
return function(u)
|
|
local last = {x = u.x, y = u.y}
|
|
for _,dir in ipairs(path.dir:split()) do
|
|
local count = 1
|
|
if dir:find(":") then
|
|
local error_dir = dir
|
|
dir, count = dir:match("([a-z]+):(%d+)")
|
|
if not dir or not count then
|
|
wml.error("Invalid direction:count in move_unit: " .. error_dir)
|
|
end
|
|
end
|
|
local next_loc = wesnoth.map.get_direction(last.x, last.y, dir, count)
|
|
coroutine.yield(next_loc[1], next_loc[2])
|
|
last.x, last.y = next_loc[1], next_loc[2]
|
|
end
|
|
end
|
|
end
|
|
return coroutine.wrap(relative_locations())
|
|
else
|
|
local function abs_locations(coord)
|
|
return function()
|
|
for _,s in ipairs(tostring(path[coord]):split()) do
|
|
coroutine.yield(tonumber(s))
|
|
end
|
|
end
|
|
end
|
|
-- Double-coroutining seems a bit excessive but I can't think of a better way to do this?
|
|
return coroutine.wrap(function()
|
|
local xs, ys = coroutine.wrap(abs_locations('to_x')), coroutine.wrap(abs_locations('to_y'))
|
|
repeat
|
|
local x, y = xs(), ys()
|
|
coroutine.yield(x, y)
|
|
until x == nil or y == nil
|
|
end)
|
|
end
|
|
end
|
|
|
|
function wesnoth.wml_actions.move_unit(cfg)
|
|
local coordinate_error = "invalid location in [move_unit]"
|
|
local path
|
|
if cfg.to_location then
|
|
path = {location_id = cfg.to_location}
|
|
elseif cfg.dir then
|
|
path = {dir = cfg.dir}
|
|
else
|
|
path = {to_x = cfg.to_x, to_y = cfg.to_y}
|
|
end
|
|
if not path then
|
|
wml.error(coordinate_error)
|
|
end
|
|
local fire_event = cfg.fire_event
|
|
local unshroud = cfg.clear_shroud
|
|
local muf_force_scroll = cfg.force_scroll
|
|
local check_passability = cfg.check_passability
|
|
if check_passability == nil then check_passability = true end
|
|
cfg = wml.literal(cfg)
|
|
cfg.to_location, cfg.to_x, cfg.to_y, cfg.fire_event, cfg.clear_shroud = nil, nil, nil, nil, nil
|
|
local units = wesnoth.units.find_on_map(cfg)
|
|
|
|
for current_unit_index, current_unit in ipairs(units) do
|
|
if not fire_event or current_unit.valid then
|
|
local locs = path_locs(path)
|
|
local x_list = {current_unit.x}
|
|
local y_list = {current_unit.y}
|
|
local pass_check = nil
|
|
if check_passability then pass_check = current_unit end
|
|
|
|
current_unit:extract()
|
|
local x, y = locs(current_unit)
|
|
local prevX, prevY = tonumber(current_unit.x), tonumber(current_unit.y)
|
|
while true do
|
|
x = tonumber(x) or current_unit:to_map(false) or wml.error(coordinate_error)
|
|
y = tonumber(y) or current_unit:to_map(false) or wml.error(coordinate_error)
|
|
if not (x == prevX and y == prevY) then x, y = wesnoth.paths.find_vacant_hex(x, y, pass_check) end
|
|
if not x or not y then wml.error("Could not find a suitable hex near to one of the target hexes in [move_unit].") end
|
|
table.insert(x_list, x)
|
|
table.insert(y_list, y)
|
|
local next_x, next_y = locs(current_unit)
|
|
if not next_x and not next_y then break end
|
|
prevX, prevY = x, y
|
|
x, y = next_x, next_y
|
|
end
|
|
|
|
if current_unit.x < x then current_unit.facing = "se"
|
|
elseif current_unit.x > x then current_unit.facing = "sw"
|
|
end
|
|
|
|
local current_unit_cfg = current_unit.__cfg
|
|
wesnoth.wml_actions.move_unit_fake {
|
|
type = current_unit_cfg.type,
|
|
gender = current_unit_cfg.gender,
|
|
variation = current_unit_cfg.variation,
|
|
image_mods = current_unit.image_mods,
|
|
side = current_unit_cfg.side,
|
|
x = x_list,
|
|
y = y_list,
|
|
force_scroll = muf_force_scroll
|
|
}
|
|
local x2, y2 = current_unit.x, current_unit.y
|
|
current_unit.x, current_unit.y = x, y
|
|
current_unit:to_map(false)
|
|
if unshroud then
|
|
wesnoth.wml_actions.redraw {clear_shroud=true}
|
|
end
|
|
|
|
if fire_event then
|
|
wesnoth.game_events.fire("moveto", x, y, x2, y2)
|
|
end
|
|
end
|
|
end
|
|
end
|