MicroAIs: Update all to use the new [args] syntax
Except for Protect Unit, all of them seem to still work correctly.
This commit is contained in:
parent
037a526a68
commit
c79874086d
55 changed files with 367 additions and 397 deletions
|
@ -440,9 +440,7 @@ return {
|
|||
return score
|
||||
end
|
||||
|
||||
function ai_cas:recruit_rushers_exec(ai_local)
|
||||
if ai_local then ai = ai_local end
|
||||
|
||||
function ai_cas:recruit_rushers_exec()
|
||||
if AH.show_messages() then W.message { speaker = 'narrator', message = 'Recruiting' } end
|
||||
|
||||
local enemy_counts = recruit_data.recruit.enemy_counts
|
||||
|
|
|
@ -6,27 +6,28 @@ local MAIUV = wesnoth.require "ai/micro_ais/micro_ai_unit_variables.lua"
|
|||
local function get_big_animals(cfg)
|
||||
local big_animals = AH.get_units_with_moves {
|
||||
side = wesnoth.current.side,
|
||||
{ "and" , cfg.filter }
|
||||
{ "and" , H.get_child(cfg, "filter") }
|
||||
}
|
||||
return big_animals
|
||||
end
|
||||
|
||||
local ca_big_animals = {}
|
||||
|
||||
function ca_big_animals:evaluation(ai, cfg)
|
||||
function ca_big_animals:evaluation(cfg)
|
||||
if get_big_animals(cfg)[1] then return cfg.ca_score end
|
||||
return 0
|
||||
end
|
||||
|
||||
function ca_big_animals:execution(ai, cfg)
|
||||
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 avoid_tag = H.get_child(cfg, "avoid_unit")
|
||||
local avoid_map = LS.create()
|
||||
if cfg.avoid_unit then
|
||||
if avoid_tag then
|
||||
avoid_map = LS.of_pairs(wesnoth.get_locations { radius = 1,
|
||||
{ "filter", { { "and", cfg.avoid_unit },
|
||||
{ "filter", { { "and", avoid_tag },
|
||||
{ "filter_side", { { "enemy_of", { side = wesnoth.current.side } } } }
|
||||
} }
|
||||
})
|
||||
|
@ -38,7 +39,7 @@ function ca_big_animals:execution(ai, cfg)
|
|||
-- 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(cfg.filter_location or {})
|
||||
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]
|
||||
|
@ -46,7 +47,7 @@ function ca_big_animals:execution(ai, cfg)
|
|||
end
|
||||
|
||||
local reach_map = AH.get_reachable_unocc(unit)
|
||||
local wander_terrain = cfg.filter_location_wander or {}
|
||||
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
|
||||
|
|
|
@ -3,7 +3,7 @@ local H = wesnoth.require "lua/helper.lua"
|
|||
|
||||
local ca_bottleneck_attack = {}
|
||||
|
||||
function ca_bottleneck_attack:evaluation(ai, cfg, self)
|
||||
function ca_bottleneck_attack:evaluation(cfg, data)
|
||||
local attackers = AH.get_units_with_attacks {
|
||||
side = wesnoth.current.side,
|
||||
{ "filter_adjacent", {
|
||||
|
@ -55,29 +55,29 @@ function ca_bottleneck_attack:evaluation(ai, cfg, self)
|
|||
|
||||
if (not best_attacker) then
|
||||
-- In this case we take attacks away from all units
|
||||
self.data.BD_bottleneck_attacks_done = true
|
||||
data.BD_bottleneck_attacks_done = true
|
||||
else
|
||||
self.data.BD_bottleneck_attacks_done = false
|
||||
self.data.BD_attacker = best_attacker
|
||||
self.data.BD_target = best_target
|
||||
self.data.BD_weapon = best_weapon
|
||||
data.BD_bottleneck_attacks_done = false
|
||||
data.BD_attacker = best_attacker
|
||||
data.BD_target = best_target
|
||||
data.BD_weapon = best_weapon
|
||||
end
|
||||
|
||||
return cfg.ca_score
|
||||
end
|
||||
|
||||
function ca_bottleneck_attack:execution(ai, cfg, self)
|
||||
if self.data.BD_bottleneck_attacks_done then
|
||||
function ca_bottleneck_attack:execution(cfg, data)
|
||||
if data.BD_bottleneck_attacks_done then
|
||||
local units = AH.get_units_with_attacks { side = wesnoth.current.side }
|
||||
for _,unit in ipairs(units) do
|
||||
AH.checked_stopunit_attacks(ai, unit)
|
||||
end
|
||||
else
|
||||
AH.checked_attack(ai, self.data.BD_attacker, self.data.BD_target, self.data.BD_weapon)
|
||||
AH.checked_attack(ai, data.BD_attacker, data.BD_target, data.BD_weapon)
|
||||
end
|
||||
|
||||
self.data.BD_attacker, self.data.BD_target, self.data.BD_weapon = nil, nil, nil
|
||||
self.data.BD_bottleneck_attacks_done = nil
|
||||
data.BD_attacker, data.BD_target, data.BD_weapon = nil, nil, nil
|
||||
data.BD_bottleneck_attacks_done = nil
|
||||
end
|
||||
|
||||
return ca_bottleneck_attack
|
||||
|
|
|
@ -81,19 +81,19 @@ local function bottleneck_triple_from_keys(key_x, key_y, max_value)
|
|||
return AH.LS_of_triples(coords)
|
||||
end
|
||||
|
||||
local function bottleneck_create_positioning_map(max_value, self)
|
||||
local function bottleneck_create_positioning_map(max_value, data)
|
||||
-- Create the positioning maps for the healers and leaders, if not given by WML keys
|
||||
-- @max_value: the rating value for the first hex in the set
|
||||
-- self.data.BD_def_map must have been created when this function is called.
|
||||
-- data.BD_def_map must have been created when this function is called.
|
||||
|
||||
-- Find all locations adjacent to def_map.
|
||||
-- This might include hexes on the line itself.
|
||||
-- Only store those that are not in enemy territory.
|
||||
local map = LS.create()
|
||||
self.data.BD_def_map:iter(function(x, y, v)
|
||||
data.BD_def_map:iter(function(x, y, v)
|
||||
for xa,ya in H.adjacent_tiles(x, y) do
|
||||
if self.data.BD_is_my_territory:get(xa, ya) then
|
||||
local rating = self.data.BD_def_map:get(x, y) or 0
|
||||
if data.BD_is_my_territory:get(xa, ya) then
|
||||
local rating = data.BD_def_map:get(x, y) or 0
|
||||
rating = rating + (map:get(xa, ya) or 0)
|
||||
map:insert(xa, ya, rating)
|
||||
end
|
||||
|
@ -108,14 +108,14 @@ local function bottleneck_create_positioning_map(max_value, self)
|
|||
|
||||
-- We merge the defense map into this, as healers/leaders (by default)
|
||||
-- can take position on the front line
|
||||
map:union_merge(self.data.BD_def_map,
|
||||
map:union_merge(data.BD_def_map,
|
||||
function(x, y, v1, v2) return v1 or v2 end
|
||||
)
|
||||
|
||||
return map
|
||||
end
|
||||
|
||||
local function bottleneck_get_rating(unit, x, y, has_leadership, is_healer, self)
|
||||
local function bottleneck_get_rating(unit, x, y, has_leadership, is_healer, data)
|
||||
-- Calculate rating of a unit @unit at coordinates (@x,@y).
|
||||
-- Don't want to extract @is_healer and @has_leadership inside this function, as it is very slow.
|
||||
-- Thus they are provided as parameters from the calling function.
|
||||
|
@ -125,18 +125,18 @@ local function bottleneck_get_rating(unit, x, y, has_leadership, is_healer, self
|
|||
-- Defense positioning rating
|
||||
-- We exclude healers/leaders here, as we don't necessarily want them on the front line
|
||||
if (not is_healer) and (not has_leadership) then
|
||||
rating = self.data.BD_def_map:get(x, y) or 0
|
||||
rating = data.BD_def_map:get(x, y) or 0
|
||||
end
|
||||
|
||||
-- Healer positioning rating
|
||||
if is_healer then
|
||||
local healer_rating = self.data.BD_healer_map:get(x, y) or 0
|
||||
local healer_rating = data.BD_healer_map:get(x, y) or 0
|
||||
if (healer_rating > rating) then rating = healer_rating end
|
||||
end
|
||||
|
||||
-- Leadership unit positioning rating
|
||||
if has_leadership then
|
||||
local leadership_rating = self.data.BD_leadership_map:get(x, y) or 0
|
||||
local leadership_rating = data.BD_leadership_map:get(x, y) or 0
|
||||
|
||||
-- If leadership unit is injured -> prefer hexes next to healers
|
||||
if (unit.hitpoints < unit.max_hitpoints) then
|
||||
|
@ -154,18 +154,18 @@ local function bottleneck_get_rating(unit, x, y, has_leadership, is_healer, self
|
|||
|
||||
-- Injured unit positioning
|
||||
if (unit.hitpoints < unit.max_hitpoints) then
|
||||
local healing_rating = self.data.BD_healing_map:get(x, y) or 0
|
||||
local healing_rating = data.BD_healing_map:get(x, y) or 0
|
||||
if (healing_rating > rating) then rating = healing_rating end
|
||||
end
|
||||
|
||||
-- If this did not produce a positive rating, we add a
|
||||
-- distance-based rating, to get units to the bottleneck in the first place
|
||||
if (rating <= 0) and self.data.BD_is_my_territory:get(x, y) then
|
||||
if (rating <= 0) and data.BD_is_my_territory:get(x, y) then
|
||||
local combined_dist = 0
|
||||
self.data.BD_def_map:iter(function(x_def, y_def, v)
|
||||
data.BD_def_map:iter(function(x_def, y_def, v)
|
||||
combined_dist = combined_dist + H.distance_between(x, y, x_def, y_def)
|
||||
end)
|
||||
combined_dist = combined_dist / self.data.BD_def_map:size()
|
||||
combined_dist = combined_dist / data.BD_def_map:size()
|
||||
rating = 1000 - combined_dist * 10.
|
||||
end
|
||||
|
||||
|
@ -177,7 +177,7 @@ local function bottleneck_get_rating(unit, x, y, has_leadership, is_healer, self
|
|||
return rating
|
||||
end
|
||||
|
||||
local function bottleneck_move_out_of_way(unit_in_way, self)
|
||||
local function bottleneck_move_out_of_way(unit_in_way, data)
|
||||
-- Find the best move out of the way for a unit @unit_in_way and choose the
|
||||
-- shortest possible move. Returns nil if no move was found.
|
||||
|
||||
|
@ -193,7 +193,7 @@ local function bottleneck_move_out_of_way(unit_in_way, self)
|
|||
|
||||
local best_reach, best_hex = -9e99
|
||||
for _,loc in ipairs(reach) do
|
||||
if self.data.BD_is_my_territory:get(loc[1], loc[2]) and (not occ_hexes:get(loc[1], loc[2])) then
|
||||
if data.BD_is_my_territory:get(loc[1], loc[2]) and (not occ_hexes:get(loc[1], loc[2])) then
|
||||
-- Criterion: MP left after the move has been done
|
||||
if (loc[3] > best_reach) then
|
||||
best_reach, best_hex = loc[3], { loc[1], loc[2] }
|
||||
|
@ -206,9 +206,9 @@ end
|
|||
|
||||
local ca_bottleneck_move = {}
|
||||
|
||||
function ca_bottleneck_move:evaluation(ai, cfg, self)
|
||||
function ca_bottleneck_move:evaluation(cfg, data)
|
||||
if cfg.active_side_leader and
|
||||
(not MAISD.get_mai_self_data(self.data, cfg.ai_id, "side_leader_activated"))
|
||||
(not MAISD.get_mai_self_data(data, cfg.ai_id, "side_leader_activated"))
|
||||
then
|
||||
local can_still_recruit = false -- Enough gold left for another recruit?
|
||||
for _,recruit_type in ipairs(wesnoth.sides[wesnoth.current.side].recruit) do
|
||||
|
@ -218,12 +218,12 @@ function ca_bottleneck_move:evaluation(ai, cfg, self)
|
|||
end
|
||||
end
|
||||
if (not can_still_recruit) then
|
||||
MAISD.set_mai_self_data(self.data, cfg.ai_id, { side_leader_activated = true })
|
||||
MAISD.set_mai_self_data(data, cfg.ai_id, { side_leader_activated = true })
|
||||
end
|
||||
end
|
||||
|
||||
local units = {}
|
||||
if MAISD.get_mai_self_data(self.data, cfg.ai_id, "side_leader_activated") then
|
||||
if MAISD.get_mai_self_data(data, cfg.ai_id, "side_leader_activated") then
|
||||
units = AH.get_units_with_moves { side = wesnoth.current.side }
|
||||
else
|
||||
units = AH.get_units_with_moves { side = wesnoth.current.side, canrecruit = 'no' }
|
||||
|
@ -231,54 +231,54 @@ function ca_bottleneck_move:evaluation(ai, cfg, self)
|
|||
if (not units[1]) then return 0 end
|
||||
|
||||
-- Set up the array that tells the AI where to defend the bottleneck
|
||||
self.data.BD_def_map = bottleneck_triple_from_keys(cfg.x, cfg.y, 10000)
|
||||
data.BD_def_map = bottleneck_triple_from_keys(cfg.x, cfg.y, 10000)
|
||||
|
||||
-- Territory map, describing which hex is on AI's side of the bottleneck
|
||||
-- This one is a bit expensive, esp. on large maps -> don't delete every move and reuse
|
||||
-- However, after a reload, self.data.BD_is_my_territory is an empty string
|
||||
-- However, after a reload, data.BD_is_my_territory is an empty string
|
||||
-- -> need to recalculate in that case also (the reason is that is_my_territory is not a WML table)
|
||||
if (not self.data.BD_is_my_territory) or (type(self.data.BD_is_my_territory) == 'string') then
|
||||
if (not data.BD_is_my_territory) or (type(data.BD_is_my_territory) == 'string') then
|
||||
local enemy_map = bottleneck_triple_from_keys(cfg.enemy_x, cfg.enemy_y, 10000)
|
||||
self.data.BD_is_my_territory = bottleneck_is_my_territory(self.data.BD_def_map, enemy_map)
|
||||
data.BD_is_my_territory = bottleneck_is_my_territory(data.BD_def_map, enemy_map)
|
||||
end
|
||||
|
||||
-- Healer positioning map
|
||||
if cfg.healer_x and cfg.healer_y then
|
||||
self.data.BD_healer_map = bottleneck_triple_from_keys(cfg.healer_x, cfg.healer_y, 5000)
|
||||
data.BD_healer_map = bottleneck_triple_from_keys(cfg.healer_x, cfg.healer_y, 5000)
|
||||
else
|
||||
self.data.BD_healer_map = bottleneck_create_positioning_map(5000, self)
|
||||
data.BD_healer_map = bottleneck_create_positioning_map(5000, data)
|
||||
end
|
||||
-- Use def_map values for any healer hexes that are defined in def_map as well
|
||||
self.data.BD_healer_map:inter_merge(self.data.BD_def_map,
|
||||
data.BD_healer_map:inter_merge(data.BD_def_map,
|
||||
function(x, y, v1, v2) return v2 or v1 end
|
||||
)
|
||||
|
||||
-- Leadership position map
|
||||
if cfg.leadership_x and cfg.leadership_y then
|
||||
self.data.BD_leadership_map = bottleneck_triple_from_keys(cfg.leadership_x, cfg.leadership_y, 4000)
|
||||
data.BD_leadership_map = bottleneck_triple_from_keys(cfg.leadership_x, cfg.leadership_y, 4000)
|
||||
else
|
||||
self.data.BD_leadership_map = bottleneck_create_positioning_map(4000, self)
|
||||
data.BD_leadership_map = bottleneck_create_positioning_map(4000, data)
|
||||
end
|
||||
-- Use def_map values for any leadership hexes that are defined in def_map as well
|
||||
self.data.BD_leadership_map:inter_merge(self.data.BD_def_map,
|
||||
data.BD_leadership_map:inter_merge(data.BD_def_map,
|
||||
function(x, y, v1, v2) return v2 or v1 end
|
||||
)
|
||||
|
||||
-- Healing map: positions next to healers
|
||||
-- Healers get moved with higher priority, so don't need to check their MP
|
||||
local healers = wesnoth.get_units { side = wesnoth.current.side, ability = "healing" }
|
||||
self.data.BD_healing_map = LS.create()
|
||||
data.BD_healing_map = LS.create()
|
||||
for _,healer in ipairs(healers) do
|
||||
for xa,ya in H.adjacent_tiles(healer.x, healer.y) do
|
||||
-- Cannot be on the line, and needs to be in own territory
|
||||
if self.data.BD_is_my_territory:get(xa, ya) then
|
||||
if data.BD_is_my_territory:get(xa, ya) then
|
||||
local min_dist = 9e99
|
||||
self.data.BD_def_map:iter( function(xd, yd, vd)
|
||||
data.BD_def_map:iter( function(xd, yd, vd)
|
||||
local dist_line = H.distance_between(xa, ya, xd, yd)
|
||||
if (dist_line < min_dist) then min_dist = dist_line end
|
||||
end)
|
||||
if (min_dist > 0) then
|
||||
self.data.BD_healing_map:insert(xa, ya, 3000 + min_dist) -- Farther away from enemy is good
|
||||
data.BD_healing_map:insert(xa, ya, 3000 + min_dist) -- Farther away from enemy is good
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -299,13 +299,13 @@ function ca_bottleneck_move:evaluation(ai, cfg, self)
|
|||
local is_healer = (unit.__cfg.usage == "healer")
|
||||
local has_leadership = AH.has_ability(unit, "leadership")
|
||||
|
||||
local rating = bottleneck_get_rating(unit, unit.x, unit.y, has_leadership, is_healer, self)
|
||||
local rating = bottleneck_get_rating(unit, unit.x, unit.y, has_leadership, is_healer, data)
|
||||
current_rating_map:insert(unit.x, unit.y, rating)
|
||||
|
||||
-- A unit that cannot move any more, (or at least cannot move out of the way)
|
||||
-- must be considered to have a very high rating (it's in the best position
|
||||
-- it can possibly achieve)
|
||||
local best_move_away = bottleneck_move_out_of_way(unit, self)
|
||||
local best_move_away = bottleneck_move_out_of_way(unit, data)
|
||||
if (not best_move_away) then current_rating_map:insert(unit.x, unit.y, 20000) end
|
||||
end
|
||||
|
||||
|
@ -315,7 +315,7 @@ function ca_bottleneck_move:evaluation(ai, cfg, self)
|
|||
local attacks = {}
|
||||
for _,enemy in ipairs(enemies) do
|
||||
for xa,ya in H.adjacent_tiles(enemy.x, enemy.y) do
|
||||
if self.data.BD_is_my_territory:get(xa, ya) then
|
||||
if data.BD_is_my_territory:get(xa, ya) then
|
||||
local unit_in_way = wesnoth.get_unit(xa, ya)
|
||||
local data = { x = xa, y = ya,
|
||||
defender = enemy,
|
||||
|
@ -346,7 +346,7 @@ function ca_bottleneck_move:evaluation(ai, cfg, self)
|
|||
|
||||
local reach = wesnoth.find_reach(unit)
|
||||
for _,loc in ipairs(reach) do
|
||||
local rating = bottleneck_get_rating(unit, loc[1], loc[2], has_leadership, is_healer, self)
|
||||
local rating = bottleneck_get_rating(unit, loc[1], loc[2], has_leadership, is_healer, data)
|
||||
|
||||
-- A move is only considered if it improves the overall rating,
|
||||
-- that is, its rating must be higher than:
|
||||
|
@ -408,7 +408,7 @@ function ca_bottleneck_move:evaluation(ai, cfg, self)
|
|||
-- Small penalty if there's a unit in the way
|
||||
-- We also need to check whether this unit can actually move out of the way
|
||||
if attack.unit_in_way then
|
||||
if bottleneck_move_out_of_way(attack.unit_in_way, self) then
|
||||
if bottleneck_move_out_of_way(attack.unit_in_way, data) then
|
||||
level_up_rating = level_up_rating - 0.001
|
||||
else
|
||||
level_up_rating = 0
|
||||
|
@ -417,8 +417,8 @@ function ca_bottleneck_move:evaluation(ai, cfg, self)
|
|||
|
||||
if (level_up_rating > max_rating) then
|
||||
max_rating, best_unit, best_hex = level_up_rating, unit, { loc[1], loc[2] }
|
||||
self.data.BD_level_up_defender = attack.defender
|
||||
self.data.BD_level_up_weapon = n_weapon
|
||||
data.BD_level_up_defender = attack.defender
|
||||
data.BD_level_up_weapon = n_weapon
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -428,7 +428,7 @@ function ca_bottleneck_move:evaluation(ai, cfg, self)
|
|||
|
||||
-- Set the variables for the exec() function
|
||||
if (not best_hex) then
|
||||
self.data.BD_bottleneck_moves_done = true
|
||||
data.BD_bottleneck_moves_done = true
|
||||
else
|
||||
-- If there's another unit in the best location, moving it out of the way becomes the best move
|
||||
local unit_in_way = wesnoth.get_units { x = best_hex[1], y = best_hex[2],
|
||||
|
@ -436,23 +436,23 @@ function ca_bottleneck_move:evaluation(ai, cfg, self)
|
|||
}[1]
|
||||
|
||||
if unit_in_way then
|
||||
best_hex = bottleneck_move_out_of_way(unit_in_way, self)
|
||||
best_hex = bottleneck_move_out_of_way(unit_in_way, data)
|
||||
best_unit = unit_in_way
|
||||
self.data.BD_level_up_defender = nil
|
||||
self.data.BD_level_up_weapon = nil
|
||||
data.BD_level_up_defender = nil
|
||||
data.BD_level_up_weapon = nil
|
||||
end
|
||||
|
||||
self.data.BD_bottleneck_moves_done = false
|
||||
self.data.BD_unit, self.data.BD_hex = best_unit, best_hex
|
||||
data.BD_bottleneck_moves_done = false
|
||||
data.BD_unit, data.BD_hex = best_unit, best_hex
|
||||
end
|
||||
|
||||
return cfg.ca_score
|
||||
end
|
||||
|
||||
function ca_bottleneck_move:execution(ai, cfg, self)
|
||||
if self.data.BD_bottleneck_moves_done then
|
||||
function ca_bottleneck_move:execution(cfg, data)
|
||||
if data.BD_bottleneck_moves_done then
|
||||
local units = {}
|
||||
if MAISD.get_mai_self_data(self.data, cfg.ai_id, "side_leader_activated") then
|
||||
if MAISD.get_mai_self_data(data, cfg.ai_id, "side_leader_activated") then
|
||||
units = AH.get_units_with_moves { side = wesnoth.current.side }
|
||||
else
|
||||
units = AH.get_units_with_moves { side = wesnoth.current.side, canrecruit = 'no' }
|
||||
|
@ -462,23 +462,23 @@ function ca_bottleneck_move:execution(ai, cfg, self)
|
|||
AH.checked_stopunit_moves(ai, unit)
|
||||
end
|
||||
else
|
||||
if (self.data.BD_unit.x ~= self.data.BD_hex[1]) or (self.data.BD_unit.y ~= self.data.BD_hex[2]) then
|
||||
if (data.BD_unit.x ~= data.BD_hex[1]) or (data.BD_unit.y ~= data.BD_hex[2]) then
|
||||
-- Don't want full move, as this might be stepping out of the way
|
||||
AH.checked_move(ai, self.data.BD_unit, self.data.BD_hex[1], self.data.BD_hex[2])
|
||||
AH.checked_move(ai, data.BD_unit, data.BD_hex[1], data.BD_hex[2])
|
||||
end
|
||||
if (not self.data.BD_unit) or (not self.data.BD_unit.valid) then return end
|
||||
if (not data.BD_unit) or (not data.BD_unit.valid) then return end
|
||||
|
||||
if self.data.BD_level_up_defender then
|
||||
AH.checked_attack(ai, self.data.BD_unit, self.data.BD_level_up_defender, self.data.BD_level_up_weapon)
|
||||
if data.BD_level_up_defender then
|
||||
AH.checked_attack(ai, data.BD_unit, data.BD_level_up_defender, data.BD_level_up_weapon)
|
||||
end
|
||||
end
|
||||
|
||||
-- Now delete almost everything
|
||||
-- Keep only self.data.BD_is_my_territory because it is very expensive
|
||||
self.data.BD_unit, self.data.BD_hex = nil, nil
|
||||
self.data.BD_level_up_defender, self.data.BD_level_up_weapon = nil, nil
|
||||
self.data.BD_bottleneck_moves_done = nil
|
||||
self.data.BD_def_map, self.data.BD_healer_map, self.data.BD_leadership_map, self.data.BD_healing_map = nil, nil, nil, nil
|
||||
-- Keep only data.BD_is_my_territory because it is very expensive
|
||||
data.BD_unit, data.BD_hex = nil, nil
|
||||
data.BD_level_up_defender, data.BD_level_up_weapon = nil, nil
|
||||
data.BD_bottleneck_moves_done = nil
|
||||
data.BD_def_map, data.BD_healer_map, data.BD_leadership_map, data.BD_healing_map = nil, nil, nil, nil
|
||||
end
|
||||
|
||||
return ca_bottleneck_move
|
||||
|
|
|
@ -2,7 +2,7 @@ local H = wesnoth.require "lua/helper.lua"
|
|||
local AH = wesnoth.require "ai/lua/ai_helper.lua"
|
||||
|
||||
local function get_coward(cfg)
|
||||
local filter = cfg.filter or { id = cfg.id }
|
||||
local filter = H.get_child(cfg, "filter") or { id = cfg.id }
|
||||
local coward = AH.get_units_with_moves {
|
||||
side = wesnoth.current.side,
|
||||
{ "and", filter }
|
||||
|
@ -13,17 +13,17 @@ end
|
|||
|
||||
local ca_coward = {}
|
||||
|
||||
function ca_coward:evaluation(ai, cfg)
|
||||
function ca_coward:evaluation(cfg)
|
||||
if get_coward(cfg) then return cfg.ca_score end
|
||||
return 0
|
||||
end
|
||||
|
||||
function ca_coward:execution(ai, cfg)
|
||||
function ca_coward:execution(cfg)
|
||||
local coward = get_coward(cfg)
|
||||
local reach = wesnoth.find_reach(coward)
|
||||
|
||||
local filter_second =
|
||||
cfg.filter_second
|
||||
H.get_child(cfg, "filter_second")
|
||||
or { { "filter_side", { { "enemy_of", { side = wesnoth.current.side } } } } }
|
||||
local enemies = wesnoth.get_units {
|
||||
{ "and", filter_second },
|
||||
|
|
|
@ -20,19 +20,13 @@ function ca_fast_attack_utils.get_avoid_map(cfg)
|
|||
-- Use [micro_ai][avoid] tag with priority over [ai][avoid].
|
||||
-- If neither is given, return an empty location set.
|
||||
|
||||
local avoid_tag
|
||||
local avoid_tag = H.get_child(cfg, "avoid")
|
||||
|
||||
if cfg.avoid then
|
||||
avoid_tag = cfg.avoid
|
||||
else
|
||||
if not avoid_tag then
|
||||
return LS.of_pairs(ai.aspects.avoid)
|
||||
end
|
||||
|
||||
if avoid_tag then
|
||||
return LS.of_pairs(wesnoth.get_locations(avoid_tag))
|
||||
else
|
||||
return LS.create()
|
||||
end
|
||||
return LS.of_pairs(wesnoth.get_locations(avoid_tag))
|
||||
end
|
||||
|
||||
function ca_fast_attack_utils.gamedata_setup()
|
||||
|
|
|
@ -5,12 +5,12 @@ local LS = wesnoth.require "lua/location_set.lua"
|
|||
|
||||
local ca_fast_combat = {}
|
||||
|
||||
function ca_fast_combat:evaluation(ai, cfg, self)
|
||||
self.data.move_cache = { turn = wesnoth.current.turn }
|
||||
self.data.gamedata = FAU.gamedata_setup()
|
||||
function ca_fast_combat:evaluation(cfg, data)
|
||||
data.move_cache = { turn = wesnoth.current.turn }
|
||||
data.gamedata = FAU.gamedata_setup()
|
||||
|
||||
local filter_own = cfg.filter
|
||||
local filter_enemy = cfg.filter_second
|
||||
local filter_own = H.get_child(cfg, "filter")
|
||||
local filter_enemy = H.get_child(cfg, "filter_second")
|
||||
if (not filter_own) and (not filter_enemy) then
|
||||
local ai_tag = H.get_child(wesnoth.sides[wesnoth.current.side].__cfg, 'ai')
|
||||
for aspect in H.child_range(ai_tag, 'aspect') do
|
||||
|
@ -24,20 +24,20 @@ function ca_fast_combat:evaluation(ai, cfg, self)
|
|||
end
|
||||
end
|
||||
|
||||
if (not self.data.fast_combat_units) or (not self.data.fast_combat_units[1]) then
|
||||
self.data.fast_combat_units = wesnoth.get_units {
|
||||
if (not data.fast_combat_units) or (not data.fast_combat_units[1]) then
|
||||
data.fast_combat_units = wesnoth.get_units {
|
||||
side = wesnoth.current.side,
|
||||
canrecruit = 'no',
|
||||
{ "and", filter_own }
|
||||
}
|
||||
|
||||
if (not self.data.fast_combat_units[1]) then return 0 end
|
||||
if (not data.fast_combat_units[1]) then return 0 end
|
||||
|
||||
-- For speed reasons, we'll go through the arrays from the end, so they are sorted backwards
|
||||
if cfg.weak_units_first then
|
||||
table.sort(self.data.fast_combat_units, function(a,b) return a.hitpoints > b.hitpoints end)
|
||||
table.sort(data.fast_combat_units, function(a,b) return a.hitpoints > b.hitpoints end)
|
||||
else
|
||||
table.sort(self.data.fast_combat_units, function(a,b) return a.hitpoints < b.hitpoints end)
|
||||
table.sort(data.fast_combat_units, function(a,b) return a.hitpoints < b.hitpoints end)
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -74,10 +74,10 @@ function ca_fast_combat:evaluation(ai, cfg, self)
|
|||
-- Get the locations to be avoided
|
||||
local avoid_map = FAU.get_avoid_map(cfg)
|
||||
|
||||
for i = #self.data.fast_combat_units,1,-1 do
|
||||
local unit = self.data.fast_combat_units[i]
|
||||
local unit_info = FAU.get_unit_info(unit, self.data.gamedata)
|
||||
local unit_copy = FAU.get_unit_copy(unit.id, self.data.gamedata)
|
||||
for i = #data.fast_combat_units,1,-1 do
|
||||
local unit = data.fast_combat_units[i]
|
||||
local unit_info = FAU.get_unit_info(unit, data.gamedata)
|
||||
local unit_copy = FAU.get_unit_copy(unit.id, data.gamedata)
|
||||
|
||||
if (unit.attacks_left > 0) and (H.get_child(unit.__cfg, 'attack')) then
|
||||
local attacks = AH.get_attacks({ unit }, { include_occupied = cfg.include_occupied_attack_hexes })
|
||||
|
@ -89,16 +89,16 @@ function ca_fast_combat:evaluation(ai, cfg, self)
|
|||
and (not avoid_map:get(attack.dst.x, attack.dst.y))
|
||||
then
|
||||
local target = wesnoth.get_unit(attack.target.x, attack.target.y)
|
||||
local target_info = FAU.get_unit_info(target, self.data.gamedata)
|
||||
local target_info = FAU.get_unit_info(target, data.gamedata)
|
||||
|
||||
local att_stat, def_stat = FAU.battle_outcome(
|
||||
unit_copy, target, { attack.dst.x, attack.dst.y },
|
||||
unit_info, target_info, self.data.gamedata, self.data.move_cache
|
||||
unit_info, target_info, data.gamedata, data.move_cache
|
||||
)
|
||||
|
||||
local rating, attacker_rating, defender_rating, extra_rating = FAU.attack_rating(
|
||||
{ unit_info }, target_info, { { attack.dst.x, attack.dst.y } },
|
||||
{ att_stat }, def_stat, self.data.gamedata,
|
||||
{ att_stat }, def_stat, data.gamedata,
|
||||
{
|
||||
own_value_weight = own_value_weight,
|
||||
leader_weight = cfg.leader_weight
|
||||
|
@ -114,30 +114,30 @@ function ca_fast_combat:evaluation(ai, cfg, self)
|
|||
end
|
||||
|
||||
if best_target then
|
||||
self.data.fast_combat_unit_i = i
|
||||
self.data.fast_target, self.data.fast_dst = best_target, best_dst
|
||||
data.fast_combat_unit_i = i
|
||||
data.fast_target, data.fast_dst = best_target, best_dst
|
||||
return cfg.ca_score
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
self.data.fast_combat_units[i] = nil
|
||||
data.fast_combat_units[i] = nil
|
||||
end
|
||||
|
||||
return 0
|
||||
end
|
||||
|
||||
function ca_fast_combat:execution(ai, cfg, self)
|
||||
local unit = self.data.fast_combat_units[self.data.fast_combat_unit_i]
|
||||
AH.movefull_outofway_stopunit(ai, unit, self.data.fast_dst.x, self.data.fast_dst.y)
|
||||
function ca_fast_combat:execution(cfg, data)
|
||||
local unit = data.fast_combat_units[data.fast_combat_unit_i]
|
||||
AH.movefull_outofway_stopunit(ai, unit, data.fast_dst.x, data.fast_dst.y)
|
||||
|
||||
if (not unit) or (not unit.valid) then return end
|
||||
if (not self.data.fast_target) or (not self.data.fast_target.valid) then return end
|
||||
if (H.distance_between(unit.x, unit.y, self.data.fast_target.x, self.data.fast_target.y) ~= 1) then return end
|
||||
if (not data.fast_target) or (not data.fast_target.valid) then return end
|
||||
if (H.distance_between(unit.x, unit.y, data.fast_target.x, data.fast_target.y) ~= 1) then return end
|
||||
|
||||
AH.checked_attack(ai, unit, self.data.fast_target)
|
||||
AH.checked_attack(ai, unit, data.fast_target)
|
||||
|
||||
self.data.fast_combat_units[self.data.fast_combat_unit_i] = nil
|
||||
data.fast_combat_units[data.fast_combat_unit_i] = nil
|
||||
end
|
||||
|
||||
return ca_fast_combat
|
||||
|
|
|
@ -5,7 +5,7 @@ local LS = wesnoth.require "lua/location_set.lua"
|
|||
|
||||
local ca_fast_combat_leader = {}
|
||||
|
||||
function ca_fast_combat_leader:evaluation(ai, cfg, self)
|
||||
function ca_fast_combat_leader:evaluation(cfg, data)
|
||||
-- Some parts of this are very similar to ca_fast_combat.lua.
|
||||
-- However, for speed reasons we really want this to be a separate CA, so
|
||||
-- that the (more expensive) calculations for keeping the leader safe only
|
||||
|
@ -15,11 +15,11 @@ function ca_fast_combat_leader:evaluation(ai, cfg, self)
|
|||
leader_attack_max_units = (cfg and cfg.leader_attack_max_units) or 3
|
||||
leader_additional_threat = (cfg and cfg.leader_additional_threat) or 1
|
||||
|
||||
self.data.move_cache = { turn = wesnoth.current.turn }
|
||||
self.data.gamedata = FAU.gamedata_setup()
|
||||
data.move_cache = { turn = wesnoth.current.turn }
|
||||
data.gamedata = FAU.gamedata_setup()
|
||||
|
||||
local filter_own = cfg.filter
|
||||
local filter_enemy = cfg.filter_second
|
||||
local filter_own = H.get_child(cfg, "filter")
|
||||
local filter_enemy = H.get_child(cfg, "filter_second")
|
||||
if (not filter_own) and (not filter_enemy) then
|
||||
local ai_tag = H.get_child(wesnoth.sides[wesnoth.current.side].__cfg, 'ai')
|
||||
for aspect in H.child_range(ai_tag, 'aspect') do
|
||||
|
@ -108,8 +108,8 @@ function ca_fast_combat_leader:evaluation(ai, cfg, self)
|
|||
end
|
||||
end
|
||||
|
||||
local leader_info = FAU.get_unit_info(leader, self.data.gamedata)
|
||||
local leader_copy = FAU.get_unit_copy(leader.id, self.data.gamedata)
|
||||
local leader_info = FAU.get_unit_info(leader, data.gamedata)
|
||||
local leader_copy = FAU.get_unit_copy(leader.id, data.gamedata)
|
||||
|
||||
-- If threatened_leader_fights=yes, check out the current threat (power only,
|
||||
-- not units) on the AI leader
|
||||
|
@ -156,16 +156,16 @@ function ca_fast_combat_leader:evaluation(ai, cfg, self)
|
|||
|
||||
if acceptable_attack then
|
||||
local target = wesnoth.get_unit(attack.target.x, attack.target.y)
|
||||
local target_info = FAU.get_unit_info(target, self.data.gamedata)
|
||||
local target_info = FAU.get_unit_info(target, data.gamedata)
|
||||
|
||||
local att_stat, def_stat = FAU.battle_outcome(
|
||||
leader_copy, target, { attack.dst.x, attack.dst.y },
|
||||
leader_info, target_info, self.data.gamedata, self.data.move_cache
|
||||
leader_info, target_info, data.gamedata, data.move_cache
|
||||
)
|
||||
|
||||
local rating, attacker_rating, defender_rating, extra_rating = FAU.attack_rating(
|
||||
{ leader_info }, target_info, { { attack.dst.x, attack.dst.y } },
|
||||
{ att_stat }, def_stat, self.data.gamedata,
|
||||
{ att_stat }, def_stat, data.gamedata,
|
||||
{
|
||||
own_value_weight = own_value_weight,
|
||||
leader_weight = cfg.leader_weight
|
||||
|
@ -182,8 +182,8 @@ function ca_fast_combat_leader:evaluation(ai, cfg, self)
|
|||
end
|
||||
|
||||
if best_target then
|
||||
self.data.leader = leader
|
||||
self.data.fast_target, self.data.fast_dst = best_target, best_dst
|
||||
data.leader = leader
|
||||
data.fast_target, data.fast_dst = best_target, best_dst
|
||||
return cfg.ca_score
|
||||
end
|
||||
end
|
||||
|
@ -191,17 +191,17 @@ function ca_fast_combat_leader:evaluation(ai, cfg, self)
|
|||
return 0
|
||||
end
|
||||
|
||||
function ca_fast_combat_leader:execution(ai, cfg, self)
|
||||
local leader = self.data.leader
|
||||
AH.movefull_outofway_stopunit(ai, leader, self.data.fast_dst.x, self.data.fast_dst.y)
|
||||
function ca_fast_combat_leader:execution(cfg, data)
|
||||
local leader = data.leader
|
||||
AH.movefull_outofway_stopunit(ai, leader, data.fast_dst.x, data.fast_dst.y)
|
||||
|
||||
if (not leader) or (not leader.valid) then return end
|
||||
if (not self.data.fast_target) or (not self.data.fast_target.valid) then return end
|
||||
if (H.distance_between(leader.x, leader.y, self.data.fast_target.x, self.data.fast_target.y) ~= 1) then return end
|
||||
if (not data.fast_target) or (not data.fast_target.valid) then return end
|
||||
if (H.distance_between(leader.x, leader.y, data.fast_target.x, data.fast_target.y) ~= 1) then return end
|
||||
|
||||
AH.checked_attack(ai, leader, self.data.fast_target)
|
||||
AH.checked_attack(ai, leader, data.fast_target)
|
||||
|
||||
self.data.leader = nil
|
||||
data.leader = nil
|
||||
end
|
||||
|
||||
return ca_fast_combat_leader
|
||||
|
|
|
@ -4,14 +4,14 @@ local FAU = wesnoth.require "ai/micro_ais/cas/ca_fast_attack_utils.lua"
|
|||
|
||||
local ca_fast_move = {}
|
||||
|
||||
function ca_fast_move:evaluation(ai, cfg, self)
|
||||
function ca_fast_move:evaluation(cfg)
|
||||
local unit = AH.get_units_with_moves { side = wesnoth.current.side, canrecruit = 'no' }[1]
|
||||
|
||||
if unit then return 20000 end
|
||||
return 0
|
||||
end
|
||||
|
||||
function ca_fast_move:execution(ai, cfg, self)
|
||||
function ca_fast_move:execution(cfg)
|
||||
local move_cost_factor = cfg.move_cost_factor or 2.0
|
||||
if (move_cost_factor < 1.1) then move_cost_factor = 1.1 end
|
||||
|
||||
|
|
|
@ -32,12 +32,12 @@ end
|
|||
|
||||
local ca_forest_animals_move = {}
|
||||
|
||||
function ca_forest_animals_move:evaluation(ai, cfg)
|
||||
function ca_forest_animals_move:evaluation(cfg)
|
||||
if get_forest_animals(cfg)[1] then return cfg.ca_score end
|
||||
return 0
|
||||
end
|
||||
|
||||
function ca_forest_animals_move:execution(ai, cfg)
|
||||
function ca_forest_animals_move:execution(cfg)
|
||||
-- These animals run from any enemy
|
||||
local forest_animals = get_forest_animals(cfg)
|
||||
local enemies = wesnoth.get_units { { "filter_side", { { "enemy_of", {side = wesnoth.current.side } } } } }
|
||||
|
@ -73,7 +73,7 @@ function ca_forest_animals_move:execution(ai, cfg)
|
|||
end
|
||||
|
||||
-- If no close enemies, do a random move
|
||||
local wander_terrain = cfg.filter_location or {}
|
||||
local wander_terrain = H.get_child(cfg, "filter_location") or {}
|
||||
if (not close_enemies[1]) then
|
||||
local reach = AH.get_reachable_unocc(unit)
|
||||
local width, height = wesnoth.get_map_size()
|
||||
|
|
|
@ -4,7 +4,7 @@ local AH = wesnoth.require "ai/lua/ai_helper.lua"
|
|||
|
||||
local ca_forest_animals_new_rabbit = {}
|
||||
|
||||
function ca_forest_animals_new_rabbit:evaluation(ai, cfg)
|
||||
function ca_forest_animals_new_rabbit:evaluation(cfg)
|
||||
-- Put new rabbits on map if there are fewer than cfg.rabbit_number
|
||||
-- To end this, we'll let the CA black-list itself
|
||||
|
||||
|
@ -12,7 +12,7 @@ function ca_forest_animals_new_rabbit:evaluation(ai, cfg)
|
|||
return cfg.ca_score
|
||||
end
|
||||
|
||||
function ca_forest_animals_new_rabbit:execution(ai, cfg)
|
||||
function ca_forest_animals_new_rabbit:execution(cfg)
|
||||
local number = cfg.rabbit_number or 6
|
||||
local rabbit_enemy_distance = cfg.rabbit_enemy_distance or 3
|
||||
|
||||
|
|
|
@ -19,7 +19,7 @@ end
|
|||
|
||||
local ca_forest_animals_tusker_attack = {}
|
||||
|
||||
function ca_forest_animals_tusker_attack:evaluation(ai, cfg)
|
||||
function ca_forest_animals_tusker_attack:evaluation(cfg)
|
||||
-- Check whether there is an enemy next to a tusklet and attack it ("protective parents" AI)
|
||||
|
||||
if (not cfg.tusker_type) or (not cfg.tusklet_type) then return 0 end
|
||||
|
@ -28,7 +28,7 @@ function ca_forest_animals_tusker_attack:evaluation(ai, cfg)
|
|||
return cfg.ca_score
|
||||
end
|
||||
|
||||
function ca_forest_animals_tusker_attack:execution(ai, cfg)
|
||||
function ca_forest_animals_tusker_attack:execution(cfg)
|
||||
local tuskers = get_tuskers(cfg)
|
||||
local adjacent_enemies = get_adjacent_enemies(cfg)
|
||||
|
||||
|
|
|
@ -19,7 +19,7 @@ end
|
|||
|
||||
local ca_forest_animals_tusklet_move = {}
|
||||
|
||||
function ca_forest_animals_tusklet_move:evaluation(ai, cfg)
|
||||
function ca_forest_animals_tusklet_move:evaluation(cfg)
|
||||
-- Tusklets will simply move toward the closest tusker, without regard for anything else
|
||||
-- Except if no tuskers are left, in which case ca_forest_animals_move takes over and does a random move
|
||||
|
||||
|
@ -29,7 +29,7 @@ function ca_forest_animals_tusklet_move:evaluation(ai, cfg)
|
|||
return cfg.ca_score
|
||||
end
|
||||
|
||||
function ca_forest_animals_tusklet_move:execution(ai, cfg)
|
||||
function ca_forest_animals_tusklet_move:execution(cfg)
|
||||
local tusklets = get_tusklets(cfg)
|
||||
local tuskers = get_tuskers(cfg)
|
||||
|
||||
|
|
|
@ -15,12 +15,12 @@ local function custom_cost(x, y, unit, enemy_map, enemy_attack_map, multiplier)
|
|||
return move_cost
|
||||
end
|
||||
|
||||
local ca_goto = {}
|
||||
local ca_goto, GO_units, GO_locs = {}
|
||||
|
||||
function ca_goto:evaluation(ai, cfg, self)
|
||||
function ca_goto:evaluation(cfg, data)
|
||||
-- If cfg.release_all_units_at_goal is set, check whether the goal has
|
||||
-- already been reached, in which case we do not do anything
|
||||
if MAISD.get_mai_self_data(self.data, cfg.ai_id, "release_all") then
|
||||
if MAISD.get_mai_self_data(data, cfg.ai_id, "release_all") then
|
||||
return 0
|
||||
end
|
||||
|
||||
|
@ -30,7 +30,7 @@ function ca_goto:evaluation(ai, cfg, self)
|
|||
local all_locs = wesnoth.get_locations {
|
||||
x = '1-' .. width,
|
||||
y = '1-' .. height,
|
||||
{ "and", cfg.filter_location }
|
||||
{ "and", H.get_child(cfg, "filter_location") }
|
||||
}
|
||||
if (#all_locs == 0) then return 0 end
|
||||
|
||||
|
@ -40,17 +40,17 @@ function ca_goto:evaluation(ai, cfg, self)
|
|||
if cfg.unique_goals then
|
||||
-- First, some cleanup of previous turn data
|
||||
local str = 'goal_taken_' .. (wesnoth.current.turn - 1)
|
||||
local old_goals = MAISD.get_mai_self_data(self.data, cfg.ai_id)
|
||||
local old_goals = MAISD.get_mai_self_data(data, cfg.ai_id)
|
||||
for goal,_ in pairs(old_goals) do
|
||||
if string.find(goal, str) then
|
||||
old_goals[goal] = nil -- This also removes it from self.data
|
||||
old_goals[goal] = nil -- This also removes it from data
|
||||
end
|
||||
end
|
||||
|
||||
-- Now on to the current turn
|
||||
for _,loc in ipairs(all_locs) do
|
||||
local str = 'goal_taken_' .. wesnoth.current.turn .. '_' .. loc[1] .. '_' .. loc[2]
|
||||
if (not MAISD.get_mai_self_data(self.data, cfg.ai_id, str)) then
|
||||
if (not MAISD.get_mai_self_data(data, cfg.ai_id, str)) then
|
||||
table.insert(locs, loc)
|
||||
end
|
||||
end
|
||||
|
@ -61,7 +61,7 @@ function ca_goto:evaluation(ai, cfg, self)
|
|||
|
||||
local all_units = AH.get_units_with_moves {
|
||||
side = wesnoth.current.side,
|
||||
{ "and", cfg.filter }
|
||||
{ "and", H.get_child(cfg, "filter") }
|
||||
}
|
||||
|
||||
local units = {}
|
||||
|
@ -76,14 +76,14 @@ function ca_goto:evaluation(ai, cfg, self)
|
|||
end
|
||||
if (not units[1]) then return 0 end
|
||||
|
||||
-- Now store units and locs in self.data, so that we don't need to duplicate this in the exec function
|
||||
self.data.GO_units, self.data.GO_locs = units, locs
|
||||
-- Now store units and locs, so that we don't need to duplicate this in the exec function
|
||||
GO_units, GO_locs = units, locs
|
||||
|
||||
return cfg.ca_score
|
||||
end
|
||||
|
||||
function ca_goto:execution(ai, cfg, self)
|
||||
local units, locs = self.data.GO_units, self.data.GO_locs
|
||||
function ca_goto:execution(cfg, data)
|
||||
local units, locs = GO_units, GO_locs
|
||||
|
||||
local enemy_map, enemy_attack_map
|
||||
if cfg.avoid_enemies then
|
||||
|
@ -150,7 +150,7 @@ function ca_goto:execution(ai, cfg, self)
|
|||
end
|
||||
end
|
||||
|
||||
-- Make all hexes within the unit's current MP equaivalent
|
||||
-- Make all hexes within the unit's current MP equivalent
|
||||
if (cost <= unit.moves) then cost = 0 end
|
||||
|
||||
local rating = - cost
|
||||
|
@ -174,7 +174,7 @@ function ca_goto:execution(ai, cfg, self)
|
|||
local str = 'goal_taken_' .. wesnoth.current.turn .. '_' .. closest_hex[1] .. '_' .. closest_hex[2]
|
||||
local tmp_table = {}
|
||||
tmp_table[str] = true
|
||||
MAISD.insert_mai_self_data(self.data, cfg.ai_id, tmp_table)
|
||||
MAISD.insert_mai_self_data(data, cfg.ai_id, tmp_table)
|
||||
end
|
||||
|
||||
-- If any of the non-standard path finding options were used,
|
||||
|
@ -227,12 +227,12 @@ function ca_goto:execution(ai, cfg, self)
|
|||
end
|
||||
|
||||
if cfg.release_all_units_at_goal then
|
||||
MAISD.insert_mai_self_data(self.data, cfg.ai_id, { release_all = true })
|
||||
MAISD.insert_mai_self_data(data, cfg.ai_id, { release_all = true })
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
self.data.GO_units, self.data.GO_locs = nil, nil
|
||||
GO_units, GO_locs = nil, nil
|
||||
end
|
||||
|
||||
return ca_goto
|
||||
|
|
|
@ -7,27 +7,28 @@ local MAISD = wesnoth.require "ai/micro_ais/micro_ai_self_data.lua"
|
|||
local function get_hang_out_units(cfg)
|
||||
local units = AH.get_units_with_moves {
|
||||
side = wesnoth.current.side,
|
||||
{ "and", cfg.filter }
|
||||
{ "and", H.get_child(cfg, "filter") }
|
||||
}
|
||||
return units
|
||||
end
|
||||
|
||||
local ca_hang_out = {}
|
||||
|
||||
function ca_hang_out:evaluation(ai, cfg, self)
|
||||
function ca_hang_out:evaluation(cfg, data)
|
||||
-- Return 0 if the mobilize condition has previously been met
|
||||
if MAISD.get_mai_self_data(self.data, cfg.ai_id, "mobilize_units") then
|
||||
if MAISD.get_mai_self_data(data, cfg.ai_id, "mobilize_units") then
|
||||
return 0
|
||||
end
|
||||
|
||||
-- Otherwise check if any of the mobilize conditions are now met
|
||||
if (cfg.mobilize_condition and wesnoth.eval_conditional(cfg.mobilize_condition))
|
||||
local mobilize_condition = H.get_child(cfg, "mobilize_condition")
|
||||
if (mobilize_condition and wesnoth.eval_conditional(mobilize_condition))
|
||||
or (cfg.mobilize_on_gold_less_than and (wesnoth.sides[wesnoth.current.side].gold < cfg.mobilize_on_gold_less_than))
|
||||
then
|
||||
MAISD.insert_mai_self_data(self.data, cfg.ai_id, { mobilize_units = true })
|
||||
MAISD.insert_mai_self_data(data, cfg.ai_id, { mobilize_units = true })
|
||||
|
||||
-- Need to unmark all units also (all units, with and without moves)
|
||||
local units = wesnoth.get_units { side = wesnoth.current.side, { "and", cfg.filter } }
|
||||
local units = wesnoth.get_units { side = wesnoth.current.side, { "and", H.get_child(cfg, "filter") } }
|
||||
for _,unit in ipairs(units) do
|
||||
MAIUV.delete_mai_unit_variables(unit, cfg.ai_id)
|
||||
end
|
||||
|
@ -39,12 +40,12 @@ function ca_hang_out:evaluation(ai, cfg, self)
|
|||
return 0
|
||||
end
|
||||
|
||||
function ca_hang_out:execution(ai, cfg, self)
|
||||
function ca_hang_out:execution(cfg)
|
||||
local units = get_hang_out_units(cfg)
|
||||
|
||||
-- Get the locations close to which the units should hang out
|
||||
-- cfg.filter_location defaults to the location of the side leader(s)
|
||||
local filter_location = cfg.filter_location or {
|
||||
local filter_location = H.get_child(cfg, "filter_location") or {
|
||||
{ "filter", { side = wesnoth.current.side, canrecruit = "yes" } }
|
||||
}
|
||||
|
||||
|
@ -58,11 +59,10 @@ function ca_hang_out:execution(ai, cfg, self)
|
|||
-- Get map of locations to be avoided.
|
||||
-- Use [micro_ai][avoid] tag with priority over [ai][avoid].
|
||||
-- If neither is given, default to all castle terrain.
|
||||
-- ai.get_avoid() cannot be used as it always returns an array, even when the aspect is not set,
|
||||
-- and an empty array could also mean that no hexes match the filter
|
||||
local avoid_tag = H.get_child(cfg, "avoid")
|
||||
local avoid_map
|
||||
if cfg.avoid then
|
||||
avoid_map = LS.of_pairs(wesnoth.get_locations(cfg.avoid))
|
||||
if avoid_tag then
|
||||
avoid_map = LS.of_pairs(wesnoth.get_locations(avoid_tag))
|
||||
else
|
||||
local ai_tag = H.get_child(wesnoth.sides[wesnoth.current.side].__cfg, 'ai')
|
||||
for aspect in H.child_range(ai_tag, 'aspect') do
|
||||
|
|
|
@ -3,7 +3,7 @@ local W = H.set_wml_action_metatable {}
|
|||
|
||||
local ca_healer_initialize = {}
|
||||
|
||||
function ca_healer_initialize:evaluation(ai)
|
||||
function ca_healer_initialize:evaluation()
|
||||
-- Set variables and aspects so that healers are excluded from attacks at beginning of turn
|
||||
-- This will be blacklisted after first execution each turn
|
||||
|
||||
|
@ -11,7 +11,7 @@ function ca_healer_initialize:evaluation(ai)
|
|||
return score
|
||||
end
|
||||
|
||||
function ca_healer_initialize:execution(ai, cfg, self)
|
||||
function ca_healer_initialize:execution(cfg, data)
|
||||
W.modify_ai {
|
||||
side = wesnoth.current.side,
|
||||
action = "try_delete",
|
||||
|
@ -27,14 +27,14 @@ function ca_healer_initialize:execution(ai, cfg, self)
|
|||
id = "no_healers_attack",
|
||||
invalidate_on_gamestate_change = "yes",
|
||||
{ "filter_own", {
|
||||
{ "not", { ability = "healing", { "and", cfg.filter } } }
|
||||
{ "not", { ability = "healing", { "and", H.get_child(cfg, "filter") } } }
|
||||
} }
|
||||
} }
|
||||
}
|
||||
|
||||
-- We also need to set the score of healer moves to happen after
|
||||
-- combat (of other units) at beginning of turn
|
||||
self.data.HS_healer_move_score = 95000
|
||||
data.HS_healer_move_score = 95000
|
||||
end
|
||||
|
||||
return ca_healer_initialize
|
||||
|
|
|
@ -3,7 +3,7 @@ local W = H.set_wml_action_metatable {}
|
|||
|
||||
local ca_healer_may_attack = {}
|
||||
|
||||
function ca_healer_may_attack:evaluation(ai)
|
||||
function ca_healer_may_attack:evaluation()
|
||||
-- After attacks by all other units are done, reset things so that healers can attack, if desired
|
||||
-- This will be blacklisted after first execution each turn
|
||||
|
||||
|
@ -11,7 +11,7 @@ function ca_healer_may_attack:evaluation(ai)
|
|||
return score
|
||||
end
|
||||
|
||||
function ca_healer_may_attack:execution(ai, cfg, self)
|
||||
function ca_healer_may_attack:execution(cfg, data)
|
||||
W.modify_ai {
|
||||
side = wesnoth.current.side,
|
||||
action = "try_delete",
|
||||
|
@ -20,7 +20,7 @@ function ca_healer_may_attack:execution(ai, cfg, self)
|
|||
|
||||
-- Once combat (by other units) is done, set the healer move score so that it
|
||||
-- now happens before combat (of the healers which were so far excluded from combat)
|
||||
self.data.HS_healer_move_score = nil
|
||||
data.HS_healer_move_score = nil
|
||||
end
|
||||
|
||||
return ca_healer_may_attack
|
||||
|
|
|
@ -3,19 +3,19 @@ local LS = wesnoth.require "lua/location_set.lua"
|
|||
local AH = wesnoth.require "ai/lua/ai_helper.lua"
|
||||
local BC = wesnoth.require "ai/lua/battle_calcs.lua"
|
||||
|
||||
local ca_healer_move = {}
|
||||
local ca_healer_move, best_healer, best_hex = {}
|
||||
|
||||
function ca_healer_move:evaluation(ai, cfg, self)
|
||||
function ca_healer_move:evaluation(cfg, data)
|
||||
-- Should happen with higher priority than attacks, except at beginning of turn,
|
||||
-- when we want attacks (by other units) done first
|
||||
-- This is done so that it is possible for healers to attack, if they do not
|
||||
-- find an appropriate hex to back up other units
|
||||
local score = self.data.HS_healer_move_score or 105000
|
||||
local score = data.HS_healer_move_score or 105000
|
||||
|
||||
local all_healers = wesnoth.get_units {
|
||||
side = wesnoth.current.side,
|
||||
ability = "healing",
|
||||
{ "and", cfg.filter }
|
||||
{ "and", H.get_child(cfg, "filter") }
|
||||
}
|
||||
|
||||
local healers, healers_noMP = {}, {}
|
||||
|
@ -30,7 +30,7 @@ function ca_healer_move:evaluation(ai, cfg, self)
|
|||
|
||||
local all_healees = wesnoth.get_units {
|
||||
side = wesnoth.current.side,
|
||||
{ "and", cfg.filter_second }
|
||||
{ "and", H.get_child(cfg, "filter_second") }
|
||||
}
|
||||
|
||||
local healees, healees_MP = {}, {}
|
||||
|
@ -65,7 +65,7 @@ function ca_healer_move:evaluation(ai, cfg, self)
|
|||
|
||||
local avoid_map = LS.of_pairs(ai.get_avoid())
|
||||
|
||||
local max_rating, best_healer, best_hex = -9e99
|
||||
local max_rating = -9e99
|
||||
for _,healer in ipairs(healers) do
|
||||
local reach = wesnoth.find_reach(healer)
|
||||
|
||||
|
@ -119,16 +119,15 @@ function ca_healer_move:evaluation(ai, cfg, self)
|
|||
end
|
||||
|
||||
if best_healer then
|
||||
self.data.HS_unit, self.data.HS_hex = best_healer, best_hex
|
||||
return score
|
||||
end
|
||||
|
||||
return 0
|
||||
end
|
||||
|
||||
function ca_healer_move:execution(ai, cfg, self)
|
||||
AH.movefull_outofway_stopunit(ai, self.data.HS_unit, self.data.HS_hex)
|
||||
self.data.HS_unit, self.data.HS_hex = nil, nil
|
||||
function ca_healer_move:execution(cfg)
|
||||
AH.movefull_outofway_stopunit(ai, best_healer, best_hex)
|
||||
best_healer, best_hex = nil, nil
|
||||
end
|
||||
|
||||
return ca_healer_move
|
||||
|
|
|
@ -4,7 +4,7 @@ local AH = wesnoth.require "ai/lua/ai_helper.lua"
|
|||
local function get_sheep(cfg)
|
||||
local sheep = wesnoth.get_units {
|
||||
side = wesnoth.current.side,
|
||||
{ "and", cfg.filter_second }
|
||||
{ "and", H.get_child(cfg, "filter_second") }
|
||||
}
|
||||
return sheep
|
||||
end
|
||||
|
@ -12,7 +12,7 @@ end
|
|||
local function get_dogs(cfg)
|
||||
local dogs = AH.get_units_with_moves {
|
||||
side = wesnoth.current.side,
|
||||
{ "and", cfg.filter }
|
||||
{ "and", H.get_child(cfg, "filter") }
|
||||
}
|
||||
return dogs
|
||||
end
|
||||
|
@ -22,7 +22,7 @@ local function get_enemies(cfg, radius)
|
|||
{ "filter_side", { { "enemy_of", { side = wesnoth.current.side } } } },
|
||||
{ "filter_location",
|
||||
{ radius = radius,
|
||||
{ "filter", { side = wesnoth.current.side, { "and", cfg.filter_second } } } }
|
||||
{ "filter", { side = wesnoth.current.side, { "and", H.get_child(cfg, "filter_second") } } } }
|
||||
}
|
||||
}
|
||||
return enemies
|
||||
|
@ -30,7 +30,7 @@ end
|
|||
|
||||
local ca_herding_attack_close_enemy = {}
|
||||
|
||||
function ca_herding_attack_close_enemy:evaluation(ai, cfg)
|
||||
function ca_herding_attack_close_enemy:evaluation(cfg)
|
||||
-- Any enemy within attention_distance (default = 8) hexes of a sheep will get the dogs' attention
|
||||
-- with enemies within attack_distance (default: 4) being attacked
|
||||
if not get_sheep(cfg)[1] then return 0 end
|
||||
|
@ -41,7 +41,7 @@ function ca_herding_attack_close_enemy:evaluation(ai, cfg)
|
|||
return 0
|
||||
end
|
||||
|
||||
function ca_herding_attack_close_enemy:execution(ai, cfg)
|
||||
function ca_herding_attack_close_enemy:execution(cfg)
|
||||
local sheep = get_sheep(cfg)
|
||||
local dogs = get_dogs(cfg)
|
||||
|
||||
|
|
|
@ -5,24 +5,24 @@ local LS = wesnoth.require "lua/location_set.lua"
|
|||
local function get_dog(cfg)
|
||||
local dogs = AH.get_units_with_moves {
|
||||
side = wesnoth.current.side,
|
||||
{ "and", cfg.filter },
|
||||
{ "not", { { "filter_adjacent", { side = wesnoth.current.side, { "and", cfg.filter_second } } } } }
|
||||
{ "and", H.get_child(cfg, "filter") },
|
||||
{ "not", { { "filter_adjacent", { side = wesnoth.current.side, { "and", H.get_child(cfg, "filter_second") } } } } }
|
||||
}
|
||||
return dogs[1]
|
||||
end
|
||||
|
||||
local ca_herding_dog_move = {}
|
||||
|
||||
function ca_herding_dog_move:evaluation(ai, cfg)
|
||||
function ca_herding_dog_move:evaluation(cfg)
|
||||
-- As a final step, any dog not adjacent to a sheep moves within herding_perimeter
|
||||
if get_dog(cfg) then return cfg.ca_score end
|
||||
return 0
|
||||
end
|
||||
|
||||
function ca_herding_dog_move:execution(ai, cfg)
|
||||
function ca_herding_dog_move:execution(cfg)
|
||||
-- We simply move the first dog first, order does not matter
|
||||
local dog = get_dog(cfg)
|
||||
local herding_perimeter = LS.of_pairs(wesnoth.get_locations(cfg.filter_location))
|
||||
local herding_perimeter = LS.of_pairs(wesnoth.get_locations(H.get_child(cfg, "filter_location")))
|
||||
|
||||
-- Find average distance of herding_perimeter from center
|
||||
local av_dist = 0
|
||||
|
|
|
@ -1,9 +1,10 @@
|
|||
local H = wesnoth.require "lua/helper.lua"
|
||||
local AH = wesnoth.require "ai/lua/ai_helper.lua"
|
||||
|
||||
local function get_dog(cfg)
|
||||
local dogs = AH.get_units_with_moves {
|
||||
side = wesnoth.current.side,
|
||||
{ "and", cfg.filter },
|
||||
{ "and", H.get_child(cfg, "filter") },
|
||||
}
|
||||
return dogs[1]
|
||||
end
|
||||
|
@ -14,12 +15,12 @@ end
|
|||
|
||||
local ca_herding_dog_stopmove = {}
|
||||
|
||||
function ca_herding_dog_stopmove:evaluation(ai, cfg)
|
||||
function ca_herding_dog_stopmove:evaluation(cfg)
|
||||
if get_dog(cfg) then return cfg.ca_score end
|
||||
return 0
|
||||
end
|
||||
|
||||
function ca_herding_dog_stopmove:execution(ai, cfg)
|
||||
function ca_herding_dog_stopmove:execution(cfg)
|
||||
local dog = get_dog(cfg)
|
||||
|
||||
AH.checked_stopunit_moves(ai, dog)
|
||||
|
|
|
@ -4,17 +4,18 @@ local LS = wesnoth.require "lua/location_set.lua"
|
|||
return function(cfg)
|
||||
-- Find the area that the sheep can occupy
|
||||
-- First, find all contiguous hexes around center hex that are inside herding_perimeter
|
||||
local location_filter = H.get_child(cfg, "filter_location")
|
||||
local herding_area = LS.of_pairs(wesnoth.get_locations {
|
||||
x = cfg.herd_x,
|
||||
y = cfg.herd_y,
|
||||
radius = 999,
|
||||
{ "filter_radius", { { "not", cfg.filter_location } } }
|
||||
{ "filter_radius", { { "not", location_filter } } }
|
||||
})
|
||||
|
||||
-- Then, also exclude hexes next to herding_perimeter; some of the functions work better like that
|
||||
herding_area:iter( function(x, y, v)
|
||||
for xa, ya in H.adjacent_tiles(x, y) do
|
||||
if (wesnoth.match_location(xa, ya, cfg.filter_location) ) then
|
||||
if (wesnoth.match_location(xa, ya, location_filter) ) then
|
||||
herding_area:remove(x, y)
|
||||
end
|
||||
end
|
||||
|
|
|
@ -6,7 +6,7 @@ local herding_area = wesnoth.require "ai/micro_ais/cas/ca_herding_f_herding_area
|
|||
local function get_dogs(cfg)
|
||||
local dogs = AH.get_units_with_moves {
|
||||
side = wesnoth.current.side,
|
||||
{ "and", cfg.filter }
|
||||
{ "and", H.get_child(cfg, "filter") }
|
||||
}
|
||||
return dogs
|
||||
end
|
||||
|
@ -14,8 +14,8 @@ end
|
|||
local function get_sheep_to_herd(cfg)
|
||||
local all_sheep = wesnoth.get_units {
|
||||
side = wesnoth.current.side,
|
||||
{ "and", cfg.filter_second },
|
||||
{ "not", { { "filter_adjacent", { side = wesnoth.current.side, { "and", cfg.filter } } } } }
|
||||
{ "and", H.get_child(cfg, "filter_second") },
|
||||
{ "not", { { "filter_adjacent", { side = wesnoth.current.side, { "and", H.get_child(cfg, "filter") } } } } }
|
||||
}
|
||||
|
||||
local sheep_to_herd = {}
|
||||
|
@ -30,7 +30,7 @@ end
|
|||
|
||||
local ca_herding_herd_sheep = {}
|
||||
|
||||
function ca_herding_herd_sheep:evaluation(ai, cfg)
|
||||
function ca_herding_herd_sheep:evaluation(cfg)
|
||||
-- If dogs have moves left, and there is a sheep with moves left outside the
|
||||
-- herding area, chase it back
|
||||
if (not get_dogs(cfg)[1]) then return 0 end
|
||||
|
@ -38,7 +38,7 @@ function ca_herding_herd_sheep:evaluation(ai, cfg)
|
|||
return cfg.ca_score
|
||||
end
|
||||
|
||||
function ca_herding_herd_sheep:execution(ai, cfg)
|
||||
function ca_herding_herd_sheep:execution(cfg)
|
||||
local dogs = get_dogs(cfg)
|
||||
local sheep_to_herd = get_sheep_to_herd(cfg)
|
||||
|
||||
|
@ -62,7 +62,7 @@ function ca_herding_herd_sheep:execution(ai, cfg)
|
|||
-- And the closer dog goes first (so that it might be able to chase another sheep afterward)
|
||||
rating = rating - H.distance_between(x, y, dog.x, dog.y) / 100.
|
||||
-- Finally, prefer to stay on path, if possible
|
||||
if (wesnoth.match_location(x, y, cfg.filter_location) ) then rating = rating + 0.001 end
|
||||
if (wesnoth.match_location(x, y, H.get_child(cfg, "filter_location")) ) then rating = rating + 0.001 end
|
||||
|
||||
reach_map:insert(x, y, rating)
|
||||
|
||||
|
|
|
@ -6,29 +6,30 @@ local herding_area = wesnoth.require "ai/micro_ais/cas/ca_herding_f_herding_area
|
|||
local function get_next_sheep(cfg)
|
||||
local sheep = AH.get_units_with_moves {
|
||||
side = wesnoth.current.side,
|
||||
{ "and", cfg.filter_second }
|
||||
{ "and", H.get_child(cfg, "filter_second") }
|
||||
}
|
||||
return sheep[1]
|
||||
end
|
||||
|
||||
local ca_herding_sheep_move = {}
|
||||
|
||||
function ca_herding_sheep_move:evaluation(ai, cfg)
|
||||
function ca_herding_sheep_move:evaluation(cfg)
|
||||
-- If nothing else is to be done, the sheep do a random move
|
||||
if get_next_sheep(cfg) then return cfg.ca_score end
|
||||
return 0
|
||||
end
|
||||
|
||||
function ca_herding_sheep_move:execution(ai, cfg)
|
||||
function ca_herding_sheep_move:execution(cfg)
|
||||
-- We simply move the first sheep first, the order does not matter
|
||||
local sheep = get_next_sheep(cfg)
|
||||
|
||||
local reach_map = AH.get_reachable_unocc(sheep)
|
||||
local dogs_filter = H.get_child(cfg, "filter")
|
||||
-- Exclude those that are next to a dog
|
||||
reach_map:iter( function(x, y, v)
|
||||
for xa, ya in H.adjacent_tiles(x, y) do
|
||||
local dog = wesnoth.get_unit(xa, ya)
|
||||
if dog and (wesnoth.match_unit(dog, cfg.filter)) then
|
||||
if dog and (wesnoth.match_unit(dog, dogs_filter)) then
|
||||
reach_map:remove(x, y)
|
||||
end
|
||||
end
|
||||
|
@ -45,7 +46,7 @@ function ca_herding_sheep_move:execution(ai, cfg)
|
|||
local herding_area = herding_area(cfg)
|
||||
local dogs = AH.get_units_with_moves {
|
||||
side = wesnoth.current.side,
|
||||
{ "and", cfg.filter }
|
||||
{ "and", dogs_filter }
|
||||
}
|
||||
if herding_area:get(x, y) or (not dogs[1]) or ((x == sheep.x) and (y == sheep.y)) then
|
||||
AH.movefull_stopunit(ai, sheep, x, y)
|
||||
|
|
|
@ -4,26 +4,26 @@ local AH = wesnoth.require "ai/lua/ai_helper.lua"
|
|||
local function get_next_sheep(cfg)
|
||||
local sheep = AH.get_units_with_moves {
|
||||
side = wesnoth.current.side,
|
||||
{ "and", cfg.filter_second },
|
||||
{ "filter_adjacent", { side = wesnoth.current.side, { "and", cfg.filter } } }
|
||||
{ "and", H.get_child(cfg, "filter_second") },
|
||||
{ "filter_adjacent", { side = wesnoth.current.side, { "and", H.get_child(cfg, "filter") } } }
|
||||
}
|
||||
return sheep[1]
|
||||
end
|
||||
|
||||
local ca_herding_sheep_runs_dog = {}
|
||||
|
||||
function ca_herding_sheep_runs_dog:evaluation(ai, cfg)
|
||||
function ca_herding_sheep_runs_dog:evaluation(cfg)
|
||||
-- Any sheep with moves left next to a dog runs away
|
||||
if get_next_sheep(cfg) then return cfg.ca_score end
|
||||
return 0
|
||||
end
|
||||
|
||||
function ca_herding_sheep_runs_dog:execution(ai, cfg)
|
||||
function ca_herding_sheep_runs_dog:execution(cfg)
|
||||
-- Simply get the first sheep, order does not matter
|
||||
local sheep = get_next_sheep(cfg)
|
||||
|
||||
-- Get the first dog that the sheep is adjacent to
|
||||
local dog = wesnoth.get_units { side = wesnoth.current.side, { "and", cfg.filter },
|
||||
local dog = wesnoth.get_units { side = wesnoth.current.side, { "and", H.get_child(cfg, "filter") },
|
||||
{ "filter_adjacent", { x = sheep.x, y = sheep.y } }
|
||||
}[1]
|
||||
|
||||
|
|
|
@ -4,7 +4,7 @@ local AH = wesnoth.require "ai/lua/ai_helper.lua"
|
|||
local function get_next_sheep(cfg)
|
||||
local sheep = AH.get_units_with_moves {
|
||||
side = wesnoth.current.side,
|
||||
{ "and", cfg.filter_second },
|
||||
{ "and", H.get_child(cfg, "filter_second") },
|
||||
{ "filter_location",
|
||||
{
|
||||
{ "filter", { { "filter_side", { { "enemy_of", {side = wesnoth.current.side} } } } }
|
||||
|
@ -18,13 +18,13 @@ end
|
|||
|
||||
local ca_herding_sheep_runs_enemy = {}
|
||||
|
||||
function ca_herding_sheep_runs_enemy:evaluation(ai, cfg)
|
||||
function ca_herding_sheep_runs_enemy:evaluation(cfg)
|
||||
-- Sheep runs from any enemy within attention_distance hexes (after the dogs have moved in)
|
||||
if get_next_sheep(cfg) then return cfg.ca_score end
|
||||
return 0
|
||||
end
|
||||
|
||||
function ca_herding_sheep_runs_enemy:execution(ai, cfg)
|
||||
function ca_herding_sheep_runs_enemy:execution(cfg)
|
||||
-- Simply start with the first sheep, order does not matter
|
||||
local sheep = get_next_sheep(cfg)
|
||||
|
||||
|
|
|
@ -35,7 +35,7 @@ local function hunter_attack_weakest_adj_enemy(ai, hunter)
|
|||
end
|
||||
|
||||
local function get_hunter(cfg)
|
||||
local filter = cfg.filter or { id = cfg.id }
|
||||
local filter = H.get_child(cfg, "filter") or { id = cfg.id }
|
||||
local hunter = AH.get_units_with_moves {
|
||||
side = wesnoth.current.side,
|
||||
{ "and", filter }
|
||||
|
@ -45,12 +45,12 @@ end
|
|||
|
||||
local ca_hunter = {}
|
||||
|
||||
function ca_hunter:evaluation(ai, cfg)
|
||||
function ca_hunter:evaluation(cfg)
|
||||
if get_hunter(cfg) then return cfg.ca_score end
|
||||
return 0
|
||||
end
|
||||
|
||||
function ca_hunter:execution(ai, cfg)
|
||||
function ca_hunter:execution(cfg)
|
||||
-- Hunter does a random wander in area given by @cfg.hunting_ground until it finds
|
||||
-- and kills an enemy unit, then retreats to position given by @cfg.home_x/y
|
||||
-- for @cfg.rest_turns turns, or until fully healed
|
||||
|
@ -64,7 +64,7 @@ function ca_hunter:execution(ai, cfg)
|
|||
local rand = math.random(10)
|
||||
if (not hunter_vars.goal_x) or (rand == 1) then
|
||||
-- 'locs' includes border hexes, but that does not matter here
|
||||
locs = AH.get_passable_locations((cfg.filter_location or {}), hunter)
|
||||
locs = AH.get_passable_locations((H.get_child(cfg, "filter_location") or {}), hunter)
|
||||
local rand = math.random(#locs)
|
||||
|
||||
hunter_vars.goal_x, hunter_vars.goal_y = locs[rand][1], locs[rand][2]
|
||||
|
|
|
@ -6,19 +6,19 @@ local function get_lurker(cfg)
|
|||
-- We simply pick the first of the lurkers, they have no strategy
|
||||
local lurker = AH.get_units_with_moves {
|
||||
side = wesnoth.current.side,
|
||||
{ "and", cfg.filter }
|
||||
{ "and", H.get_child(cfg, "filter") }
|
||||
}[1]
|
||||
return lurker
|
||||
end
|
||||
|
||||
local ca_lurkers = {}
|
||||
|
||||
function ca_lurkers:evaluation(ai, cfg)
|
||||
function ca_lurkers:evaluation(cfg)
|
||||
if get_lurker(cfg) then return cfg.ca_score end
|
||||
return 0
|
||||
end
|
||||
|
||||
function ca_lurkers:execution(ai, cfg)
|
||||
function ca_lurkers:execution(cfg)
|
||||
local lurker = get_lurker(cfg)
|
||||
local targets = AH.get_live_units {
|
||||
{ "filter_side", { { "enemy_of", { side = wesnoth.current.side } } } }
|
||||
|
@ -28,10 +28,11 @@ function ca_lurkers:execution(ai, cfg)
|
|||
table.sort(targets, function(a, b) return (a.hitpoints < b.hitpoints) end)
|
||||
|
||||
local reach = LS.of_pairs(wesnoth.find_reach(lurker.x, lurker.y))
|
||||
local lurk_area = H.get_child(cfg, "filter_location")
|
||||
local reachable_attack_terrain =
|
||||
LS.of_pairs(wesnoth.get_locations {
|
||||
{ "and", { x = lurker.x, y = lurker.y, radius = lurker.moves } },
|
||||
{ "and", cfg.filter_location }
|
||||
{ "and", lurk_area }
|
||||
})
|
||||
reachable_attack_terrain:inter(reach)
|
||||
|
||||
|
@ -72,7 +73,7 @@ function ca_lurkers:execution(ai, cfg)
|
|||
local reachable_wander_terrain =
|
||||
LS.of_pairs( wesnoth.get_locations {
|
||||
{ "and", { x = lurker.x, y = lurker.y, radius = lurker.moves } },
|
||||
{ "and", (cfg.filter_location_wander or cfg.filter_location) }
|
||||
{ "and", H.get_child(cfg, "filter_location_wander") or lurk_area }
|
||||
})
|
||||
reachable_wander_terrain:inter(reach)
|
||||
|
||||
|
|
|
@ -2,6 +2,7 @@ local H = wesnoth.require "lua/helper.lua"
|
|||
local AH = wesnoth.require "ai/lua/ai_helper.lua"
|
||||
|
||||
local messenger_next_waypoint = wesnoth.require "ai/micro_ais/cas/ca_messenger_f_next_waypoint.lua"
|
||||
local best_attack
|
||||
|
||||
local function messenger_find_enemies_in_way(messenger, goal_x, goal_y)
|
||||
-- Returns the first unit on or next to the path of the messenger
|
||||
|
@ -49,17 +50,17 @@ local function messenger_find_clearing_attack(messenger, goal_x, goal_y, cfg)
|
|||
if (not enemy_in_way) then return end
|
||||
|
||||
|
||||
local filter = cfg.filter or { id = cfg.id }
|
||||
local filter = H.get_child(cfg, "filter") or { id = cfg.id }
|
||||
local units = AH.get_units_with_attacks {
|
||||
side = wesnoth.current.side,
|
||||
{ "not", filter },
|
||||
{ "and", cfg.filter_second }
|
||||
{ "and", H.get_child(cfg, "filter_second") }
|
||||
}
|
||||
if (not units[1]) then return end
|
||||
|
||||
local attacks = AH.get_attacks(units, { simulate_combat = true })
|
||||
|
||||
local max_rating, best_attack = -9e99
|
||||
local max_rating = -9e99
|
||||
for _,attack in ipairs(attacks) do
|
||||
if (attack.target.x == enemy_in_way.x) and (attack.target.y == enemy_in_way.y) then
|
||||
|
||||
|
@ -96,7 +97,7 @@ end
|
|||
|
||||
local ca_messenger_attack = {}
|
||||
|
||||
function ca_messenger_attack:evaluation(ai, cfg, self)
|
||||
function ca_messenger_attack:evaluation(cfg)
|
||||
-- Attack units in the path of the messengers
|
||||
|
||||
local messenger, x, y = messenger_next_waypoint(cfg)
|
||||
|
@ -105,23 +106,22 @@ function ca_messenger_attack:evaluation(ai, cfg, self)
|
|||
local attack = messenger_find_clearing_attack(messenger, x, y, cfg)
|
||||
|
||||
if attack then
|
||||
self.data.ME_best_attack = attack
|
||||
return cfg.ca_score
|
||||
end
|
||||
|
||||
return 0
|
||||
end
|
||||
|
||||
function ca_messenger_attack:execution(ai, cfg, self)
|
||||
local attacker = wesnoth.get_unit(self.data.ME_best_attack.src.x, self.data.ME_best_attack.src.y)
|
||||
local defender = wesnoth.get_unit(self.data.ME_best_attack.target.x, self.data.ME_best_attack.target.y)
|
||||
function ca_messenger_attack:execution(cfg)
|
||||
local attacker = wesnoth.get_unit(best_attack.src.x, best_attack.src.y)
|
||||
local defender = wesnoth.get_unit(best_attack.target.x, best_attack.target.y)
|
||||
|
||||
AH.movefull_stopunit(ai, attacker, self.data.ME_best_attack.dst.x, self.data.ME_best_attack.dst.y)
|
||||
AH.movefull_stopunit(ai, attacker, best_attack.dst.x, best_attack.dst.y)
|
||||
if (not attacker) or (not attacker.valid) then return end
|
||||
if (not defender) or (not defender.valid) then return end
|
||||
|
||||
AH.checked_attack(ai, attacker, defender)
|
||||
self.data.ME_best_attack = nil
|
||||
best_attack = nil
|
||||
end
|
||||
|
||||
return ca_messenger_attack
|
||||
|
|
|
@ -8,14 +8,14 @@ local messenger_next_waypoint = wesnoth.require "ai/micro_ais/cas/ca_messenger_f
|
|||
local function get_escorts(cfg)
|
||||
local escorts = AH.get_units_with_moves {
|
||||
side = wesnoth.current.side,
|
||||
{ "and", cfg.filter_second }
|
||||
{ "and", H.get_child(cfg, "filter_second") }
|
||||
}
|
||||
return escorts
|
||||
end
|
||||
|
||||
local ca_messenger_escort_move = {}
|
||||
|
||||
function ca_messenger_escort_move:evaluation(ai, cfg)
|
||||
function ca_messenger_escort_move:evaluation(cfg)
|
||||
-- Move escort units close to messengers, and in between messengers and enemies
|
||||
-- The messengers have moved at this time, so we don't need to exclude them,
|
||||
-- but we check that there are messengers left
|
||||
|
@ -28,7 +28,7 @@ function ca_messenger_escort_move:evaluation(ai, cfg)
|
|||
return cfg.ca_score
|
||||
end
|
||||
|
||||
function ca_messenger_escort_move:execution(ai, cfg)
|
||||
function ca_messenger_escort_move:execution(cfg)
|
||||
local escorts = get_escorts(cfg)
|
||||
local _, _, _, messengers = messenger_next_waypoint(cfg)
|
||||
|
||||
|
|
|
@ -10,7 +10,7 @@ return function(cfg)
|
|||
-- Returns nil for first 3 arguments if no messenger has moves left
|
||||
-- Returns nil for all arguments if there are no messengers on the map
|
||||
|
||||
local filter = cfg.filter or { id = cfg.id }
|
||||
local filter = H.get_child(cfg, "filter") or { id = cfg.id }
|
||||
local messengers = wesnoth.get_units { side = wesnoth.current.side, { "and", filter } }
|
||||
if (not messengers[1]) then return end
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@ local messenger_next_waypoint = wesnoth.require "ai/micro_ais/cas/ca_messenger_f
|
|||
|
||||
local ca_messenger_move = {}
|
||||
|
||||
function ca_messenger_move:evaluation(ai, cfg)
|
||||
function ca_messenger_move:evaluation(cfg)
|
||||
-- Move the messenger toward goal, potentially attack adjacent unit
|
||||
|
||||
local messenger = messenger_next_waypoint(cfg)
|
||||
|
@ -14,7 +14,7 @@ function ca_messenger_move:evaluation(ai, cfg)
|
|||
return 0
|
||||
end
|
||||
|
||||
function ca_messenger_move:execution(ai, cfg)
|
||||
function ca_messenger_move:execution(cfg)
|
||||
local messenger, x, y = messenger_next_waypoint(cfg)
|
||||
|
||||
if (messenger.x ~= x) or (messenger.y ~= y) then
|
||||
|
|
|
@ -1,8 +1,9 @@
|
|||
local H = wesnoth.require "lua/helper.lua"
|
||||
local AH = wesnoth.require "ai/lua/ai_helper.lua"
|
||||
local MAIUV = wesnoth.require "ai/micro_ais/micro_ai_unit_variables.lua"
|
||||
|
||||
local function get_patrol(cfg)
|
||||
local filter = cfg.filter or { id = cfg.id }
|
||||
local filter = H.get_child(cfg, "filter") or { id = cfg.id }
|
||||
local patrol = AH.get_units_with_moves {
|
||||
side = wesnoth.current.side,
|
||||
{ "and", filter }
|
||||
|
@ -12,12 +13,12 @@ end
|
|||
|
||||
local ca_patrol = {}
|
||||
|
||||
function ca_patrol:evaluation(ai, cfg)
|
||||
function ca_patrol:evaluation(cfg)
|
||||
if get_patrol(cfg) then return cfg.ca_score end
|
||||
return 0
|
||||
end
|
||||
|
||||
function ca_patrol:execution(ai, cfg)
|
||||
function ca_patrol:execution(cfg)
|
||||
local patrol = get_patrol(cfg)
|
||||
local patrol_vars = MAIUV.get_mai_unit_variables(patrol, cfg.ai_id)
|
||||
|
||||
|
|
|
@ -2,16 +2,16 @@ local H = wesnoth.require "lua/helper.lua"
|
|||
local AH = wesnoth.require "ai/lua/ai_helper.lua"
|
||||
local BC = wesnoth.require "ai/lua/battle_calcs.lua"
|
||||
|
||||
local ca_protect_unit_attack = {}
|
||||
local ca_protect_unit_attack, best_attack = {}
|
||||
|
||||
function ca_protect_unit_attack:evaluation(ai, cfg, self)
|
||||
function ca_protect_unit_attack:evaluation(cfg)
|
||||
-- Find possible attacks for the units
|
||||
-- This is set up very conservatively: if a unit can die in the attack
|
||||
-- or the counter attack on the enemy turn, it does not attack, even if that's really unlikely
|
||||
|
||||
local units = {}
|
||||
for _,id in ipairs(cfg.id) do
|
||||
table.insert(units, AH.get_units_with_attacks { id = id }[1])
|
||||
for u in H.child_range(cfg, "unit") do
|
||||
table.insert(units, AH.get_units_with_attacks { id = u.id }[1])
|
||||
end
|
||||
if (not units[1]) then return 0 end
|
||||
|
||||
|
@ -32,7 +32,7 @@ function ca_protect_unit_attack:evaluation(ai, cfg, self)
|
|||
-- Set up a counter attack damage table, as many pairs of attacks will be the same
|
||||
local counter_damage_table = {}
|
||||
|
||||
local max_rating, best_attack = -9e99
|
||||
local max_rating = -9e99
|
||||
for _,attack in pairs(attacks) do
|
||||
-- Only consider attack if there is no chance to die or to be poisoned or slowed
|
||||
if (attack.att_stats.hp_chance[0] == 0)
|
||||
|
@ -96,22 +96,21 @@ function ca_protect_unit_attack:evaluation(ai, cfg, self)
|
|||
end
|
||||
|
||||
if best_attack then
|
||||
self.data.PU_best_attack = best_attack
|
||||
return 95000
|
||||
end
|
||||
return 0
|
||||
end
|
||||
|
||||
function ca_protect_unit_attack:execution(ai, cfg, self)
|
||||
local attacker = wesnoth.get_unit(self.data.PU_best_attack.src.x, self.data.PU_best_attack.src.y)
|
||||
local defender = wesnoth.get_unit(self.data.PU_best_attack.target.x, self.data.PU_best_attack.target.y)
|
||||
function ca_protect_unit_attack:execution(cfg)
|
||||
local attacker = wesnoth.get_unit(best_attack.src.x, best_attack.src.y)
|
||||
local defender = wesnoth.get_unit(best_attack.target.x, best_attack.target.y)
|
||||
|
||||
AH.movefull_stopunit(ai, attacker, self.data.PU_best_attack.dst.x, self.data.PU_best_attack.dst.y)
|
||||
AH.movefull_stopunit(ai, attacker, best_attack.dst.x, best_attack.dst.y)
|
||||
if (not attacker) or (not attacker.valid) then return end
|
||||
if (not defender) or (not defender.valid) then return end
|
||||
|
||||
AH.checked_attack(ai, attacker, defender)
|
||||
self.data.PU_best_attack = nil
|
||||
best_attack = nil
|
||||
end
|
||||
|
||||
return ca_protect_unit_attack
|
||||
|
|
|
@ -1,16 +1,17 @@
|
|||
local H = wesnoth.require "lua/helper.lua"
|
||||
local AH = wesnoth.require "ai/lua/ai_helper.lua"
|
||||
|
||||
local ca_protect_unit_finish = {}
|
||||
local ca_protect_unit_finish, PU_unit, PU_goal = {}
|
||||
|
||||
function ca_protect_unit_finish:evaluation(ai, cfg, self)
|
||||
function ca_protect_unit_finish:evaluation(cfg)
|
||||
-- If a unit can make it to the goal, this is the first thing that happens
|
||||
for i,id in ipairs(cfg.id) do
|
||||
local unit = AH.get_units_with_moves { id = id }[1]
|
||||
for u in H.child_range(cfg, "unit") do
|
||||
local unit = AH.get_units_with_moves { id = u.id }[1]
|
||||
if unit then
|
||||
local path, cost = wesnoth.find_path(unit, cfg.goal_x[i], cfg.goal_y[i])
|
||||
if (cost <= unit.moves) and ((unit.x ~= cfg.goal_x[i]) or (unit.y ~= cfg.goal_y[i])) then
|
||||
self.data.PU_unit = unit
|
||||
self.data.PU_goal = { cfg.goal_x[i], cfg.goal_y[i] }
|
||||
local path, cost = wesnoth.find_path(unit, u.goal_x, u.goal_y)
|
||||
if (cost <= unit.moves) and ((unit.x ~= u.goal_x) or (unit.y ~= u.goal_y)) then
|
||||
PU_unit = unit
|
||||
PU_goal = { u.goal_x, u.goal_y }
|
||||
return 300000
|
||||
end
|
||||
end
|
||||
|
@ -18,9 +19,9 @@ function ca_protect_unit_finish:evaluation(ai, cfg, self)
|
|||
return 0
|
||||
end
|
||||
|
||||
function ca_protect_unit_finish:execution(ai, cfg, self)
|
||||
AH.movefull_stopunit(ai, self.data.PU_unit, self.data.PU_goal)
|
||||
self.data.PU_unit, self.data.PU_goal = nil, nil
|
||||
function ca_protect_unit_finish:execution(cfg)
|
||||
AH.movefull_stopunit(ai, PU_unit, PU_goal)
|
||||
PU_unit, PU_goal = nil, nil
|
||||
end
|
||||
|
||||
return ca_protect_unit_finish
|
||||
|
|
|
@ -5,20 +5,20 @@ local BC = wesnoth.require "ai/lua/battle_calcs.lua"
|
|||
|
||||
local function get_protected_units(cfg)
|
||||
local units = {}
|
||||
for _,id in ipairs(cfg.id) do
|
||||
table.insert(units, AH.get_units_with_moves { id = id }[1])
|
||||
for u in H.child_range(cfg, "unit") do
|
||||
table.insert(units, AH.get_units_with_moves { id = u.id }[1])
|
||||
end
|
||||
return units
|
||||
end
|
||||
|
||||
local ca_protect_unit_move = {}
|
||||
|
||||
function ca_protect_unit_move:evaluation(ai, cfg, self)
|
||||
function ca_protect_unit_move:evaluation(cfg)
|
||||
if get_protected_units(cfg)[1] then return 94999 end
|
||||
return 0
|
||||
end
|
||||
|
||||
function ca_protect_unit_move:execution(ai, cfg, self)
|
||||
function ca_protect_unit_move:execution(cfg, data)
|
||||
-- Find and execute best (safest) move toward goal
|
||||
local protected_units = get_protected_units(cfg)
|
||||
|
||||
|
@ -40,8 +40,8 @@ function ca_protect_unit_move:execution(ai, cfg, self)
|
|||
-- We move the weakest (fewest HP unit) first
|
||||
local unit = AH.choose(protected_units, function(u) return - u.hitpoints end)
|
||||
local goal = {}
|
||||
for i,id in ipairs(cfg.id) do
|
||||
if (unit.id == id) then goal = { cfg.goal_x[i], cfg.goal_y[i] } end
|
||||
for u in H.child_range(cfg, "unit") do
|
||||
if (unit.id == u.id) then goal = { u.goal_x, u.goal_y } end
|
||||
end
|
||||
|
||||
local reach_map = AH.get_reachable_unocc(unit)
|
||||
|
@ -58,10 +58,10 @@ function ca_protect_unit_move:execution(ai, cfg, self)
|
|||
end)
|
||||
|
||||
-- Configuration parameters (no option to change these enabled at the moment)
|
||||
local enemy_weight = self.data.PU_enemy_weight or 100.
|
||||
local my_unit_weight = self.data.PU_my_unit_weight or 1.
|
||||
local distance_weight = self.data.PU_distance_weight or 3.
|
||||
local terrain_weight = self.data.PU_terrain_weight or 0.1
|
||||
local enemy_weight = data.PU_enemy_weight or 100.
|
||||
local my_unit_weight = data.PU_my_unit_weight or 1.
|
||||
local distance_weight = data.PU_distance_weight or 3.
|
||||
local terrain_weight = data.PU_terrain_weight or 0.1
|
||||
|
||||
-- If there are no enemies left, only distance to goal matters
|
||||
-- This is to avoid rare situations where moving toward goal rating is canceled by rating for moving away from own units
|
||||
|
|
|
@ -6,7 +6,7 @@ local recruit_type
|
|||
|
||||
local ca_recruit_random = {}
|
||||
|
||||
function ca_recruit_random:evaluation(ai, cfg)
|
||||
function ca_recruit_random:evaluation(cfg)
|
||||
-- Random recruiting from all the units the side has
|
||||
|
||||
-- Check if leader is on keep
|
||||
|
@ -59,15 +59,14 @@ function ca_recruit_random:evaluation(ai, cfg)
|
|||
local probabilities, probability_sum = {}, 0
|
||||
|
||||
-- Go through all the types listed in [probability] tags (which can be comma-separated lists)
|
||||
-- Types and probabilities are put into cfg.type and cfg.prob arrays by micro_ai_wml_tag.lua
|
||||
for ind,types in ipairs(cfg.type) do
|
||||
types = AH.split(types, ",")
|
||||
for prob in H.child_range(cfg, "probability") do
|
||||
types = AH.split(prob.type, ",")
|
||||
for _,typ in ipairs(types) do -- 'type' is a reserved keyword in Lua
|
||||
-- If this type is in the recruit list, add it
|
||||
for _,recruit in ipairs(wesnoth.sides[wesnoth.current.side].recruit) do
|
||||
if (recruit == typ) then
|
||||
probabilities[typ] = { value = cfg.prob[ind] }
|
||||
probability_sum = probability_sum + cfg.prob[ind]
|
||||
probabilities[typ] = { value = prob.probability }
|
||||
probability_sum = probability_sum + prob.probability
|
||||
break
|
||||
end
|
||||
end
|
||||
|
@ -119,7 +118,7 @@ function ca_recruit_random:evaluation(ai, cfg)
|
|||
return cfg.ca_score
|
||||
end
|
||||
|
||||
function ca_recruit_random:execution(ai, cfg)
|
||||
function ca_recruit_random:execution(cfg)
|
||||
-- Let this function blacklist itself if the chosen recruit is too expensive
|
||||
if wesnoth.unit_types[recruit_type].cost <= wesnoth.sides[wesnoth.current.side].gold then
|
||||
AH.checked_recruit(ai, recruit_type)
|
||||
|
|
|
@ -1,22 +1,20 @@
|
|||
local internal_recruit_cas = {}
|
||||
local internal_params = {}
|
||||
local ai
|
||||
|
||||
-- The following external engine creates the CA functions recruit_rushers_eval and recruit_rushers_exec
|
||||
-- It also exposes find_best_recruit and find_best_recruit_hex for use by other recruit engines
|
||||
|
||||
-- 'ai' is nil here (not defined), so we pass it directly in the execution function below
|
||||
wesnoth.require("ai/lua/generic_recruit_engine.lua").init(ai, internal_recruit_cas, internal_params)
|
||||
|
||||
local ca_recruit_rushers = {}
|
||||
|
||||
function ca_recruit_rushers:evaluation(ai, cfg)
|
||||
function ca_recruit_rushers:evaluation(cfg)
|
||||
internal_params.randomness = cfg.randomness
|
||||
return internal_recruit_cas:recruit_rushers_eval()
|
||||
end
|
||||
|
||||
function ca_recruit_rushers:execution(ai)
|
||||
return internal_recruit_cas:recruit_rushers_exec(ai)
|
||||
function ca_recruit_rushers:execution()
|
||||
return internal_recruit_cas:recruit_rushers_exec()
|
||||
end
|
||||
|
||||
return ca_recruit_rushers
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
local H = wesnoth.require "lua/helper.lua"
|
||||
local AH = wesnoth.require "ai/lua/ai_helper.lua"
|
||||
|
||||
local function get_guardian(cfg)
|
||||
local filter = cfg.filter or { id = cfg.id }
|
||||
local filter = H.get_child(cfg, "filter") or { id = cfg.id }
|
||||
local guardian = AH.get_units_with_moves {
|
||||
side = wesnoth.current.side,
|
||||
{ "and", filter }
|
||||
|
@ -12,7 +13,7 @@ end
|
|||
|
||||
local ca_return_guardian = {}
|
||||
|
||||
function ca_return_guardian:evaluation(ai, cfg)
|
||||
function ca_return_guardian:evaluation(cfg)
|
||||
local guardian = get_guardian(cfg)
|
||||
if guardian then
|
||||
if (guardian.x == cfg.return_x) and (guardian.y == cfg.return_y) then
|
||||
|
@ -25,7 +26,7 @@ function ca_return_guardian:evaluation(ai, cfg)
|
|||
return 0
|
||||
end
|
||||
|
||||
function ca_return_guardian:execution(ai, cfg)
|
||||
function ca_return_guardian:execution(cfg)
|
||||
local guardian = get_guardian(cfg)
|
||||
|
||||
-- In case the return hex is occupied:
|
||||
|
|
|
@ -1,23 +1,25 @@
|
|||
local H = wesnoth.require "lua/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 ca_simple_attack = {}
|
||||
local ca_simple_attack, best_attack = {}
|
||||
|
||||
function ca_simple_attack:evaluation(ai, cfg, self)
|
||||
function ca_simple_attack:evaluation(cfg)
|
||||
local units = AH.get_units_with_attacks {
|
||||
side = wesnoth.current.side,
|
||||
{ "and", cfg.filter }
|
||||
{ "and", H.get_child(cfg, "filter") }
|
||||
}
|
||||
if (not units[1]) then return 0 end
|
||||
|
||||
-- If cfg.filter_second is set, set up a map (location set)
|
||||
-- of enemies that it is okay to attack
|
||||
local enemy_filter = H.get_child(cfg, "filter_second")
|
||||
local enemy_map
|
||||
if cfg.filter_second then
|
||||
if enemy_filter then
|
||||
local enemies = wesnoth.get_units {
|
||||
{ "filter_side", { { "enemy_of", { side = wesnoth.current.side } } } },
|
||||
{ "and", cfg.filter_second }
|
||||
{ "and", enemy_filter }
|
||||
}
|
||||
if (not enemies[1]) then return 0 end
|
||||
|
||||
|
@ -29,10 +31,10 @@ function ca_simple_attack:evaluation(ai, cfg, self)
|
|||
local attacks = AH.get_attacks(units, { include_occupied = true })
|
||||
if (not attacks[1]) then return 0 end
|
||||
|
||||
local max_rating, best_attack = -9e99
|
||||
local max_rating = -9e99
|
||||
for _, att in ipairs(attacks) do
|
||||
local valid_target = true
|
||||
if cfg.filter_second and (not enemy_map:get(att.target.x, att.target.y)) then
|
||||
if enemy_filter and (not enemy_map:get(att.target.x, att.target.y)) then
|
||||
valid_target = false
|
||||
end
|
||||
|
||||
|
@ -50,23 +52,22 @@ function ca_simple_attack:evaluation(ai, cfg, self)
|
|||
end
|
||||
|
||||
if best_attack then
|
||||
self.data.SA_attack = best_attack
|
||||
return cfg.ca_score
|
||||
end
|
||||
|
||||
return 0
|
||||
end
|
||||
|
||||
function ca_simple_attack:execution(ai, cfg, self)
|
||||
local attacker = wesnoth.get_unit(self.data.SA_attack.src.x, self.data.SA_attack.src.y)
|
||||
local defender = wesnoth.get_unit(self.data.SA_attack.target.x, self.data.SA_attack.target.y)
|
||||
function ca_simple_attack:execution(cfg)
|
||||
local attacker = wesnoth.get_unit(best_attack.src.x, best_attack.src.y)
|
||||
local defender = wesnoth.get_unit(best_attack.target.x, best_attack.target.y)
|
||||
|
||||
AH.movefull_outofway_stopunit(ai, attacker, self.data.SA_attack.dst.x, self.data.SA_attack.dst.y)
|
||||
AH.movefull_outofway_stopunit(ai, attacker, best_attack.dst.x, best_attack.dst.y)
|
||||
if (not attacker) or (not attacker.valid) then return end
|
||||
if (not defender) or (not defender.valid) then return end
|
||||
|
||||
AH.checked_attack(ai, attacker, defender, (cfg.weapon or -1))
|
||||
self.data.SA_attack = nil
|
||||
best_attack = nil
|
||||
end
|
||||
|
||||
return ca_simple_attack
|
||||
|
|
|
@ -2,7 +2,7 @@ local H = wesnoth.require "lua/helper.lua"
|
|||
local AH = wesnoth.require "ai/lua/ai_helper.lua"
|
||||
|
||||
local function get_guardian(cfg)
|
||||
local filter = cfg.filter or { id = cfg.id }
|
||||
local filter = H.get_child(cfg, "filter") or { id = cfg.id }
|
||||
local guardian = AH.get_units_with_moves {
|
||||
side = wesnoth.current.side,
|
||||
{ "and", filter }
|
||||
|
@ -12,12 +12,12 @@ end
|
|||
|
||||
local ca_stationed_guardian = {}
|
||||
|
||||
function ca_stationed_guardian:evaluation(ai, cfg)
|
||||
function ca_stationed_guardian:evaluation(cfg)
|
||||
if get_guardian(cfg) then return cfg.ca_score end
|
||||
return 0
|
||||
end
|
||||
|
||||
function ca_stationed_guardian:execution(ai, cfg)
|
||||
function ca_stationed_guardian:execution(cfg)
|
||||
-- (s_x, s_y): coordinates where guardian is stationed; tries to move here if there is nobody to attack
|
||||
-- (g_x, g_y): location that the guardian guards
|
||||
|
||||
|
|
|
@ -3,7 +3,7 @@ local AH = wesnoth.require "ai/lua/ai_helper.lua"
|
|||
|
||||
local ca_swarm_move = {}
|
||||
|
||||
function ca_swarm_move:evaluation(ai, cfg)
|
||||
function ca_swarm_move:evaluation(cfg)
|
||||
local units = wesnoth.get_units { side = wesnoth.current.side }
|
||||
for _,unit in ipairs(units) do
|
||||
if (unit.moves > 0) then return cfg.ca_score end
|
||||
|
@ -12,7 +12,7 @@ function ca_swarm_move:evaluation(ai, cfg)
|
|||
return 0
|
||||
end
|
||||
|
||||
function ca_swarm_move:execution(ai, cfg)
|
||||
function ca_swarm_move:execution(cfg)
|
||||
local enemy_distance = cfg.enemy_distance or 5
|
||||
local vision_distance = cfg.vision_distance or 12
|
||||
|
||||
|
|
|
@ -18,13 +18,13 @@ end
|
|||
|
||||
local ca_swarm_scatter = {}
|
||||
|
||||
function ca_swarm_scatter:evaluation(ai, cfg)
|
||||
function ca_swarm_scatter:evaluation(cfg)
|
||||
if (not get_enemies(cfg)[1]) then return 0 end
|
||||
if (not get_swarm_units(cfg)[1]) then return 0 end
|
||||
return cfg.ca_score
|
||||
end
|
||||
|
||||
function ca_swarm_scatter:execution(ai, cfg)
|
||||
function ca_swarm_scatter:execution(cfg)
|
||||
local enemies = get_enemies(cfg)
|
||||
local units = get_swarm_units(cfg)
|
||||
local vision_distance = cfg.vision_distance or 12
|
||||
|
|
|
@ -5,7 +5,7 @@ local BC = wesnoth.require "ai/lua/battle_calcs.lua"
|
|||
local function get_wolves(cfg)
|
||||
local wolves = AH.get_units_with_moves {
|
||||
side = wesnoth.current.side,
|
||||
{ "and", cfg.filter }
|
||||
{ "and", H.get_child(cfg, "filter") }
|
||||
}
|
||||
return wolves
|
||||
end
|
||||
|
@ -13,20 +13,20 @@ end
|
|||
local function get_prey(cfg)
|
||||
local prey = wesnoth.get_units {
|
||||
{ "filter_side", { { "enemy_of", { side = wesnoth.current.side } } } },
|
||||
{ "and", cfg.filter_second }
|
||||
{ "and", H.get_child(cfg, "filter_second") }
|
||||
}
|
||||
return prey
|
||||
end
|
||||
|
||||
local ca_wolves_move = {}
|
||||
|
||||
function ca_wolves_move:evaluation(ai, cfg)
|
||||
function ca_wolves_move:evaluation(cfg)
|
||||
if (not get_wolves(cfg)[1]) then return 0 end
|
||||
if (not get_prey(cfg)[1]) then return 0 end
|
||||
return cfg.ca_score
|
||||
end
|
||||
|
||||
function ca_wolves_move:execution(ai, cfg)
|
||||
function ca_wolves_move:execution(cfg)
|
||||
local wolves = get_wolves(cfg)
|
||||
local prey = get_prey(cfg)
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@ local WMPF = wesnoth.require "ai/micro_ais/cas/ca_wolves_multipacks_functions.lu
|
|||
|
||||
local ca_wolves_multipacks_attack = {}
|
||||
|
||||
function ca_wolves_multipacks_attack:evaluation(ai, cfg)
|
||||
function ca_wolves_multipacks_attack:evaluation(cfg)
|
||||
-- If wolves have attacks left, call this CA
|
||||
-- It will be disabled by being black-listed, so as to avoid
|
||||
-- having to do the full attack evaluation for every single move evaluation
|
||||
|
@ -19,7 +19,7 @@ function ca_wolves_multipacks_attack:evaluation(ai, cfg)
|
|||
return 0
|
||||
end
|
||||
|
||||
function ca_wolves_multipacks_attack:execution(ai, cfg)
|
||||
function ca_wolves_multipacks_attack:execution(cfg)
|
||||
local packs = WMPF.assign_packs(cfg)
|
||||
|
||||
-- Attacks are dealt with on a pack by pack basis
|
||||
|
|
|
@ -6,7 +6,7 @@ local WMPF = wesnoth.require "ai/micro_ais/cas/ca_wolves_multipacks_functions.lu
|
|||
|
||||
local ca_wolves_multipacks_wander = {}
|
||||
|
||||
function ca_wolves_multipacks_wander:evaluation(ai, cfg)
|
||||
function ca_wolves_multipacks_wander:evaluation(cfg)
|
||||
-- When there's nothing to attack, the wolves wander and regroup into their packs
|
||||
|
||||
local wolves = AH.get_units_with_moves {
|
||||
|
@ -18,7 +18,7 @@ function ca_wolves_multipacks_wander:evaluation(ai, cfg)
|
|||
return 0
|
||||
end
|
||||
|
||||
function ca_wolves_multipacks_wander:execution(ai, cfg)
|
||||
function ca_wolves_multipacks_wander:execution(cfg)
|
||||
local packs = WMPF.assign_packs(cfg)
|
||||
|
||||
for pack_number,pack in pairs(packs) do
|
||||
|
|
|
@ -6,20 +6,20 @@ local LS = wesnoth.require "lua/location_set.lua"
|
|||
local function get_wolves(cfg)
|
||||
local wolves = AH.get_units_with_moves {
|
||||
side = wesnoth.current.side,
|
||||
{ "and", cfg.filter }
|
||||
{ "and", H.get_child(cfg, "filter") }
|
||||
}
|
||||
return wolves
|
||||
end
|
||||
|
||||
local ca_wolves_wander = {}
|
||||
|
||||
function ca_wolves_wander:evaluation(ai, cfg)
|
||||
function ca_wolves_wander:evaluation(cfg)
|
||||
-- When there's no prey left, the wolves wander and regroup
|
||||
if get_wolves(cfg)[1] then return cfg.ca_score end
|
||||
return 0
|
||||
end
|
||||
|
||||
function ca_wolves_wander:execution(ai, cfg)
|
||||
function ca_wolves_wander:execution(cfg)
|
||||
local wolves = get_wolves(cfg)
|
||||
|
||||
-- Number of wolves that can reach each hex
|
||||
|
|
|
@ -3,7 +3,7 @@ local AH = wesnoth.require "ai/lua/ai_helper.lua"
|
|||
local LS = wesnoth.require "lua/location_set.lua"
|
||||
|
||||
local function get_guardian(cfg)
|
||||
local filter = cfg.filter or { id = cfg.id }
|
||||
local filter = H.get_child(cfg, "filter") or { id = cfg.id }
|
||||
local guardian = AH.get_units_with_moves {
|
||||
side = wesnoth.current.side,
|
||||
{ "and", filter }
|
||||
|
@ -13,16 +13,17 @@ end
|
|||
|
||||
local ca_zone_guardian = {}
|
||||
|
||||
function ca_zone_guardian:evaluation(ai, cfg)
|
||||
function ca_zone_guardian:evaluation(cfg)
|
||||
if get_guardian(cfg) then return cfg.ca_score end
|
||||
return 0
|
||||
end
|
||||
|
||||
function ca_zone_guardian:execution(ai, cfg)
|
||||
function ca_zone_guardian:execution(cfg)
|
||||
local guardian = get_guardian(cfg)
|
||||
local reach = wesnoth.find_reach(guardian)
|
||||
|
||||
local zone_enemy = cfg.filter_location_enemy or cfg.filter_location
|
||||
local zone = H.get_child(cfg, "filter_location")
|
||||
local zone_enemy = H.get_child(cfg, "filter_location_enemy") or zone
|
||||
local enemies = wesnoth.get_units {
|
||||
{ "filter_side", { { "enemy_of", { side = wesnoth.current.side } } } },
|
||||
{ "filter_location", zone_enemy }
|
||||
|
@ -95,7 +96,7 @@ function ca_zone_guardian:execution(ai, cfg)
|
|||
local locs_map = LS.of_pairs(wesnoth.get_locations {
|
||||
x = '1-' .. width,
|
||||
y = '1-' .. height,
|
||||
{ "and", cfg.filter_location }
|
||||
{ "and", zone }
|
||||
})
|
||||
|
||||
-- Check out which of those hexes the guardian can reach
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
return {
|
||||
init = function(ai)
|
||||
init = function()
|
||||
local priority_target = {}
|
||||
|
||||
local H = wesnoth.require "lua/helper.lua"
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
return {
|
||||
init = function(ai)
|
||||
init = function()
|
||||
local AH = wesnoth.require "ai/lua/ai_helper.lua"
|
||||
|
||||
local urudin = {}
|
||||
|
|
|
@ -3,7 +3,6 @@ local W = H.set_wml_action_metatable {}
|
|||
local MAIH = wesnoth.require("ai/micro_ais/micro_ai_helper.lua")
|
||||
|
||||
function wesnoth.micro_ais.protect_unit(cfg)
|
||||
local required_keys = { "id", "goal_x", "goal_y" }
|
||||
-- Scores for this AI need to be hard-coded, it does not work otherwise
|
||||
local CA_parms = {
|
||||
ai_id = 'mai_protect_unit',
|
||||
|
@ -12,27 +11,21 @@ function wesnoth.micro_ais.protect_unit(cfg)
|
|||
{ ca_id = 'move', location = 'ca_protect_unit_move.lua', score = 94999 }
|
||||
}
|
||||
|
||||
-- [unit] tags need to be dealt with separately
|
||||
cfg.id, cfg.goal_x, cfg.goal_y = {}, {}, {}
|
||||
if (cfg.action ~= 'delete') then
|
||||
for unit in H.child_range(cfg, "unit") do
|
||||
if (not unit.id) then
|
||||
H.wml_error("Protect Unit Micro AI [unit] tag is missing required id= key")
|
||||
end
|
||||
if (not unit.goal_x) then
|
||||
H.wml_error("Protect Unit Micro AI [unit] tag is missing required goal_x= key")
|
||||
end
|
||||
if (not unit.goal_y) then
|
||||
H.wml_error("Protect Unit Micro AI [unit] tag is missing required goal_y= key")
|
||||
end
|
||||
table.insert(cfg.id, unit.id)
|
||||
table.insert(cfg.goal_x, unit.goal_x)
|
||||
table.insert(cfg.goal_y, unit.goal_y)
|
||||
local unit_ids = {}
|
||||
for u in H.child_range(cfg, "unit") do
|
||||
if not u.id then
|
||||
H.wml_error("Protect Unit Micro AI missing id key in [unit] tag")
|
||||
end
|
||||
|
||||
if (not cfg.id[1]) then
|
||||
H.wml_error("Protect Unit Micro AI is missing required [unit] tag")
|
||||
if not u.goal_x then
|
||||
H.wml_error("Protect Unit Micro AI missing goal_x key in [unit] tag")
|
||||
end
|
||||
if not u.goal_y then
|
||||
H.wml_error("Protect Unit Micro AI missing goal_y key in [unit] tag")
|
||||
end
|
||||
table.insert(unit_ids, u.id)
|
||||
end
|
||||
if #unit_ids == 0 then
|
||||
H.wml_error("Protect Unit Micro AI is missing required [unit] tag")
|
||||
end
|
||||
|
||||
-- Optional key disable_move_leader_to_keep: needs to be dealt with
|
||||
|
@ -46,10 +39,6 @@ function wesnoth.micro_ais.protect_unit(cfg)
|
|||
end
|
||||
|
||||
-- attacks aspects also needs to be set separately
|
||||
local unit_ids_str = 'dummy'
|
||||
for _,id in ipairs(cfg.id) do
|
||||
unit_ids_str = unit_ids_str .. ',' .. id
|
||||
end
|
||||
local aspect_parms = {
|
||||
{
|
||||
aspect = "attacks",
|
||||
|
@ -59,7 +48,7 @@ function wesnoth.micro_ais.protect_unit(cfg)
|
|||
invalidate_on_gamestate_change = "yes",
|
||||
{ "filter_own", {
|
||||
{ "not", {
|
||||
id = unit_ids_str
|
||||
id = unit_ids
|
||||
} }
|
||||
} }
|
||||
}
|
||||
|
@ -85,5 +74,5 @@ function wesnoth.micro_ais.protect_unit(cfg)
|
|||
else
|
||||
MAIH.add_aspects(cfg.side, aspect_parms)
|
||||
end
|
||||
return required_keys, {}, CA_parms
|
||||
return {}, {}, CA_parms
|
||||
end
|
||||
|
|
|
@ -45,21 +45,6 @@ function wesnoth.micro_ais.recruit_random(cfg)
|
|||
{ ca_id = "move", location = 'ca_recruit_random.lua', score = cfg.ca_score or 180000 }
|
||||
}
|
||||
|
||||
if (cfg.action ~= 'delete') then
|
||||
-- The 'probability' tags need to be handled separately here
|
||||
cfg.type, cfg.prob = {}, {}
|
||||
for probability in H.child_range(cfg, "probability") do
|
||||
if (not probability.type) then
|
||||
H.wml_error("Random Recruiting Micro AI [probability] tag is missing required type= key")
|
||||
end
|
||||
if (not probability.probability) then
|
||||
H.wml_error("Random Recruiting Micro AI [probability] tag is missing required probability= key")
|
||||
end
|
||||
table.insert(cfg.type, probability.type)
|
||||
table.insert(cfg.prob, probability.probability)
|
||||
end
|
||||
end
|
||||
|
||||
handle_default_recruitment(cfg)
|
||||
return {}, optional_keys, CA_parms
|
||||
end
|
|
@ -1,5 +1,6 @@
|
|||
local H = wesnoth.require "lua/helper.lua"
|
||||
local W = H.set_wml_action_metatable {}
|
||||
local T = H.set_wml_tag_metatable {}
|
||||
local AH = wesnoth.require("ai/lua/ai_helper.lua")
|
||||
local MAIUV = wesnoth.require "ai/micro_ais/micro_ai_unit_variables.lua"
|
||||
|
||||
|
@ -38,7 +39,7 @@ function micro_ai_helper.add_CAs(side, CA_parms, CA_cfg)
|
|||
end
|
||||
|
||||
-- Ideally, we would also delete previous occurrences of [micro_ai] tags in the
|
||||
-- AI's self.data variable. However, the MAI can be changed while it is not
|
||||
-- AI's data variable. However, the MAI can be changed while it is not
|
||||
-- the AI's turn, when this is not possible. So instead, we check for the
|
||||
-- existence of such tags and make sure we are using a different ai_id.
|
||||
for ai_tag in H.child_range(wesnoth.sides[side].__cfg, 'ai') do
|
||||
|
@ -74,15 +75,13 @@ function micro_ai_helper.add_CAs(side, CA_parms, CA_cfg)
|
|||
}
|
||||
|
||||
CA.location = parms.location
|
||||
local cfg = string.sub(AH.serialize(CA_cfg), 2, -2) -- need to strip surrounding {}
|
||||
CA.eval_parms = cfg
|
||||
CA.exec_parms = cfg
|
||||
table.insert(CA, T.args(CA_cfg))
|
||||
|
||||
W.modify_ai {
|
||||
side = side,
|
||||
action = "add",
|
||||
path = "stage[main_loop].candidate_action",
|
||||
{ "candidate_action", CA }
|
||||
T.candidate_action(CA)
|
||||
}
|
||||
end
|
||||
end
|
||||
|
@ -136,7 +135,7 @@ function micro_ai_helper.add_aspects(side, aspect_parms)
|
|||
side = side,
|
||||
action = "add",
|
||||
path = "aspect[" .. parms.aspect .. "].facet",
|
||||
{ "facet", parms.facet }
|
||||
T.facet(parms.facet)
|
||||
}
|
||||
end
|
||||
end
|
||||
|
@ -180,14 +179,14 @@ function micro_ai_helper.micro_ai_setup(cfg, CA_parms, required_keys, optional_k
|
|||
H.wml_error("[micro_ai] tag (" .. cfg.ai_type .. ") is missing required parameter: " .. v)
|
||||
end
|
||||
CA_cfg[v] = cfg[v]
|
||||
if child then CA_cfg[v] = child end
|
||||
if child then table.insert(CA_cfg, T[v](child)) end
|
||||
end
|
||||
|
||||
-- Optional keys
|
||||
for _,v in pairs(optional_keys) do
|
||||
CA_cfg[v] = cfg[v]
|
||||
local child = H.get_child(cfg, v)
|
||||
if child then CA_cfg[v] = child end
|
||||
if child then table.insert(CA_cfg, T[v](child)) end
|
||||
end
|
||||
|
||||
-- Finally, set up the candidate actions themselves
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
-- This set of functions provides a consistent way of storing Micro AI variables
|
||||
-- in the AI's persistent self.data variable. These need to be stored inside
|
||||
-- in the AI's persistent data variable. These need to be stored inside
|
||||
-- a [micro_ai] tag, so that they are bundled together for a given Micro AI
|
||||
-- together with an ai_id= key. Their existence can then be checked when setting
|
||||
-- up another MAI. Otherwise other Micro AIs used in the same scenario might
|
||||
-- work incorrectly or not at all.
|
||||
-- Note that, ideally, we would delete these [micro_ai] tags when a Micro AI is
|
||||
-- deleted, but that that is not always possible as deletion can happen on
|
||||
-- another side's turn, while the self.data variable is only accessible during
|
||||
-- another side's turn, while the data variable is only accessible during
|
||||
-- the AI turn.
|
||||
-- Note that, with this method, there can only ever be one of these tags for each
|
||||
-- Micro AI (but of course several when there are several Micro AIs for the
|
||||
|
@ -18,7 +18,7 @@ local H = wesnoth.require "lua/helper.lua"
|
|||
local micro_ai_self_data = {}
|
||||
|
||||
function micro_ai_self_data.modify_mai_self_data(self_data, ai_id, action, vars_table)
|
||||
-- Modify self.data [micro_ai] tags
|
||||
-- Modify data [micro_ai] tags
|
||||
-- @ai_id (string): the id of the Micro AI
|
||||
-- @action (string): "delete", "set" or "insert"
|
||||
-- @vars_table: table of key=value pairs with the variables to be set or inserted
|
||||
|
@ -73,7 +73,7 @@ function micro_ai_self_data.set_mai_self_data(self_data, ai_id, vars_table)
|
|||
end
|
||||
|
||||
function micro_ai_self_data.get_mai_self_data(self_data, ai_id, key)
|
||||
-- Get the content of the self.data [micro_ai] tag for the given @ai_id
|
||||
-- Get the content of the data [micro_ai] tag for the given @ai_id
|
||||
-- Return value:
|
||||
-- - If tag is found: value of key if @key parameter is given, otherwise
|
||||
-- table of key=value pairs (including the ai_id key)
|
||||
|
|
|
@ -55,7 +55,7 @@
|
|||
[engine]
|
||||
name="lua"
|
||||
code= <<
|
||||
return wesnoth.require("ai/micro_ais/engines/priority_target_engine.lua").init(ai)
|
||||
return wesnoth.require("ai/micro_ais/engines/priority_target_engine.lua").init()
|
||||
>>
|
||||
[/engine]
|
||||
[modify_ai]
|
||||
|
|
Loading…
Add table
Reference in a new issue