Skip to content

Commit

Permalink
Big Animals Micro AI: move only one unit per execution
Browse files Browse the repository at this point in the history
There is essentially no time saving involved with doing it all in one
execution as all tables need to be reevaluated for each unit anyway in
order to adapt to potential changes due to ambushes or WML events. (The
latter is not all done yet, will be added in a follow-up commit.)
  • Loading branch information
mattsc committed Oct 11, 2016
1 parent d7bb7dc commit 2eeed5a
Showing 1 changed file with 60 additions and 61 deletions.
121 changes: 60 additions & 61 deletions data/ai/micro_ais/cas/ca_big_animals.lua
Expand Up @@ -22,7 +22,8 @@ function ca_big_animals:execution(cfg)
-- Big animals just move toward a goal that gets (re)set occasionally
-- and attack whatever is in their range (except for some units that they avoid)

local big_animals = get_big_animals(cfg)
local unit = get_big_animals(cfg)[1]

local avoid_tag = H.get_child(cfg, "avoid_unit")
local avoid_map = LS.create()
if avoid_tag then
Expand All @@ -33,79 +34,77 @@ function ca_big_animals:execution(cfg)
})
end

for _,unit in ipairs(big_animals) do
local goal = MAIUV.get_mai_unit_variables(unit, cfg.ai_id)
local goal = MAIUV.get_mai_unit_variables(unit, cfg.ai_id)

-- Unit gets a new goal if none is set or on any move with a 10% random chance
local r = math.random(10)
if (not goal.goal_x) or (r == 1) then
local locs = AH.get_passable_locations(H.get_child(cfg, "filter_location") or {})
local rand = math.random(#locs)
-- Unit gets a new goal if none is set or on any move with a 10% random chance
local r = math.random(10)
if (not goal.goal_x) or (r == 1) then
local locs = AH.get_passable_locations(H.get_child(cfg, "filter_location") or {})
local rand = math.random(#locs)

goal.goal_x, goal.goal_y = locs[rand][1], locs[rand][2]
MAIUV.set_mai_unit_variables(unit, cfg.ai_id, goal)
end
goal.goal_x, goal.goal_y = locs[rand][1], locs[rand][2]
MAIUV.set_mai_unit_variables(unit, cfg.ai_id, goal)
end

local reach_map = AH.get_reachable_unocc(unit)
local wander_terrain = H.get_child(cfg, "filter_location_wander") or {}
reach_map:iter( function(x, y, v)
-- Remove tiles that do not comform to the wander terrain filter
if (not wesnoth.match_location(x, y, wander_terrain)) then
reach_map:remove(x, y)
end
end)

-- Now find the one of these hexes that is closest to the goal
local max_rating, best_hex = -9e99
reach_map:iter( function(x, y, v)
local rating = - H.distance_between(x, y, goal.goal_x, goal.goal_y)

-- Proximity to an enemy unit is a plus
local enemy_hp = 500
for xa,ya in H.adjacent_tiles(x, y) do
local enemy = wesnoth.get_unit(xa, ya)
if enemy and wesnoth.is_enemy(enemy.side, wesnoth.current.side) then
if (enemy.hitpoints < enemy_hp) then enemy_hp = enemy.hitpoints end
end
end
rating = rating + 500 - enemy_hp -- Prefer attack on weakest enemy
local reach_map = AH.get_reachable_unocc(unit)
local wander_terrain = H.get_child(cfg, "filter_location_wander") or {}
reach_map:iter( function(x, y, v)
-- Remove tiles that do not comform to the wander terrain filter
if (not wesnoth.match_location(x, y, wander_terrain)) then
reach_map:remove(x, y)
end
end)

-- Hexes reachable by units to be be avoided get a massive negative hit
if avoid_map:get(x, y) then rating = rating - 1000 end
-- Now find the one of these hexes that is closest to the goal
local max_rating, best_hex = -9e99
reach_map:iter( function(x, y, v)
local rating = - H.distance_between(x, y, goal.goal_x, goal.goal_y)

if (rating > max_rating) then
max_rating, best_hex = rating, { x, y }
-- Proximity to an enemy unit is a plus
local enemy_hp = 500
for xa,ya in H.adjacent_tiles(x, y) do
local enemy = wesnoth.get_unit(xa, ya)
if enemy and wesnoth.is_enemy(enemy.side, wesnoth.current.side) then
if (enemy.hitpoints < enemy_hp) then enemy_hp = enemy.hitpoints end
end
end)

if (best_hex[1] ~= unit.x) or (best_hex[2] ~= unit.y) then
AH.checked_move(ai, unit, best_hex[1], best_hex[2]) -- Partial move only
if (not unit) or (not unit.valid) then return end
else -- If unit did not move, we need to stop it (also delete the goal)
AH.checked_stopunit_moves(ai, unit)
if (not unit) or (not unit.valid) then return end
MAIUV.delete_mai_unit_variables(unit, cfg.ai_id)
end
rating = rating + 500 - enemy_hp -- Prefer attack on weakest enemy

-- If this gets the unit to the goal, we also delete the goal
if (unit.x == goal.goal_x) and (unit.y == goal.goal_y) then
MAIUV.delete_mai_unit_variables(unit, cfg.ai_id)
-- Hexes reachable by units to be be avoided get a massive negative hit
if avoid_map:get(x, y) then rating = rating - 1000 end

if (rating > max_rating) then
max_rating, best_hex = rating, { x, y }
end
end)

if (best_hex[1] ~= unit.x) or (best_hex[2] ~= unit.y) then
AH.checked_move(ai, unit, best_hex[1], best_hex[2]) -- Partial move only
if (not unit) or (not unit.valid) then return end
else -- If unit did not move, we need to stop it (also delete the goal)
AH.checked_stopunit_moves(ai, unit)
if (not unit) or (not unit.valid) then return end
MAIUV.delete_mai_unit_variables(unit, cfg.ai_id)
end

-- Finally, if the unit ended up next to enemies, attack the weakest of those
local min_hp, target = 9e99
for xa,ya in H.adjacent_tiles(unit.x, unit.y) do
local enemy = wesnoth.get_unit(xa, ya)
if enemy and wesnoth.is_enemy(enemy.side, wesnoth.current.side) then
if (enemy.hitpoints < min_hp) then
min_hp, target = enemy.hitpoints, enemy
end
-- If this gets the unit to the goal, we also delete the goal
if (unit.x == goal.goal_x) and (unit.y == goal.goal_y) then
MAIUV.delete_mai_unit_variables(unit, cfg.ai_id)
end

-- Finally, if the unit ended up next to enemies, attack the weakest of those
local min_hp, target = 9e99
for xa,ya in H.adjacent_tiles(unit.x, unit.y) do
local enemy = wesnoth.get_unit(xa, ya)
if enemy and wesnoth.is_enemy(enemy.side, wesnoth.current.side) then
if (enemy.hitpoints < min_hp) then
min_hp, target = enemy.hitpoints, enemy
end
end
end

if target then
AH.checked_attack(ai, unit, target)
end
if target then
AH.checked_attack(ai, unit, target)
end
end

Expand Down

0 comments on commit 2eeed5a

Please sign in to comment.