Messenger MAI: fix bug with escort units blocking the messenger

When there were lots of escort units, they previously quite frequently
blocked the messenger’s way, preventing him from making progress even
when it was possible.  Escort units now specifically move out of the
way if they do not need to attack enemy units in the messenger’s way.
This commit is contained in:
mattsc 2014-03-26 18:06:36 -07:00
parent 9e6b780306
commit 2d458b642a

View file

@ -21,21 +21,34 @@ function ca_messenger_move:execution(ai, cfg, self)
local messenger = wesnoth.get_units{ id = cfg.id, formula = '$this_unit.moves > 0' }[1]
local x, y = messenger_next_waypoint(messenger, cfg, self)
if (messenger.x ~= x) or (messenger.y ~= y) then
x, y = wesnoth.find_vacant_tile( x, y, messenger)
local wp = AH.get_closest_location(
{ x, y },
{ { "not", { { "filter", { { "not", { side = wesnoth.current.side } } } } } } },
messenger
)
x, y = wp[1], wp[2]
end
local next_hop = AH.next_hop(messenger, x, y)
local next_hop = AH.next_hop(messenger, x, y, { ignore_own_units = true } )
if (not next_hop) then next_hop = { messenger.x, messenger.y } end
-- Compare this to the "ideal path"
local path, cost = wesnoth.find_path(messenger, x, y, { ignore_units = 'yes' })
local opt_hop, opt_cost = {messenger.x, messenger.y}, 0
local opt_hop, opt_cost = { messenger.x, messenger.y }, 0
for i, p in ipairs(path) do
local sub_path, sub_cost = wesnoth.find_path(messenger, p[1], p[2])
if sub_cost > messenger.moves then
if sub_cost > messenger.moves then
break
else
local unit_in_way = wesnoth.get_unit(p[1], p[2])
if unit_in_way and (unit_in_way.side == messenger.side) then
local reach = AH.get_reachable_unocc(unit_in_way)
if (reach:size() > 1) then unit_in_way = nil end
end
if not unit_in_way then
opt_hop, nh_cost = p, sub_cost
end
@ -45,11 +58,24 @@ function ca_messenger_move:execution(ai, cfg, self)
--print(next_hop[1], next_hop[2], opt_hop[1], opt_hop[2])
-- Now compare how long it would take from the end of both of these options
local x1, y1 = messenger.x, messenger.y
local unit_in_way = wesnoth.get_unit(next_hop[1], next_hop[2])
if (unit_in_way == messenger) then unit_in_way = nil end
if unit_in_way then wesnoth.extract_unit(unit_in_way) end
wesnoth.put_unit(next_hop[1], next_hop[2], messenger)
local tmp, cost1 = wesnoth.find_path(messenger, x, y, {ignore_units = 'yes'})
local unit_in_way2 = wesnoth.get_unit(opt_hop[1], opt_hop[2])
if (unit_in_way2 == messenger) then unit_in_way2 = nil end
if unit_in_way2 then wesnoth.extract_unit(unit_in_way2) end
wesnoth.put_unit(opt_hop[1], opt_hop[2], messenger)
local tmp, cost2 = wesnoth.find_path(messenger, x, y, {ignore_units = 'yes'})
wesnoth.put_unit(x1, y1, messenger)
if unit_in_way then wesnoth.put_unit(unit_in_way) end
if unit_in_way2 then wesnoth.put_unit(unit_in_way2) end
--print(cost1, cost2)
-- If cost2 is significantly less, that means that the other path might overall be faster
@ -58,6 +84,10 @@ function ca_messenger_move:execution(ai, cfg, self)
--print(next_hop[1], next_hop[2])
if next_hop and ((next_hop[1] ~= messenger.x) or (next_hop[2] ~= messenger.y)) then
local unit_in_way = wesnoth.get_unit(next_hop[1], next_hop[2])
if unit_in_way then AH.move_unit_out_of_way(ai, unit_in_way) end
if (not messenger) or (not messenger.valid) then return end
AH.checked_move(ai, messenger, next_hop[1], next_hop[2])
else
AH.checked_stopunit_moves(ai, messenger)