Lua AIs: do not use engine's 'data' variable unless necessary

Now that all the AIs use external CAs, there is no need to use the persistent 'data' variable any more, unless information is to be exchanged between different CAs or is supposed to be persistent across save/load cycles.

(cherry-picked from commit 3bfd59f28b)
This commit is contained in:
mattsc 2018-09-02 12:57:11 -07:00
parent 740bd456ab
commit ed406495d7
12 changed files with 148 additions and 117 deletions

View file

@ -3,6 +3,9 @@
local AH = wesnoth.require "ai/lua/ai_helper.lua"
local M = wesnoth.map
local CS_leader_score
-- Note that leader_target is also needed by the recruiting CA, so it must be stored in 'data'
local function get_reachable_enemy_leaders(unit)
-- We're cheating a little here and also find hidden enemy leaders. That's
-- because a human player could make a pretty good educated guess as to where
@ -51,7 +54,7 @@ function ca_castle_switch:evaluation(cfg, data)
local next_hop = AH.next_hop(leader, data.leader_target[1], data.leader_target[2])
if next_hop and next_hop[1] == data.leader_target[1]
and next_hop[2] == data.leader_target[2] then
return data.leader_score
return CS_leader_score
end
end
@ -158,7 +161,7 @@ function ca_castle_switch:evaluation(cfg, data)
data.leader_target = next_hop
-- if we're on a keep, wait until there are no movable units on the castle before moving off
data.leader_score = 290000
CS_leader_score = 290000
if wesnoth.get_terrain_info(wesnoth.get_terrain(leader.x, leader.y)).keep then
local castle = wesnoth.get_locations {
x = "1-"..width, y = "1-"..height,
@ -178,12 +181,12 @@ function ca_castle_switch:evaluation(cfg, data)
end
end
if should_wait then
data.leader_score = 15000
CS_leader_score = 15000
end
end
if AH.print_eval() then AH.done_eval_messages(start_time, ca_name) end
return data.leader_score
return CS_leader_score
end
if AH.print_eval() then AH.done_eval_messages(start_time, ca_name) end

View file

@ -4,6 +4,8 @@ local AH = wesnoth.require "ai/lua/ai_helper.lua"
local BC = wesnoth.require "ai/lua/battle_calcs.lua"
local M = wesnoth.map
local GV_unit, GV_village
local ca_grab_villages = {}
function ca_grab_villages:evaluation(cfg, data)
@ -116,7 +118,7 @@ function ca_grab_villages:evaluation(cfg, data)
end
if best_village then
data.unit, data.village = best_unit, best_village
GV_unit, GV_village = best_unit, best_village
if (max_rating >= 1000) then
if AH.print_eval() then AH.done_eval_messages(start_time, ca_name) end
return return_value
@ -131,10 +133,10 @@ end
function ca_grab_villages:execution(cfg, data)
if AH.print_exec() then AH.print_ts(' Executing grab_villages CA') end
if AH.show_messages() then wesnoth.wml_actions.message { speaker = data.unit.id, message = 'Grab villages' } end
if AH.show_messages() then wesnoth.wml_actions.message { speaker = GV_unit.id, message = 'Grab villages' } end
AH.movefull_stopunit(ai, data.unit, data.village)
data.unit, data.village = nil, nil
AH.movefull_stopunit(ai, GV_unit, GV_village)
GV_unit, GV_village = nil, nil
end
return ca_grab_villages

View file

@ -26,6 +26,8 @@ local M = wesnoth.map
-- so that we can follow up with stronger units. In addition, use of poison or
-- slow attacks is strongly discouraged. See code for exact equations.
local XP_attack
local ca_attack_highxp = {}
function ca_attack_highxp:evaluation(cfg, data)
@ -284,15 +286,15 @@ function ca_attack_highxp:evaluation(cfg, data)
end
if best_attack then
data.XP_attack = best_attack
XP_attack = best_attack
end
return max_ca_score
end
function ca_attack_highxp:execution(cfg, data)
AH.robust_move_and_attack(ai, data.XP_attack.src, data.XP_attack.dst, data.XP_attack.target, { weapon = data.XP_attack.attack_num })
data.XP_attack = nil
AH.robust_move_and_attack(ai, XP_attack.src, XP_attack.dst, XP_attack.target, { weapon = XP_attack.attack_num })
XP_attack = nil
end
return ca_attack_highxp

View file

@ -5,6 +5,8 @@
local AH = wesnoth.require "ai/lua/ai_helper.lua"
local MTAE_unit, MTAE_destination
local ca_move_to_any_enemy = {}
function ca_move_to_any_enemy:evaluation(cfg, data)
@ -45,8 +47,8 @@ function ca_move_to_any_enemy:evaluation(cfg, data)
return 0
end
data.destination = destination
data.unit = unit
MTAE_destination = destination
MTAE_unit = unit
if AH.print_eval() then AH.done_eval_messages(start_time, ca_name) end
return 1
@ -54,7 +56,8 @@ end
function ca_move_to_any_enemy:execution(cfg, data)
if AH.print_exec() then AH.print_ts(' Executing move_to_any_enemy CA') end
AH.checked_move(ai, data.unit, data.destination[1], data.destination[2])
AH.checked_move(ai, MTAE_unit, MTAE_destination[1], MTAE_destination[2])
MTAE_unit, MTAE_destination = nil,nil
end
return ca_move_to_any_enemy

View file

@ -3,6 +3,8 @@
local AH = wesnoth.require "ai/lua/ai_helper.lua"
local R = wesnoth.require "ai/lua/retreat.lua"
local retreat_unit, retreat_loc
local ca_retreat_injured = {}
function ca_retreat_injured:evaluation(cfg, data)
@ -15,8 +17,8 @@ function ca_retreat_injured:evaluation(cfg, data)
}
local unit, loc = R.retreat_injured_units(units)
if unit then
data.retreat_unit = unit
data.retreat_loc = loc
retreat_unit = unit
retreat_loc = loc
-- First check if attacks are possible for any unit
-- If one with > 50% chance of kill is possible, set return_value to lower than combat CA
@ -36,9 +38,9 @@ end
function ca_retreat_injured:execution(cfg, data)
if AH.print_exec() then AH.print_ts(' Executing retreat_injured CA') end
AH.robust_move_and_attack(ai, data.retreat_unit, data.retreat_loc)
data.retreat_unit = nil
data.retreat_loc = nil
AH.robust_move_and_attack(ai, retreat_unit, retreat_loc)
retreat_unit = nil
retreat_loc = nil
end
return ca_retreat_injured

