From ed406495d74710567ef96b1f85cddfe43d1aae12 Mon Sep 17 00:00:00 2001 From: mattsc Date: Sun, 2 Sep 2018 12:57:11 -0700 Subject: [PATCH] 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 3bfd59f28ba7f70a6ac32782e98cba9ca6c2a44a) --- data/ai/lua/ca_castle_switch.lua | 11 ++- data/ai/lua/ca_grab_villages.lua | 10 +- data/ai/lua/ca_high_xp_attack.lua | 8 +- data/ai/lua/ca_move_to_any_enemy.lua | 9 +- data/ai/lua/ca_retreat_injured.lua | 12 ++- data/ai/lua/ca_spread_poison.lua | 10 +- .../ai/micro_ais/cas/ca_bottleneck_attack.lua | 20 ++-- data/ai/micro_ais/cas/ca_bottleneck_move.lua | 92 ++++++++++--------- data/ai/micro_ais/cas/ca_fast_combat.lua | 50 +++++----- .../micro_ais/cas/ca_fast_combat_leader.lua | 25 ++--- .../ai/ca_aggressive_attack_no_suicide.lua | 8 +- .../The_Rise_Of_Wesnoth/ai/ca_retreat.lua | 10 +- 12 files changed, 148 insertions(+), 117 deletions(-) diff --git a/data/ai/lua/ca_castle_switch.lua b/data/ai/lua/ca_castle_switch.lua index 6927a2ea67f..56aa829e7c2 100644 --- a/data/ai/lua/ca_castle_switch.lua +++ b/data/ai/lua/ca_castle_switch.lua @@ -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 diff --git a/data/ai/lua/ca_grab_villages.lua b/data/ai/lua/ca_grab_villages.lua index 09a1d8b33f3..13f252bab8d 100644 --- a/data/ai/lua/ca_grab_villages.lua +++ b/data/ai/lua/ca_grab_villages.lua @@ -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 diff --git a/data/ai/lua/ca_high_xp_attack.lua b/data/ai/lua/ca_high_xp_attack.lua index 3049e98b040..984224505a2 100644 --- a/data/ai/lua/ca_high_xp_attack.lua +++ b/data/ai/lua/ca_high_xp_attack.lua @@ -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 diff --git a/data/ai/lua/ca_move_to_any_enemy.lua b/data/ai/lua/ca_move_to_any_enemy.lua index aae0afdc2b8..d5930f47d27 100644 --- a/data/ai/lua/ca_move_to_any_enemy.lua +++ b/data/ai/lua/ca_move_to_any_enemy.lua @@ -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 diff --git a/data/ai/lua/ca_retreat_injured.lua b/data/ai/lua/ca_retreat_injured.lua index 0932edf09c1..9fbced337e1 100644 --- a/data/ai/lua/ca_retreat_injured.lua +++ b/data/ai/lua/ca_retreat_injured.lua @@ -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 diff --git a/data/ai/lua/ca_spread_poison.lua b/data/ai/lua/ca_spread_poison.lua index cf36f8a136a..187b9d74353 100644 --- a/data/ai/lua/ca_spread_poison.lua +++ b/data/ai/lua/ca_spread_poison.lua @@ -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 diff --git a/data/ai/micro_ais/cas/ca_bottleneck_attack.lua b/data/ai/micro_ais/cas/ca_bottleneck_attack.lua index e65b12dd8e7..36d02f85925 100644 --- a/data/ai/micro_ais/cas/ca_bottleneck_attack.lua +++ b/data/ai/micro_ais/cas/ca_bottleneck_attack.lua @@ -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 diff --git a/data/ai/micro_ais/cas/ca_bottleneck_move.lua b/data/ai/micro_ais/cas/ca_bottleneck_move.lua index 9c9c81b04f7..88186d598a1 100644 --- a/data/ai/micro_ais/cas/ca_bottleneck_move.lua +++ b/data/ai/micro_ais/cas/ca_bottleneck_move.lua @@ -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 diff --git a/data/ai/micro_ais/cas/ca_fast_combat.lua b/data/ai/micro_ais/cas/ca_fast_combat.lua index 26ce2d5fe70..9dccb1db93e 100644 --- a/data/ai/micro_ais/cas/ca_fast_combat.lua +++ b/data/ai/micro_ais/cas/ca_fast_combat.lua @@ -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 diff --git a/data/ai/micro_ais/cas/ca_fast_combat_leader.lua b/data/ai/micro_ais/cas/ca_fast_combat_leader.lua index 5316fced9c2..b24e8c63620 100644 --- a/data/ai/micro_ais/cas/ca_fast_combat_leader.lua +++ b/data/ai/micro_ais/cas/ca_fast_combat_leader.lua @@ -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 diff --git a/data/campaigns/The_Rise_Of_Wesnoth/ai/ca_aggressive_attack_no_suicide.lua b/data/campaigns/The_Rise_Of_Wesnoth/ai/ca_aggressive_attack_no_suicide.lua index 69d7e435920..6528507077b 100644 --- a/data/campaigns/The_Rise_Of_Wesnoth/ai/ca_aggressive_attack_no_suicide.lua +++ b/data/campaigns/The_Rise_Of_Wesnoth/ai/ca_aggressive_attack_no_suicide.lua @@ -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 diff --git a/data/campaigns/The_Rise_Of_Wesnoth/ai/ca_retreat.lua b/data/campaigns/The_Rise_Of_Wesnoth/ai/ca_retreat.lua index af796e4160b..0c6c6b92d39 100644 --- a/data/campaigns/The_Rise_Of_Wesnoth/ai/ca_retreat.lua +++ b/data/campaigns/The_Rise_Of_Wesnoth/ai/ca_retreat.lua @@ -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