Micro AIs: prevent potential conflicts of stored data
It’s theoretically possible that different Micro AIs’ evaluation functions store information in the same variable within self.data. This would only happen if the CAs have the same score and while this should generally be avoided when setting up a scenario, it is better to ensure that it cannot cause conflicts (not in the stored data at least, the MAIs might still interfere with each other in other respects).
This commit is contained in:
parent
1ab3faca44
commit
2396ccacb8
8 changed files with 94 additions and 94 deletions
|
@ -58,28 +58,28 @@ function ca_bottleneck_attack:evaluation(ai, cfg, self)
|
|||
if max_rating == 0 then
|
||||
-- In this case we take attacks away from all units
|
||||
-- This is done so that the RCA AI CAs can be kept in place
|
||||
self.data.bottleneck_attacks_done = true
|
||||
self.data.BD_bottleneck_attacks_done = true
|
||||
else
|
||||
self.data.bottleneck_attacks_done = false
|
||||
self.data.attacker = best_att
|
||||
self.data.target = best_tar
|
||||
self.data.weapon = best_weapon
|
||||
self.data.BD_bottleneck_attacks_done = false
|
||||
self.data.BD_attacker = best_att
|
||||
self.data.BD_target = best_tar
|
||||
self.data.BD_weapon = best_weapon
|
||||
end
|
||||
return cfg.ca_score
|
||||
end
|
||||
|
||||
function ca_bottleneck_attack:execution(ai, cfg, self)
|
||||
if self.data.bottleneck_attacks_done then
|
||||
if self.data.BD_bottleneck_attacks_done then
|
||||
local units = AH.get_units_with_attacks { side = wesnoth.current.side }
|
||||
for i,u in ipairs(units) do
|
||||
AH.checked_stopunit_attacks(ai, u)
|
||||
end
|
||||
else
|
||||
AH.checked_attack(ai, self.data.attacker, self.data.target, self.data.weapon)
|
||||
AH.checked_attack(ai, self.data.BD_attacker, self.data.BD_target, self.data.BD_weapon)
|
||||
end
|
||||
|
||||
self.data.attacker, self.data.target, self.data.weapon = nil, nil, nil
|
||||
self.data.bottleneck_attacks_done = nil
|
||||
self.data.BD_attacker, self.data.BD_target, self.data.BD_weapon = nil, nil, nil
|
||||
self.data.BD_bottleneck_attacks_done = nil
|
||||
end
|
||||
|
||||
return ca_bottleneck_attack
|
||||
|
|
|
@ -88,11 +88,11 @@ local function bottleneck_create_positioning_map(max_value, self)
|
|||
-- This might include hexes on the line itself, but
|
||||
-- only store those that are not in enemy territory
|
||||
local map = LS.create()
|
||||
self.data.def_map:iter( function(x, y, v)
|
||||
self.data.BD_def_map:iter( function(x, y, v)
|
||||
for xa, ya in H.adjacent_tiles(x, y) do
|
||||
if self.data.is_my_territory:get(xa, ya) then
|
||||
if self.data.BD_is_my_territory:get(xa, ya) then
|
||||
-- This rating adds up the scores of all the adjacent def_map hexes
|
||||
local rating = self.data.def_map:get(x, y) or 0
|
||||
local rating = self.data.BD_def_map:get(x, y) or 0
|
||||
rating = rating + (map:get(xa, ya) or 0)
|
||||
map:insert(xa, ya, rating)
|
||||
end
|
||||
|
@ -107,7 +107,7 @@ local function bottleneck_create_positioning_map(max_value, self)
|
|||
|
||||
-- Finally, we merge the defense map into this, as healers/leaders (by default)
|
||||
-- can take position on the front line
|
||||
map:union_merge(self.data.def_map,
|
||||
map:union_merge(self.data.BD_def_map,
|
||||
function(x, y, v1, v2) return v1 or v2 end
|
||||
)
|
||||
|
||||
|
@ -123,18 +123,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.def_map:get(x, y) or 0
|
||||
rating = self.data.BD_def_map:get(x, y) or 0
|
||||
end
|
||||
|
||||
-- Healer positioning rating
|
||||
if is_healer then
|
||||
local healer_rating = self.data.healer_map:get(x, y) or 0
|
||||
local healer_rating = self.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.leadership_map:get(x, y) or 0
|
||||
local leadership_rating = self.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
|
||||
|
@ -153,18 +153,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.healing_map:get(x, y) or 0
|
||||
local healing_rating = self.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.is_my_territory:get(x, y) then
|
||||
if (rating <= 0) and self.data.BD_is_my_territory:get(x, y) then
|
||||
local combined_dist = 0
|
||||
self.data.def_map:iter(function(x_def, y_def, v)
|
||||
self.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.def_map:size()
|
||||
combined_dist = combined_dist / self.data.BD_def_map:size()
|
||||
rating = 1000 - combined_dist * 10.
|
||||
end
|
||||
|
||||
|
@ -197,7 +197,7 @@ local function bottleneck_move_out_of_way(unit, self)
|
|||
-- find the closest unoccupied reachable hex in the east
|
||||
local best_reach, best_hex = -1, {}
|
||||
for i,r in ipairs(reach) do
|
||||
if self.data.is_my_territory:get(r[1], r[2]) and (not occ_hexes:get(r[1], r[2])) then
|
||||
if self.data.BD_is_my_territory:get(r[1], r[2]) and (not occ_hexes:get(r[1], r[2])) then
|
||||
-- Best hex to move out of way to:
|
||||
-- (r[3] > best_reach) : move shorter than previous best move
|
||||
if (r[3] > best_reach) then
|
||||
|
@ -245,68 +245,68 @@ function ca_bottleneck_move:evaluation(ai, cfg, self)
|
|||
|
||||
-- Set up the arrays that tell the AI where to defend the bottleneck
|
||||
-- Get the x and y coordinates (this assumes that cfg.x and cfg.y have the same length)
|
||||
self.data.def_map = bottleneck_triple_from_keys(cfg.x, cfg.y, 10000)
|
||||
--AH.put_labels(self.data.def_map)
|
||||
self.data.BD_def_map = bottleneck_triple_from_keys(cfg.x, cfg.y, 10000)
|
||||
--AH.put_labels(self.data.BD_def_map)
|
||||
|
||||
-- Get the 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.is_my_territory is an empty string
|
||||
-- However, after a reload, self.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.is_my_territory) or (type(self.data.is_my_territory) == 'string') then
|
||||
if (not self.data.BD_is_my_territory) or (type(self.data.BD_is_my_territory) == 'string') then
|
||||
local enemy_map = bottleneck_triple_from_keys(cfg.enemy_x, cfg.enemy_y, 10000)
|
||||
self.data.is_my_territory = bottleneck_is_my_territory(self.data.def_map, enemy_map)
|
||||
self.data.BD_is_my_territory = bottleneck_is_my_territory(self.data.BD_def_map, enemy_map)
|
||||
end
|
||||
--AH.put_labels(self.data.is_my_territory)
|
||||
--AH.put_labels(self.data.BD_is_my_territory)
|
||||
|
||||
-- Setting up healer positioning map
|
||||
if cfg.healer_x and cfg.healer_y then
|
||||
-- If healer_x,healer_y are given, extract locs from there
|
||||
self.data.healer_map = bottleneck_triple_from_keys(cfg.healer_x, cfg.healer_y, 5000)
|
||||
self.data.BD_healer_map = bottleneck_triple_from_keys(cfg.healer_x, cfg.healer_y, 5000)
|
||||
else
|
||||
-- Otherwise create the map here
|
||||
self.data.healer_map = bottleneck_create_positioning_map(5000, self)
|
||||
self.data.BD_healer_map = bottleneck_create_positioning_map(5000, self)
|
||||
end
|
||||
-- Use def_map values for any healer hexes that are defined in def_map as well
|
||||
self.data.healer_map:inter_merge(self.data.def_map,
|
||||
self.data.BD_healer_map:inter_merge(self.data.BD_def_map,
|
||||
function(x, y, v1, v2) return v2 or v1 end
|
||||
)
|
||||
--AH.put_labels(self.data.healer_map)
|
||||
--AH.put_labels(self.data.BD_healer_map)
|
||||
|
||||
-- Setting up leadership position map
|
||||
-- If leadership_x, leadership_y are not given, we create the leadership positioning array
|
||||
if cfg.leadership_x and cfg.leadership_y then
|
||||
-- If leadership_x,leadership_y are given, extract locs from there
|
||||
self.data.leadership_map = bottleneck_triple_from_keys(cfg.leadership_x, cfg.leadership_y, 4000)
|
||||
self.data.BD_leadership_map = bottleneck_triple_from_keys(cfg.leadership_x, cfg.leadership_y, 4000)
|
||||
else
|
||||
-- Otherwise create the map here
|
||||
self.data.leadership_map = bottleneck_create_positioning_map(4000, self)
|
||||
self.data.BD_leadership_map = bottleneck_create_positioning_map(4000, self)
|
||||
end
|
||||
-- Use def_map values for any leadership hexes that are defined in def_map as well
|
||||
self.data.leadership_map:inter_merge(self.data.def_map,
|
||||
self.data.BD_leadership_map:inter_merge(self.data.BD_def_map,
|
||||
function(x, y, v1, v2) return v2 or v1 end
|
||||
)
|
||||
--AH.put_labels(self.data.leadership_map)
|
||||
--AH.put_labels(self.data.BD_leadership_map)
|
||||
|
||||
-- healing map: positions next to healers, needs to be calculated each move
|
||||
-- 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.healing_map = LS.create()
|
||||
self.data.BD_healing_map = LS.create()
|
||||
for i,h in ipairs(healers) do
|
||||
for x, y in H.adjacent_tiles(h.x, h.y) do
|
||||
-- Cannot be on the line, and needs to be in own territory
|
||||
if self.data.is_my_territory:get(x, y) then
|
||||
if self.data.BD_is_my_territory:get(x, y) then
|
||||
local min_dist = 9e99
|
||||
self.data.def_map:iter( function(xd, yd, vd)
|
||||
self.data.BD_def_map:iter( function(xd, yd, vd)
|
||||
local dist_line = H.distance_between(x, y, xd, yd)
|
||||
if (dist_line < min_dist) then min_dist = dist_line end
|
||||
end)
|
||||
if (min_dist > 0) then
|
||||
self.data.healing_map:insert(x, y, 3000 + min_dist) -- farther away from enemy is good
|
||||
self.data.BD_healing_map:insert(x, y, 3000 + min_dist) -- farther away from enemy is good
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
--AH.put_labels(self.data.healing_map)
|
||||
--AH.put_labels(self.data.BD_healing_map)
|
||||
|
||||
-- Now on to evaluating possible moves:
|
||||
-- First, get the rating of all units in their current positions
|
||||
|
@ -341,7 +341,7 @@ function ca_bottleneck_move:evaluation(ai, cfg, self)
|
|||
local attacks = {}
|
||||
for i,e in ipairs(enemies) do
|
||||
for x,y in H.adjacent_tiles(e.x, e.y) do
|
||||
if self.data.is_my_territory:get(x,y) then
|
||||
if self.data.BD_is_my_territory:get(x,y) then
|
||||
local unit_in_way = wesnoth.get_unit(x, y)
|
||||
local data = { x = x, y = y,
|
||||
defender = e,
|
||||
|
@ -438,8 +438,8 @@ function ca_bottleneck_move:evaluation(ai, cfg, self)
|
|||
-- The following are also needed in this case
|
||||
-- We don't have to worry about unsetting them, as LU attacks
|
||||
-- always have higher priority than any other move
|
||||
self.data.lu_defender = a.defender
|
||||
self.data.lu_weapon = n_weapon
|
||||
self.data.BD_lu_defender = a.defender
|
||||
self.data.BD_lu_weapon = n_weapon
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -462,25 +462,25 @@ function ca_bottleneck_move:evaluation(ai, cfg, self)
|
|||
|
||||
-- Also need to delete the level-up attack fields
|
||||
-- They will be reset on the next turn
|
||||
self.data.lu_defender = nil
|
||||
self.data.lu_weapon = nil
|
||||
self.data.BD_lu_defender = nil
|
||||
self.data.BD_lu_weapon = nil
|
||||
end
|
||||
|
||||
-- Set the variables for the exec() function
|
||||
if max_rating == 0 then
|
||||
-- In this case we take MP away from all units
|
||||
-- This is done so that the RCA AI CAs can be kept in place
|
||||
self.data.bottleneck_moves_done = true
|
||||
self.data.BD_bottleneck_moves_done = true
|
||||
else
|
||||
self.data.bottleneck_moves_done = false
|
||||
self.data.unit = best_unit
|
||||
self.data.hex = best_hex
|
||||
self.data.BD_bottleneck_moves_done = false
|
||||
self.data.BD_unit = best_unit
|
||||
self.data.BD_hex = best_hex
|
||||
end
|
||||
return cfg.ca_score
|
||||
end
|
||||
|
||||
function ca_bottleneck_move:execution(ai, cfg, self)
|
||||
if self.data.bottleneck_moves_done then
|
||||
if self.data.BD_bottleneck_moves_done then
|
||||
local units = {}
|
||||
if MAISD.get_mai_self_data(self.data, cfg.ai_id, "side_leader_activated") then
|
||||
units = AH.get_units_with_moves { side = wesnoth.current.side }
|
||||
|
@ -491,27 +491,27 @@ function ca_bottleneck_move:execution(ai, cfg, self)
|
|||
AH.checked_stopunit_moves(ai, u)
|
||||
end
|
||||
else
|
||||
--print("Moving unit:",self.data.unit.id, self.data.unit.x, self.data.unit.y, " ->", best_hex[1], best_hex[2], " -- turn:", wesnoth.current.turn)
|
||||
--print("Moving unit:",self.data.BD_unit.id, self.data.BD_unit.x, self.data.BD_unit.y, " ->", best_hex[1], best_hex[2], " -- turn:", wesnoth.current.turn)
|
||||
|
||||
if (self.data.unit.x ~= self.data.hex[1]) or (self.data.unit.y ~= self.data.hex[2]) then -- test needed for level-up move
|
||||
AH.checked_move(ai, self.data.unit, self.data.hex[1], self.data.hex[2]) -- don't want full move, as this might be stepping out of the way
|
||||
if (self.data.BD_unit.x ~= self.data.BD_hex[1]) or (self.data.BD_unit.y ~= self.data.BD_hex[2]) then -- test needed for level-up move
|
||||
AH.checked_move(ai, self.data.BD_unit, self.data.BD_hex[1], self.data.BD_hex[2]) -- don't want full move, as this might be stepping out of the way
|
||||
end
|
||||
if (not self.data.unit) or (not self.data.unit.valid) then return end
|
||||
if (not self.data.BD_unit) or (not self.data.BD_unit.valid) then return end
|
||||
|
||||
-- If this is a move for a level-up attack, do the attack also
|
||||
if self.data.lu_defender then
|
||||
--print("Level-up attack",self.data.unit.id, self.data.lu_defender.id, self.data.lu_weapon)
|
||||
if self.data.BD_lu_defender then
|
||||
--print("Level-up attack",self.data.BD_unit.id, self.data.BD_lu_defender.id, self.data.BD_lu_weapon)
|
||||
|
||||
AH.checked_attack(ai, self.data.unit, self.data.lu_defender, self.data.lu_weapon)
|
||||
AH.checked_attack(ai, self.data.BD_unit, self.data.BD_lu_defender, self.data.BD_lu_weapon)
|
||||
end
|
||||
end
|
||||
|
||||
-- Now delete almost everything
|
||||
-- Keep: self.data.is_my_territory, [micro_ai]side_leader_activated=
|
||||
self.data.unit, self.data.hex = nil, nil
|
||||
self.data.lu_defender, self.data.lu_weapon = nil, nil
|
||||
self.data.bottleneck_moves_done = nil
|
||||
self.data.def_map, self.data.healer_map, self.data.leadership_map, self.data.healing_map = nil, nil, nil, nil
|
||||
-- Keep: self.data.BD_is_my_territory, [micro_ai]side_leader_activated=
|
||||
self.data.BD_unit, self.data.BD_hex = nil, nil
|
||||
self.data.BD_lu_defender, self.data.BD_lu_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
|
||||
end
|
||||
|
||||
return ca_bottleneck_move
|
||||
|
|
|
@ -41,11 +41,11 @@ function ca_goto:evaluation(ai, cfg, self)
|
|||
local locs = {}
|
||||
if cfg.unique_goals then
|
||||
-- First, some cleanup of previous turn data
|
||||
local str = 'goals_taken_' .. (wesnoth.current.turn - 1)
|
||||
local str = 'GO_goals_taken_' .. (wesnoth.current.turn - 1)
|
||||
self.data[str] = nil
|
||||
|
||||
-- Now on to the current turn
|
||||
local str = 'goals_taken_' .. wesnoth.current.turn
|
||||
local str = 'GO_goals_taken_' .. wesnoth.current.turn
|
||||
for _, loc in ipairs(all_locs) do
|
||||
if (not self.data[str]) or (not self.data[str]:get(loc[1], loc[2])) then
|
||||
table.insert(locs, loc)
|
||||
|
@ -76,13 +76,13 @@ function ca_goto:evaluation(ai, cfg, self)
|
|||
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.units, self.data.locs = units, locs
|
||||
self.data.GO_units, self.data.GO_locs = units, locs
|
||||
|
||||
return cfg.ca_score
|
||||
end
|
||||
|
||||
function ca_goto:execution(ai, cfg, self)
|
||||
local units, locs = self.data.units, self.data.locs -- simply for convenience
|
||||
local units, locs = self.data.GO_units, self.data.GO_locs -- simply for convenience
|
||||
|
||||
-- Need the enemy map and enemy attack map if avoid_enemies is set
|
||||
local enemy_map, enemy_attack_map
|
||||
|
@ -174,7 +174,7 @@ function ca_goto:execution(ai, cfg, self)
|
|||
|
||||
-- If 'unique_goals' is set, mark this location as being taken
|
||||
if cfg.unique_goals then
|
||||
local str = 'goals_taken_' .. wesnoth.current.turn
|
||||
local str = 'GO_goals_taken_' .. wesnoth.current.turn
|
||||
if (not self.data[str]) then self.data[str] = LS.create() end
|
||||
self.data[str]:insert(closest_hex[1], closest_hex[2])
|
||||
end
|
||||
|
@ -239,7 +239,7 @@ function ca_goto:execution(ai, cfg, self)
|
|||
end
|
||||
|
||||
-- And some cleanup
|
||||
self.data.units, self.data.locs = nil, nil
|
||||
self.data.GO_units, self.data.GO_locs = nil, nil
|
||||
end
|
||||
|
||||
return ca_goto
|
||||
|
|
|
@ -136,7 +136,7 @@ function ca_messenger_attack:evaluation(ai, cfg, self)
|
|||
local attack = messenger_find_clearing_attack(messenger, x, y)
|
||||
|
||||
if attack then
|
||||
self.data.best_attack = attack
|
||||
self.data.ME_best_attack = attack
|
||||
return cfg.ca_score
|
||||
end
|
||||
|
||||
|
@ -144,15 +144,15 @@ function ca_messenger_attack:evaluation(ai, cfg, self)
|
|||
end
|
||||
|
||||
function ca_messenger_attack:execution(ai, cfg, self)
|
||||
local attacker = wesnoth.get_unit(self.data.best_attack.src.x, self.data.best_attack.src.y)
|
||||
local defender = wesnoth.get_unit(self.data.best_attack.target.x, self.data.best_attack.target.y)
|
||||
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)
|
||||
|
||||
AH.movefull_stopunit(ai, attacker, self.data.best_attack.dst.x, self.data.best_attack.dst.y)
|
||||
AH.movefull_stopunit(ai, attacker, self.data.ME_best_attack.dst.x, self.data.ME_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.best_attack = nil
|
||||
self.data.ME_best_attack = nil
|
||||
end
|
||||
|
||||
return ca_messenger_attack
|
||||
|
|
|
@ -116,22 +116,22 @@ function ca_protect_unit_attack:evaluation(ai, cfg, self)
|
|||
--print('Max_rating:', max_rating)
|
||||
|
||||
if (max_rating > -9e99) then
|
||||
self.data.best_attack = best_attack
|
||||
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.best_attack.src.x, self.data.best_attack.src.y)
|
||||
local defender = wesnoth.get_unit(self.data.best_attack.target.x, self.data.best_attack.target.y)
|
||||
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)
|
||||
|
||||
AH.movefull_stopunit(ai, attacker, self.data.best_attack.dst.x, self.data.best_attack.dst.y)
|
||||
AH.movefull_stopunit(ai, attacker, self.data.PU_best_attack.dst.x, self.data.PU_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.best_attack = nil
|
||||
self.data.PU_best_attack = nil
|
||||
end
|
||||
|
||||
return ca_protect_unit_attack
|
||||
|
|
|
@ -9,8 +9,8 @@ function ca_protect_unit_finish:evaluation(ai, cfg, self)
|
|||
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.unit = unit
|
||||
self.data.goal = { cfg.goal_x[i], cfg.goal_y[i] }
|
||||
self.data.PU_unit = unit
|
||||
self.data.PU_goal = { cfg.goal_x[i], cfg.goal_y[i] }
|
||||
return 300000
|
||||
end
|
||||
end
|
||||
|
@ -19,9 +19,9 @@ function ca_protect_unit_finish:evaluation(ai, cfg, self)
|
|||
end
|
||||
|
||||
function ca_protect_unit_finish:execution(ai, cfg, self)
|
||||
AH.movefull_stopunit(ai, self.data.unit, self.data.goal)
|
||||
self.data.unit = nil
|
||||
self.data.goal = nil
|
||||
AH.movefull_stopunit(ai, self.data.PU_unit, self.data.PU_goal)
|
||||
self.data.PU_unit = nil
|
||||
self.data.PU_goal = nil
|
||||
end
|
||||
|
||||
return ca_protect_unit_finish
|
||||
|
|
|
@ -80,11 +80,11 @@ function ca_protect_unit_move:execution(ai, cfg, self)
|
|||
--AH.put_labels(GDM)
|
||||
|
||||
-- Configuration parameters (no option to change these enabled at the moment)
|
||||
local enemy_weight = self.data.enemy_weight or 100.
|
||||
local my_unit_weight = self.data.my_unit_weight or 1.
|
||||
local distance_weight = self.data.distance_weight or 3.
|
||||
local terrain_weight = self.data.terrain_weight or 0.1
|
||||
local bearing = self.data.bearing or 1
|
||||
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 bearing = self.data.PU_bearing or 1
|
||||
|
||||
-- If there are no enemies left, only distance to goal matters
|
||||
-- This is to avoid rare situations where moving toward goal is canceled by moving away from own units
|
||||
|
|
|
@ -51,7 +51,7 @@ function ca_simple_attack:evaluation(ai, cfg, self)
|
|||
end
|
||||
|
||||
if (max_rating > -9e99) then
|
||||
self.data.attack = best_attack
|
||||
self.data.SA_attack = best_attack
|
||||
return cfg.ca_score
|
||||
end
|
||||
|
||||
|
@ -59,15 +59,15 @@ function ca_simple_attack:evaluation(ai, cfg, self)
|
|||
end
|
||||
|
||||
function ca_simple_attack:execution(ai, cfg, self)
|
||||
local attacker = wesnoth.get_unit(self.data.attack.src.x, self.data.attack.src.y)
|
||||
local defender = wesnoth.get_unit(self.data.attack.target.x, self.data.attack.target.y)
|
||||
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)
|
||||
|
||||
AH.movefull_outofway_stopunit(ai, attacker, self.data.attack.dst.x, self.data.attack.dst.y)
|
||||
AH.movefull_outofway_stopunit(ai, attacker, self.data.SA_attack.dst.x, self.data.SA_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.attack = nil
|
||||
self.data.SA_attack = nil
|
||||
end
|
||||
|
||||
return ca_simple_attack
|
||||
return ca_simple_attack
|
||||
|
|
Loading…
Add table
Reference in a new issue