View file

@ -2,6 +2,8 @@
local AH = wesnoth.require "ai/lua/ai_helper.lua"
local SP_attack
local ca_spread_poison = {}
function ca_spread_poison:evaluation(cfg, data)
@ -78,7 +80,7 @@ function ca_spread_poison:evaluation(cfg, data)
end
if best_attack then
data.attack = best_attack
SP_attack = best_attack
if AH.print_eval() then AH.done_eval_messages(start_time, ca_name) end
return 190000
end
@ -87,16 +89,16 @@ function ca_spread_poison:evaluation(cfg, data)
end
function ca_spread_poison:execution(cfg, data)
local attacker = wesnoth.get_unit(data.attack.src.x, data.attack.src.y)
local attacker = wesnoth.get_unit(SP_attack.src.x, SP_attack.src.y)
-- If several attacks have poison, this will always find the last one
local is_poisoner, poison_weapon = AH.has_weapon_special(attacker, "poison")
if AH.print_exec() then AH.print_ts(' Executing spread_poison CA') end
if AH.show_messages() then wesnoth.wml_actions.message { speaker = attacker.id, message = 'Poison attack' } end
AH.robust_move_and_attack(ai, attacker, data.attack.dst, data.attack.target, { weapon = poison_weapon })
AH.robust_move_and_attack(ai, attacker, SP_attack.dst, SP_attack.target, { weapon = poison_weapon })
data.attack = nil
SP_attack = nil
end
return ca_spread_poison

View file

