mirror of
https://github.com/wesnoth/wesnoth
synced 2025-05-19 10:25:54 +00:00
Goto MAI: add avoid_enemies= parameter
This commit is contained in:
parent
b103ded118
commit
8d55cc572f
@ -5,8 +5,19 @@ return {
|
|||||||
|
|
||||||
local H = wesnoth.require "lua/helper.lua"
|
local H = wesnoth.require "lua/helper.lua"
|
||||||
local AH = wesnoth.require "ai/lua/ai_helper.lua"
|
local AH = wesnoth.require "ai/lua/ai_helper.lua"
|
||||||
|
local BC = wesnoth.require "ai/lua/battle_calcs.lua"
|
||||||
local LS = wesnoth.require "lua/location_set.lua"
|
local LS = wesnoth.require "lua/location_set.lua"
|
||||||
|
|
||||||
|
local function custom_cost(x, y, u, enemy_map, enemy_attack_map, multiplier)
|
||||||
|
local terrain = wesnoth.get_terrain(x, y)
|
||||||
|
local move_cost = wesnoth.unit_movement_cost(u, terrain)
|
||||||
|
|
||||||
|
move_cost = move_cost + (enemy_map:get(x,y) or 0)
|
||||||
|
move_cost = move_cost + (enemy_attack_map.units:get(x,y) or 0) * multiplier
|
||||||
|
|
||||||
|
return move_cost
|
||||||
|
end
|
||||||
|
|
||||||
function engine:mai_goto_eval(cfg)
|
function engine:mai_goto_eval(cfg)
|
||||||
|
|
||||||
-- If cfg.release_all_units_at_goal is set, check
|
-- If cfg.release_all_units_at_goal is set, check
|
||||||
@ -75,6 +86,28 @@ return {
|
|||||||
function engine:mai_goto_exec(cfg)
|
function engine:mai_goto_exec(cfg)
|
||||||
local units, locs = self.data.units, self.data.locs -- simply for convenience
|
local units, locs = self.data.units, self.data.locs -- simply for convenience
|
||||||
|
|
||||||
|
-- Need the enemy map and enemy attack map if avoid_enemies is set
|
||||||
|
local enemy_map, enemy_attack_map
|
||||||
|
if cfg.avoid_enemies then
|
||||||
|
if (type(cfg.avoid_enemies) ~= 'number') then
|
||||||
|
H.wml_error("Goto AI avoid_enemies= requires a number as argument")
|
||||||
|
elseif (cfg.avoid_enemies <= 0) then
|
||||||
|
H.wml_error("Goto AI avoid_enemies= argument must be >0")
|
||||||
|
end
|
||||||
|
|
||||||
|
local enemies = wesnoth.get_units { { "filter_side", { {"enemy_of", {side = wesnoth.current.side} } } } }
|
||||||
|
|
||||||
|
enemy_map = LS.create()
|
||||||
|
for i,e in ipairs(enemies) do
|
||||||
|
enemy_map:insert(e.x, e.y, (enemy_map:get(e.x, e.y) or 0) + 1000)
|
||||||
|
for x, y in H.adjacent_tiles(e.x, e.y) do
|
||||||
|
enemy_map:insert(x, y, (enemy_map:get(x, y) or 0) + 10)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
enemy_attack_map = BC.get_attack_map(enemies)
|
||||||
|
end
|
||||||
|
|
||||||
local closest_hex, best_unit, max_rating = {}, {}, -9e99
|
local closest_hex, best_unit, max_rating = {}, {}, -9e99
|
||||||
for i,u in ipairs(units) do
|
for i,u in ipairs(units) do
|
||||||
for i,l in ipairs(locs) do
|
for i,l in ipairs(locs) do
|
||||||
@ -95,7 +128,15 @@ return {
|
|||||||
closest_hex, best_unit = hex, u
|
closest_hex, best_unit = hex, u
|
||||||
end
|
end
|
||||||
else -- Otherwise find the best path to take
|
else -- Otherwise find the best path to take
|
||||||
local path, cost = wesnoth.find_path(u, l[1], l[2])
|
local path, cost
|
||||||
|
if cfg.avoid_enemies then
|
||||||
|
path, cost = wesnoth.find_path(u, l[1], l[2],
|
||||||
|
function(x, y, current_cost)
|
||||||
|
return custom_cost(x, y, u, enemy_map, enemy_attack_map, cfg.avoid_enemies)
|
||||||
|
end)
|
||||||
|
else
|
||||||
|
path, cost = wesnoth.find_path(u, l[1], l[2])
|
||||||
|
end
|
||||||
|
|
||||||
-- Make all hexes within the unit's current MP equaivalent
|
-- Make all hexes within the unit's current MP equaivalent
|
||||||
if (cost <= u.moves) then cost = 0 end
|
if (cost <= u.moves) then cost = 0 end
|
||||||
@ -118,8 +159,6 @@ return {
|
|||||||
end
|
end
|
||||||
--print(best_unit.id, best_unit.x, best_unit.y, closest_hex[1], closest_hex[2], max_rating)
|
--print(best_unit.id, best_unit.x, best_unit.y, closest_hex[1], closest_hex[2], max_rating)
|
||||||
|
|
||||||
AH.movefull_outofway_stopunit(ai, best_unit, closest_hex[1], closest_hex[2])
|
|
||||||
|
|
||||||
-- If 'unique_goals' is set, mark this location as being taken
|
-- If 'unique_goals' is set, mark this location as being taken
|
||||||
if cfg.unique_goals then
|
if cfg.unique_goals then
|
||||||
local str = 'goals_taken_' .. wesnoth.current.turn
|
local str = 'goals_taken_' .. wesnoth.current.turn
|
||||||
@ -127,6 +166,30 @@ return {
|
|||||||
self.data[str]:insert(closest_hex[1], closest_hex[2])
|
self.data[str]:insert(closest_hex[1], closest_hex[2])
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- If avoid_enemies is set, we need to pick farthest reachable hex along that path
|
||||||
|
if cfg.avoid_enemies then
|
||||||
|
local path, cost = wesnoth.find_path(best_unit, closest_hex[1], closest_hex[2],
|
||||||
|
function(x, y, current_cost)
|
||||||
|
return custom_cost(x, y, best_unit, enemy_map, enemy_attack_map, cfg.avoid_enemies)
|
||||||
|
end)
|
||||||
|
|
||||||
|
-- Now go through the hexes along that path, use normal path finding
|
||||||
|
closest_hex = path[1]
|
||||||
|
for i = 2,#path do
|
||||||
|
local sub_path, sub_cost = wesnoth.find_path(best_unit, path[i][1], path[i][2], cfg)
|
||||||
|
if sub_cost <= best_unit.moves then
|
||||||
|
local unit_in_way = wesnoth.get_unit(path[i][1], path[i][2])
|
||||||
|
if not unit_in_way then
|
||||||
|
closest_hex = path[i]
|
||||||
|
end
|
||||||
|
else
|
||||||
|
break
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
AH.movefull_outofway_stopunit(ai, best_unit, closest_hex[1], closest_hex[2])
|
||||||
|
|
||||||
-- If release_unit_at_goal= or release_all_units_at_goal= key is set:
|
-- If release_unit_at_goal= or release_all_units_at_goal= key is set:
|
||||||
-- Check if the unit made it to one of the goal hexes
|
-- Check if the unit made it to one of the goal hexes
|
||||||
-- This needs to be done for the original goal hexes, not checking the SLF again,
|
-- This needs to be done for the original goal hexes, not checking the SLF again,
|
||||||
|
@ -457,7 +457,7 @@ function wesnoth.wml_actions.micro_ai(cfg)
|
|||||||
--------- Goto Micro AI - side-wide AI ------------------------------------
|
--------- Goto Micro AI - side-wide AI ------------------------------------
|
||||||
elseif (cfg.ai_type == 'goto') then
|
elseif (cfg.ai_type == 'goto') then
|
||||||
required_keys = { "filter", "filter_location" }
|
required_keys = { "filter", "filter_location" }
|
||||||
optional_keys = { "release_all_units_at_goal", "release_unit_at_goal", "unique_goals", "use_straight_line" }
|
optional_keys = { "avoid_enemies", "release_all_units_at_goal", "release_unit_at_goal", "unique_goals", "use_straight_line" }
|
||||||
CA_parms = { { ca_id = 'mai_goto', score = cfg.ca_score or 300000 } }
|
CA_parms = { { ca_id = 'mai_goto', score = cfg.ca_score or 300000 } }
|
||||||
|
|
||||||
--------- Hang Out Micro AI - side-wide AI ------------------------------------
|
--------- Hang Out Micro AI - side-wide AI ------------------------------------
|
||||||
|
Loading…
x
Reference in New Issue
Block a user