Skip to content

Commit

Permalink
ExpAI recruit rushers: include unit types from extra_recruit
Browse files Browse the repository at this point in the history
This fixes #4924. Note, however, that the recruit rushers CA is set up for single-leader sides and does not work with multiple leaders, so this is of limited use.
  • Loading branch information
mattsc committed Jun 22, 2022
1 parent 7877218 commit c1d1ff5
Showing 1 changed file with 17 additions and 9 deletions.
26 changes: 17 additions & 9 deletions data/ai/lua/ca_recruit_rushers.lua
Original file line number Diff line number Diff line change
Expand Up @@ -423,7 +423,7 @@ end
local function get_test_units()
local test_units, num_recruits = {}, 0
local movetypes = {}
for x,id in ipairs(wesnoth.sides[wesnoth.current.side].recruit) do
for id in pairs(recruit_data.recruit_types) do
local custom_movement = wml.get_child(wesnoth.unit_types[id].__cfg, "movement_costs")
local movetype = wesnoth.unit_types[id].__cfg.movement_type
if custom_movement
Expand Down Expand Up @@ -451,7 +451,7 @@ end
local function get_village_target(leader, data)
-- Only consider villages reachable by our fastest unit
local fastest_unit_speed = 0
for i, recruit_id in ipairs(wesnoth.sides[wesnoth.current.side].recruit) do
for recruit_id in pairs(recruit_data.recruit_types) do
if wesnoth.unit_types[recruit_id].max_moves > fastest_unit_speed then
fastest_unit_speed = wesnoth.unit_types[recruit_id].max_moves
end
Expand Down Expand Up @@ -705,7 +705,7 @@ local function find_best_recruit(attack_type_count, unit_attack_type_count, recr

local recruitable_units = {}

for i, recruit_id in ipairs(wesnoth.sides[wesnoth.current.side].recruit) do
for recruit_id in pairs(recruit_data.recruit_types) do
-- Count number of units with the same attack type. Used to avoid recruiting too many of the same unit
local attack_types = 0
local recruit_count = 0
Expand Down Expand Up @@ -804,7 +804,7 @@ local function find_best_recruit(attack_type_count, unit_attack_type_count, recr
level_count[level] = (level_count[level] or 0) + 1
end
local min_recruit_level, max_recruit_level = math.huge, -math.huge
for i, recruit_id in ipairs(wesnoth.sides[wesnoth.current.side].recruit) do
for recruit_id in pairs(recruit_data.recruit_types) do
local level = wesnoth.unit_types[recruit_id].level
if (level < min_recruit_level) then min_recruit_level = level end
if (level > max_recruit_level) then max_recruit_level = level end
Expand All @@ -823,7 +823,7 @@ local function find_best_recruit(attack_type_count, unit_attack_type_count, recr
unit_deficit[i] = high_level_fraction ^ (i - min_recruit_level) * n_units - n_units_this_level
end

for i, recruit_id in ipairs(wesnoth.sides[wesnoth.current.side].recruit) do
for recruit_id in pairs(recruit_data.recruit_types) do
local level_bonus = 0
local level = wesnoth.unit_types[recruit_id].level
if (level > min_recruit_level) and (unit_deficit[level] > 0) then
Expand Down Expand Up @@ -908,6 +908,14 @@ function ca_recruit_rushers:evaluation(cfg, data, filter_own)
return 0
end

recruit_data.recruit_types = {}
for _,unit_type in ipairs(wesnoth.sides[wesnoth.current.side].recruit) do
recruit_data.recruit_types[unit_type] = true
end
for _,unit_type in ipairs(leader.extra_recruit) do
recruit_data.recruit_types[unit_type] = true
end

-- Check for space to recruit a unit
get_current_castle(leader, recruit_data)
local no_space = true
Expand Down Expand Up @@ -966,14 +974,14 @@ function ca_recruit_rushers:execution(cfg, data, filter_own)
local poisoner_count = 0.1 -- Number of units with a poison attack (set to slightly > 0 because we divide by it later)
local poisonable_count = 0 -- Number of units that the opponents control that are hurt by poison
local recruit_count = {}
for i, recruit_id in ipairs(wesnoth.sides[wesnoth.current.side].recruit) do
for recruit_id in pairs(recruit_data.recruit_types) do
recruit_count[recruit_id] = #(AH.get_live_units { side = wesnoth.current.side, type = recruit_id, canrecruit = 'no' })
end

for i, unit_type in ipairs(enemy_types) do
enemy_type_count = enemy_type_count + 1
local poison_vulnerable = false
for j, recruit_id in ipairs(wesnoth.sides[wesnoth.current.side].recruit) do
for recruit_id in pairs(recruit_data.recruit_types) do
local analysis = analyze_enemy_unit(unit_type, recruit_id)

if not recruit_effectiveness[recruit_id] then
Expand Down Expand Up @@ -1015,7 +1023,7 @@ function ca_recruit_rushers:execution(cfg, data, filter_own)
poisonable_count = poisonable_count + enemy_counts[unit_type]
end
end
for i, recruit_id in ipairs(wesnoth.sides[wesnoth.current.side].recruit) do
for recruit_id in pairs(recruit_data.recruit_types) do
-- Count the number of units with the poison ability
-- This could be wrong if all the units on the enemy side are immune to poison, but since poison has no effect then anyway it doesn't matter
if recruit_effectiveness[recruit_id].poison_damage > 0 then
Expand All @@ -1026,7 +1034,7 @@ function ca_recruit_rushers:execution(cfg, data, filter_own)
-- This works perfectly unless some of the enemy recruits cannot be poisoned.
-- However, there is no problem with this since poison is generally less useful in such situations and subtracting them too discourages such recruiting
local poison_modifier = math.max(0, math.min(((poisonable_count-recruit_data.recruit.possible_enemy_recruit_count) / (poisoner_count*5)), 1))^2
for i, recruit_id in ipairs(wesnoth.sides[wesnoth.current.side].recruit) do
for recruit_id in pairs(recruit_data.recruit_types) do
-- Ensure effectiveness and vulnerability are positive.
-- Negative values imply that drain is involved and the amount drained is very high
if recruit_effectiveness[recruit_id].damage <= 0 then
Expand Down

0 comments on commit c1d1ff5

Please sign in to comment.