@ -1,5 +1,7 @@
local AH = wesnoth.require "ai/lua/ai_helper.lua"
local BD_attacker, BD_target, BD_weapon, BD_bottleneck_attacks_done
local ca_bottleneck_attack = {}
function ca_bottleneck_attack:evaluation(cfg, data)
@ -48,29 +50,29 @@ function ca_bottleneck_attack:evaluation(cfg, data)
if (not best_attacker) then
-- In this case we take attacks away from all units
data.BD_bottleneck_attacks_done = true
BD_bottleneck_attacks_done = true
else
data.BD_bottleneck_attacks_done = false
data.BD_attacker = best_attacker
data.BD_target = best_target
data.BD_weapon = best_weapon
BD_bottleneck_attacks_done = false
BD_attacker = best_attacker
BD_target = best_target
BD_weapon = best_weapon
end
return cfg.ca_score
end
function ca_bottleneck_attack:execution(cfg, data)
if data.BD_bottleneck_attacks_done then
if 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, data.BD_attacker, data.BD_target, data.BD_weapon)
AH.checked_attack(ai, BD_attacker, BD_target, BD_weapon)
end
data.BD_attacker, data.BD_target, data.BD_weapon = nil, nil, nil
data.BD_bottleneck_attacks_done = nil
BD_attacker, BD_target, BD_weapon = nil, nil, nil
BD_bottleneck_attacks_done = nil
end
return ca_bottleneck_attack

View file

@ -5,6 +5,10 @@ local BC = wesnoth.require "ai/lua/battle_calcs.lua"
local MAISD = wesnoth.require "ai/micro_ais/micro_ai_self_data.lua"
local M = wesnoth.map
local BD_unit, BD_hex
local BD_level_up_defender, BD_level_up_weapon, BD_bottleneck_moves_done
local BD_is_my_territory, BD_def_map, BD_healer_map, BD_leadership_map, BD_healing_map
local function bottleneck_is_my_territory(map, enemy_map)
-- Create map that contains 'true' for all hexes that are
-- on the AI's side of the map
@ -85,16 +89,16 @@ end
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
-- data.BD_def_map must have been created when this function is called.
-- 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()
data.BD_def_map:iter(function(x, y, v)
BD_def_map:iter(function(x, y, v)
for xa,ya in H.adjacent_tiles(x, y) do
if data.BD_is_my_territory:get(xa, ya) then
local rating = data.BD_def_map:get(x, y) or 0
if BD_is_my_territory:get(xa, ya) then
local rating = BD_def_map:get(x, y) or 0
rating = rating + (map:get(xa, ya) or 0)
map:insert(xa, ya, rating)
end
@ -109,7 +113,7 @@ local function bottleneck_create_positioning_map(max_value, data)
-- We merge the defense map into this, as healers/leaders (by default)
-- can take position on the front line
map:union_merge(data.BD_def_map,
map:union_merge(BD_def_map,
function(x, y, v1, v2) return v1 or v2 end
)
@ -126,18 +130,18 @@ local function bottleneck_get_rating(unit, x, y, has_leadership, is_healer, data
-- 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 = data.BD_def_map:get(x, y) or 0
rating = BD_def_map:get(x, y) or 0
end
-- Healer positioning rating
if is_healer then
local healer_rating = data.BD_healer_map:get(x, y) or 0
local healer_rating = 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 = data.BD_leadership_map:get(x, y) or 0
local leadership_rating = 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
@ -155,18 +159,18 @@ local function bottleneck_get_rating(unit, x, y, has_leadership, is_healer, data
-- Injured unit positioning
if (unit.hitpoints < unit.max_hitpoints) then
local healing_rating = data.BD_healing_map:get(x, y) or 0
local healing_rating = 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 data.BD_is_my_territory:get(x, y) then
if (rating <= 0) and BD_is_my_territory:get(x, y) then
local combined_dist = 0
data.BD_def_map:iter(function(x_def, y_def, v)
BD_def_map:iter(function(x_def, y_def, v)
combined_dist = combined_dist + M.distance_between(x, y, x_def, y_def)
end)
combined_dist = combined_dist / data.BD_def_map:size()
combined_dist = combined_dist / BD_def_map:size()
rating = 1000 - combined_dist * 10.
end
@ -194,7 +198,7 @@ local function bottleneck_move_out_of_way(unit_in_way, data)
local best_reach, best_hex = - math.huge
for _,loc in ipairs(reach) do
if data.BD_is_my_territory:get(loc[1], loc[2]) and (not occ_hexes:get(loc[1], loc[2])) then
if 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] }
@ -232,54 +236,54 @@ function ca_bottleneck_move:evaluation(cfg, data)
if (not units[1]) then return 0 end
-- Set up the array that tells the AI where to defend the bottleneck
data.BD_def_map = bottleneck_triple_from_keys(cfg.x, cfg.y, 10000)
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, 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 data.BD_is_my_territory) or (type(data.BD_is_my_territory) == 'string') then
-- However, after a reload, BD_is_my_territory is empty
-- -> need to recalculate in that case also
if (not BD_is_my_territory) or (type(BD_is_my_territory) == 'string') then
local enemy_map = bottleneck_triple_from_keys(cfg.enemy_x, cfg.enemy_y, 10000)
data.BD_is_my_territory = bottleneck_is_my_territory(data.BD_def_map, enemy_map)
BD_is_my_territory = bottleneck_is_my_territory(BD_def_map, enemy_map)
end
-- Healer positioning map
if cfg.healer_x and cfg.healer_y then
data.BD_healer_map = bottleneck_triple_from_keys(cfg.healer_x, cfg.healer_y, 5000)
BD_healer_map = bottleneck_triple_from_keys(cfg.healer_x, cfg.healer_y, 5000)
else
data.BD_healer_map = bottleneck_create_positioning_map(5000, 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
data.BD_healer_map:inter_merge(data.BD_def_map,
BD_healer_map:inter_merge(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
data.BD_leadership_map = bottleneck_triple_from_keys(cfg.leadership_x, cfg.leadership_y, 4000)
BD_leadership_map = bottleneck_triple_from_keys(cfg.leadership_x, cfg.leadership_y, 4000)
else
data.BD_leadership_map = bottleneck_create_positioning_map(4000, 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
data.BD_leadership_map:inter_merge(data.BD_def_map,
BD_leadership_map:inter_merge(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" }
data.BD_healing_map = LS.create()
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 data.BD_is_my_territory:get(xa, ya) then
if BD_is_my_territory:get(xa, ya) then
local min_dist = math.huge
data.BD_def_map:iter( function(xd, yd, vd)
BD_def_map:iter( function(xd, yd, vd)
local dist_line = M.distance_between(xa, ya, xd, yd)
if (dist_line < min_dist) then min_dist = dist_line end
end)
if (min_dist > 0) then
data.BD_healing_map:insert(xa, ya, 3000 + min_dist) -- Farther away from enemy is good
BD_healing_map:insert(xa, ya, 3000 + min_dist) -- Farther away from enemy is good
end
end
end
@ -314,7 +318,7 @@ function ca_bottleneck_move:evaluation(cfg, data)
local attacks = {}
for _,enemy in ipairs(enemies) do
for xa,ya in H.adjacent_tiles(enemy.x, enemy.y) do
if data.BD_is_my_territory:get(xa, ya) then
if BD_is_my_territory:get(xa, ya) then
local unit_in_way = wesnoth.get_unit(xa, ya)
if (not AH.is_visible_unit(wesnoth.current.side, unit_in_way)) then
unit_in_way = nil
@ -417,8 +421,8 @@ function ca_bottleneck_move:evaluation(cfg, data)
if (level_up_rating > max_rating) then
max_rating, best_unit, best_hex = level_up_rating, unit, { loc[1], loc[2] }
data.BD_level_up_defender = attack.defender
data.BD_level_up_weapon = n_weapon
BD_level_up_defender = attack.defender
BD_level_up_weapon = n_weapon
end
end
end
@ -428,7 +432,7 @@ function ca_bottleneck_move:evaluation(cfg, data)
-- Set the variables for the exec() function
if (not best_hex) then
data.BD_bottleneck_moves_done = true
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],
@ -441,19 +445,19 @@ function ca_bottleneck_move:evaluation(cfg, data)
if unit_in_way then
best_hex = bottleneck_move_out_of_way(unit_in_way, data)
best_unit = unit_in_way
data.BD_level_up_defender = nil
data.BD_level_up_weapon = nil
BD_level_up_defender = nil
BD_level_up_weapon = nil
end
data.BD_bottleneck_moves_done = false
data.BD_unit, data.BD_hex = best_unit, best_hex
BD_bottleneck_moves_done = false
BD_unit, BD_hex = best_unit, best_hex
end
return cfg.ca_score
end
function ca_bottleneck_move:execution(cfg, data)
if data.BD_bottleneck_moves_done then
if BD_bottleneck_moves_done then
local units = {}
if MAISD.get_mai_self_data(data, cfg.ai_id, "side_leader_activated") then
units = AH.get_units_with_moves { side = wesnoth.current.side }
@ -466,16 +470,16 @@ function ca_bottleneck_move:execution(cfg, data)
end
else
-- Don't want full move, as this might be stepping out of the way
local cfg = { partial_move = true, weapon = data.BD_level_up_weapon }
AH.robust_move_and_attack(ai, data.BD_unit, data.BD_hex, data.BD_level_up_defender, cfg)
local cfg = { partial_move = true, weapon = BD_level_up_weapon }
AH.robust_move_and_attack(ai, BD_unit, BD_hex, BD_level_up_defender, cfg)
end
-- Now delete almost everything
-- 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
-- Keep only BD_is_my_territory because it is very expensive
BD_unit, BD_hex = nil, nil
BD_level_up_defender, BD_level_up_weapon = nil, nil
BD_bottleneck_moves_done = nil
BD_def_map, BD_healer_map, BD_leadership_map, BD_healing_map = nil, nil, nil, nil
end
return ca_bottleneck_move

View file

@ -2,11 +2,14 @@ local AH = wesnoth.require "ai/lua/ai_helper.lua"
local FAU = wesnoth.require "ai/micro_ais/cas/ca_fast_attack_utils.lua"
local LS = wesnoth.require "location_set"
local fast_combat_units, fast_combat_unit_i,fast_target, fast_dst
local gamedata, move_cache
local ca_fast_combat = {}
function ca_fast_combat:evaluation(cfg, data)
data.move_cache = { turn = wesnoth.current.turn }
data.gamedata = FAU.gamedata_setup()
move_cache = { turn = wesnoth.current.turn }
gamedata = FAU.gamedata_setup()
local filter_own = wml.get_child(cfg, "filter")
local filter_enemy = wml.get_child(cfg, "filter_second")
@ -15,24 +18,24 @@ function ca_fast_combat:evaluation(cfg, data)
local units_sorted = true
if (not filter_own) and (not filter_enemy) then
local attacks_aspect = ai.aspects.attacks
if (not data.fast_combat_units) or (not data.fast_combat_units[1]) then
if (not fast_combat_units) or (not fast_combat_units[1]) then
-- Leader is dealt with in a separate CA
data.fast_combat_units = {}
fast_combat_units = {}
for _,unit in ipairs(attacks_aspect.own) do
if (not unit.canrecruit) then
table.insert(data.fast_combat_units, unit)
table.insert(fast_combat_units, unit)
end
end
if (not data.fast_combat_units[1]) then return 0 end
if (not fast_combat_units[1]) then return 0 end
units_sorted = false
end
enemies = attacks_aspect.enemy
else
if (not data.fast_combat_units) or (not data.fast_combat_units[1]) then
data.fast_combat_units = AH.get_live_units(
if (not fast_combat_units) or (not fast_combat_units[1]) then
fast_combat_units = AH.get_live_units(
FAU.build_attack_filter("own", filter_own)
)
if (not data.fast_combat_units[1]) then return 0 end
if (not fast_combat_units[1]) then return 0 end
units_sorted = false
end
enemies = AH.get_live_units(
@ -43,9 +46,9 @@ function ca_fast_combat:evaluation(cfg, data)
if not units_sorted then
-- 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(data.fast_combat_units, function(a,b) return a.hitpoints > b.hitpoints end)
table.sort(fast_combat_units, function(a,b) return a.hitpoints > b.hitpoints end)
else
table.sort(data.fast_combat_units, function(a,b) return a.hitpoints < b.hitpoints end)
table.sort(fast_combat_units, function(a,b) return a.hitpoints < b.hitpoints end)
end
end
@ -75,12 +78,12 @@ function ca_fast_combat:evaluation(cfg, data)
-- Get the locations to be avoided
local avoid_map = FAU.get_avoid_map(cfg)
for i = #data.fast_combat_units,1,-1 do
local unit = data.fast_combat_units[i]
for i = #fast_combat_units,1,-1 do
local unit = fast_combat_units[i]
if unit and unit.valid and (unit.attacks_left > 0) and (#unit.attacks > 0) then
local unit_info = FAU.get_unit_info(unit, data.gamedata)
local unit_copy = FAU.get_unit_copy(unit.id, data.gamedata)
local unit_info = FAU.get_unit_info(unit, gamedata)
local unit_copy = FAU.get_unit_copy(unit.id, gamedata)
local attacks = AH.get_attacks({ unit }, { include_occupied = cfg.include_occupied_attack_hexes, viewing_side = viewing_side })
if (#attacks > 0) then
@ -90,16 +93,16 @@ function ca_fast_combat:evaluation(cfg, data)
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, data.gamedata)
local target_info = FAU.get_unit_info(target, gamedata)
local att_stat, def_stat = FAU.battle_outcome(
unit_copy, target, { attack.dst.x, attack.dst.y },
unit_info, target_info, data.gamedata, data.move_cache
unit_info, target_info, gamedata, 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, data.gamedata,
{ att_stat }, def_stat, gamedata,
{
aggression = aggression,
leader_weight = cfg.leader_weight
@ -115,22 +118,23 @@ function ca_fast_combat:evaluation(cfg, data)
end
if best_target then
data.fast_combat_unit_i = i
data.fast_target, data.fast_dst = best_target, best_dst
fast_combat_unit_i = i
fast_target, fast_dst = best_target, best_dst
return cfg.ca_score
end
end
end
data.fast_combat_units[i] = nil
fast_combat_units[i] = nil
end
return 0
end
function ca_fast_combat:execution(cfg, data)
AH.robust_move_and_attack(ai, data.fast_combat_units[data.fast_combat_unit_i], data.fast_dst, data.fast_target)
data.fast_combat_units[data.fast_combat_unit_i] = nil
AH.robust_move_and_attack(ai, fast_combat_units[fast_combat_unit_i], fast_dst, fast_target)
fast_combat_units[fast_combat_unit_i] = nil
fast_combat_unit_i,fast_target, fast_dst = nil, nil, nil
end
return ca_fast_combat

View file

@ -3,6 +3,9 @@ local AH = wesnoth.require "ai/lua/ai_helper.lua"
local FAU = wesnoth.require "ai/micro_ais/cas/ca_fast_attack_utils.lua"
local LS = wesnoth.require "location_set"
local leader, fast_target, fast_dst
local gamedata, move_cache
local ca_fast_combat_leader = {}
function ca_fast_combat_leader:evaluation(cfg, data)
@ -15,8 +18,8 @@ function ca_fast_combat_leader:evaluation(cfg, data)
leader_attack_max_units = (cfg and cfg.leader_attack_max_units) or 3
leader_additional_threat = (cfg and cfg.leader_additional_threat) or 1
data.move_cache = { turn = wesnoth.current.turn }
data.gamedata = FAU.gamedata_setup()
move_cache = { turn = wesnoth.current.turn }
gamedata = FAU.gamedata_setup()
local filter_own = wml.get_child(cfg, "filter")
local filter_enemy = wml.get_child(cfg, "filter_second")
@ -101,8 +104,8 @@ function ca_fast_combat_leader:evaluation(cfg, data)
end
end
local leader_info = FAU.get_unit_info(leader, data.gamedata)
local leader_copy = FAU.get_unit_copy(leader.id, data.gamedata)
local leader_info = FAU.get_unit_info(leader, gamedata)
local leader_copy = FAU.get_unit_copy(leader.id, gamedata)
-- If threatened_leader_fights=yes, check out the current threat (power only,
-- not units) on the AI leader
@ -149,16 +152,16 @@ function ca_fast_combat_leader:evaluation(cfg, data)
if acceptable_attack then
local target = wesnoth.get_unit(attack.target.x, attack.target.y)
local target_info = FAU.get_unit_info(target, data.gamedata)
local target_info = FAU.get_unit_info(target, gamedata)
local att_stat, def_stat = FAU.battle_outcome(
leader_copy, target, { attack.dst.x, attack.dst.y },
leader_info, target_info, data.gamedata, data.move_cache
leader_info, target_info, gamedata, 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, data.gamedata,
{ att_stat }, def_stat, gamedata,
{
aggression = aggression,
leader_weight = leader_weight
@ -175,8 +178,8 @@ function ca_fast_combat_leader:evaluation(cfg, data)
end
if best_target then
data.leader = leader
data.fast_target, data.fast_dst = best_target, best_dst
leader = leader
fast_target, fast_dst = best_target, best_dst
return cfg.ca_score
end
end
@ -185,8 +188,8 @@ function ca_fast_combat_leader:evaluation(cfg, data)
end
function ca_fast_combat_leader:execution(cfg, data)
AH.robust_move_and_attack(ai, data.leader, data.fast_dst, data.fast_target)
data.leader, data.fast_target, data.fast_dst = nil, nil, nil
AH.robust_move_and_attack(ai, leader, fast_dst, fast_target)
leader, fast_target, fast_dst = nil, nil, nil
end
return ca_fast_combat_leader

View file

@ -1,5 +1,7 @@
local AH = wesnoth.require "ai/lua/ai_helper.lua"
local AANS_attack
local ca_aggressive_attack_no_suicide = {}
function ca_aggressive_attack_no_suicide:evaluation(cfg, data)
@ -45,7 +47,7 @@ function ca_aggressive_attack_no_suicide:evaluation(cfg, data)
end
if best_attack then
data.attack = best_attack
AANS_attack = best_attack
return 100000
end
@ -53,8 +55,8 @@ function ca_aggressive_attack_no_suicide:evaluation(cfg, data)
end
function ca_aggressive_attack_no_suicide:execution(cfg, data)
AH.robust_move_and_attack(ai, data.attack.src, data.attack.dst, data.attack.target)
data.attack = nil
AH.robust_move_and_attack(ai, AANS_attack.src, AANS_attack.dst, AANS_attack.target)
AANS_attack = nil
end
return ca_aggressive_attack_no_suicide

View file

@ -1,6 +1,8 @@
local R = wesnoth.require "ai/lua/retreat.lua"
local AH = wesnoth.require "ai/lua/ai_helper.lua"
local retreat_unit, retreat_dst
local retreat = {}
function retreat:evaluation(cfg, data)
@ -14,8 +16,8 @@ function retreat:evaluation(cfg, data)
local unit, dst, enemy_threat = R.retreat_injured_units(units)
if unit then
data.retreat_unit = unit
data.retreat_dst = dst
retreat_unit = unit
retreat_dst = dst
return 101000
end
@ -23,8 +25,8 @@ function retreat:evaluation(cfg, data)
end
function retreat:execution(cfg, data)
AH.movefull_outofway_stopunit(ai, data.retreat_unit, data.retreat_dst[1], data.retreat_dst[2])
data.retreat_unit, data.retreat_dst = nil, nil
AH.movefull_outofway_stopunit(ai, retreat_unit, retreat_dst[1], retreat_dst[2])
retreat_unit, retreat_dst = nil, nil
end
return retreat