Merge branch 'master' of github.com:wesnoth/wesnoth-old

This commit is contained in:
David Mikos 2013-10-25 14:00:19 +10:30
commit 07037d9969
10 changed files with 361 additions and 408 deletions

View file

@ -1,126 +0,0 @@
return {
init = function(ai, existing_engine)
local engine = existing_engine or {}
local H = wesnoth.require "lua/helper.lua"
local AH = wesnoth.require "ai/lua/ai_helper.lua"
local LS = wesnoth.require "lua/location_set.lua"
function engine:mai_hang_out_eval(cfg)
cfg = cfg or {}
-- Return 0 if the mobilize condition has previously been met
for mobilze in H.child_range(self.data, "hangout_mobilize_units") do
if (mobilze.id == cfg.ca_id) then
return 0
end
end
-- Otherwise check if any of the mobilize conditions are now met
if (cfg.mobilize_condition and wesnoth.eval_conditional(cfg.mobilize_condition))
or (cfg.mobilize_on_gold_less_than and (wesnoth.sides[wesnoth.current.side].gold < cfg.mobilize_on_gold_less_than))
then
table.insert(self.data, { "hangout_mobilize_units" , { id = cfg.ca_id } } )
-- Need to unmark all units also
local units = wesnoth.get_units { side = wesnoth.current.side, { "and", cfg.filter } }
for i,u in ipairs(units) do
u.variables.mai_hangout_moved = nil
end
return 0
end
local units = wesnoth.get_units { side = wesnoth.current.side,
{ "and", cfg.filter }, formula = '$this_unit.moves > 0'
}
if units[1] then
return cfg.ca_score
end
return 0
end
function engine:mai_hang_out_exec(cfg)
cfg = cfg or {}
local units = wesnoth.get_units { side = wesnoth.current.side,
{ "and", cfg.filter }, formula = '$this_unit.moves > 0'
}
--print('#unit', #units)
-- 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 {
{ "filter", { side = wesnoth.current.side, canrecruit = "yes" } }
}
local width, height = wesnoth.get_map_size()
local locs = wesnoth.get_locations {
x = '1-' .. width,
y = '1-' .. height,
{ "and", filter_location }
}
--print('#locs', #locs)
-- Get map for locations to be avoided (defaults to all castle terrain)
local avoid = cfg.avoid or { terrain = 'C*,C*^*,*^C*' }
local avoid_map = LS.of_pairs(wesnoth.get_locations(avoid))
local best_hex, best_unit, max_rating = {}, {}, -9e99
for i,u in ipairs(units) do
-- Only consider units that have not been marked yet
if (not u.variables.mai_hangout_moved) then
local best_hex_unit, max_rating_unit = {}, -9e99
-- Check out all unoccupied hexes the unit can reach
local reach_map = AH.get_reachable_unocc(u)
reach_map:iter( function(x, y, v)
if (not avoid_map:get(x, y)) then
for k,l in ipairs(locs) do
-- Main rating is the distance from any of the goal hexes
local rating = -H.distance_between(x, y, l[1], l[2])
-- Fastest unit moves first
rating = rating + u.max_moves / 100.
-- Minor penalty for distance from current position of unit
-- so that there's not too much shuffling around
local rating = rating - H.distance_between(x, y, u.x, u.y) / 1000.
if (rating > max_rating_unit) then
max_rating_unit = rating
best_hex_unit = {x, y}
end
end
end
end)
-- Only consider a unit if the best hex found for it is not its current location
if (best_hex_unit[1] ~= u.x) or (best_hex_unit[2] ~= u.y) then
if (max_rating_unit > max_rating) then
max_rating = max_rating_unit
best_hex, best_unit = best_hex_unit, u
end
end
end
end
--print(best_unit.id, best_unit.x, best_unit.y, best_hex[1], best_hex[2], max_rating)
-- If no valid locations/units were found or all units are in their
-- respective best locations already, we take moves away from all units
if (max_rating == -9e99) then
for i,u in ipairs(units) do
ai.stopunit_moves(u)
-- Also remove the markers
u.variables.mai_hangout_moved = nil
end
else
-- Otherwise move unit and mark as having been used
ai.move(best_unit, best_hex[1], best_hex[2])
best_unit.variables.mai_hangout_moved = true
end
end
return engine
end
}

View file

@ -1,146 +0,0 @@
return {
init = function(ai, existing_engine)
local engine = existing_engine or {}
local H = wesnoth.require "lua/helper.lua"
local AH = wesnoth.require "ai/lua/ai_helper.lua"
function engine:mai_patrol_eval(cfg)
local patrol = wesnoth.get_units({ id = cfg.id })[1]
-- Check if unit exists as sticky BCAs are not always removed successfully
if patrol and (patrol.moves > 0) then return cfg.ca_score end
return 0
end
function engine:mai_patrol_exec(cfg)
local patrol = wesnoth.get_units( { id = cfg.id } )[1]
cfg.waypoint_x = AH.split(cfg.waypoint_x, ",")
cfg.waypoint_y = AH.split(cfg.waypoint_y, ",")
local n_wp = #cfg.waypoint_x -- just for convenience
-- Set up waypoints, taking into account whether 'reverse' is set
-- This works even the first time, when self.data.id_reverse is not set yet
local waypoints = {}
if self.data[patrol.id..'_reverse'] then
for i = 1,n_wp do
waypoints[i] = { tonumber(cfg.waypoint_x[n_wp-i+1]), tonumber(cfg.waypoint_y[n_wp-i+1]) }
end
else
for i = 1,n_wp do
waypoints[i] = { tonumber(cfg.waypoint_x[i]), tonumber(cfg.waypoint_y[i]) }
end
end
-- if not set, set next location (first move)
-- This needs to be in WML format, so that it persists over save/load cycles
if (not self.data[patrol.id..'_x']) then
self.data[patrol.id..'_x'] = waypoints[1][1]
self.data[patrol.id..'_y'] = waypoints[1][2]
self.data[patrol.id..'_reverse'] = false
end
while patrol.moves > 0 do
-- Check whether one of the enemies to be attacked is next to the patroller
-- If so, don't move, but attack that enemy
local enemies = wesnoth.get_units {
id = cfg.attack,
{ "filter_adjacent", { id = cfg.id } },
{ "filter_side", {{ "enemy_of", { side = wesnoth.current.side } }} }
}
if next(enemies) then break end
-- Also check whether we're next to any unit (enemy or ally) which is on the next waypoint
local unit_on_wp = wesnoth.get_units {
x = self.data[patrol.id..'_x'],
y = self.data[patrol.id..'_y'],
{ "filter_adjacent", { id = cfg.id } }
}[1]
for i,wp in ipairs(waypoints) do
-- If the patrol is on a waypoint or adjacent to one that is occupied by any unit
if ((patrol.x == wp[1]) and (patrol.y == wp[2]))
or (unit_on_wp and ((unit_on_wp.x == wp[1]) and (unit_on_wp.y == wp[2])))
then
if (i == n_wp) then
-- Move him to the first one (or reverse route), if he's on the last waypoint
-- Unless cfg.one_time_only is set
if cfg.one_time_only then
self.data[patrol.id..'_x'] = waypoints[n_wp][1]
self.data[patrol.id..'_y'] = waypoints[n_wp][2]
else
-- Go back to first WP or reverse direction
if cfg.out_and_back then
self.data[patrol.id..'_x'] = waypoints[n_wp-1][1]
self.data[patrol.id..'_y'] = waypoints[n_wp-1][2]
-- We also need to reverse the waypoints right here, as this might not be the end of the move
self.data[patrol.id..'_reverse'] = not self.data[patrol.id..'_reverse']
local tmp_wp = {}
for i,wp in ipairs(waypoints) do tmp_wp[n_wp-i+1] = wp end
waypoints = tmp_wp
else
self.data[patrol.id..'_x'] = waypoints[1][1]
self.data[patrol.id..'_y'] = waypoints[1][2]
end
end
else
-- ... else move him on the next waypoint
self.data[patrol.id..'_x'] = waypoints[i+1][1]
self.data[patrol.id..'_y'] = waypoints[i+1][2]
end
end
end
-- If we're on the last waypoint on one_time_only is set, stop here
if cfg.one_time_only and
(patrol.x == waypoints[n_wp][1]) and (patrol.y == waypoints[n_wp][2])
then
ai.stopunit_moves(patrol)
else -- otherwise move toward next WP
local x, y = wesnoth.find_vacant_tile(self.data[patrol.id..'_x'], self.data[patrol.id..'_y'], patrol)
local nh = AH.next_hop(patrol, x, y)
if nh and ((nh[1] ~= patrol.x) or (nh[2] ~= patrol.y)) then
ai.move(patrol, nh[1], nh[2])
else
ai.stopunit_moves(patrol)
end
end
end
-- Attack unit on the last waypoint under all circumstances if cfg.one_time_only is set
local enemies = {}
if cfg.one_time_only then
enemies = wesnoth.get_units{
x = waypoints[n_wp][1],
y = waypoints[n_wp][2],
{ "filter_adjacent", { id = cfg.id } },
{ "filter_side", {{ "enemy_of", { side = wesnoth.current.side } }} }
}
end
-- Otherwise attack adjacent enemy (if specified)
if (not next(enemies)) then
enemies = wesnoth.get_units{
id = cfg.attack,
{ "filter_adjacent", { id = cfg.id } },
{ "filter_side", {{ "enemy_of", { side = wesnoth.current.side } }} }
}
end
if next(enemies) then
for i,v in ipairs(enemies) do
ai.attack(patrol, v)
break
end
end
-- Check that patrol is not killed
if patrol and patrol.valid then ai.stopunit_all(patrol) end
end
return engine
end
}

View file

@ -1,91 +0,0 @@
return {
init = function(ai, existing_engine)
local engine = existing_engine or {}
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"
function engine:mai_simple_attack_eval(cfg)
-- Find all units that can attack and match the SUF
local units = wesnoth.get_units {
side = wesnoth.current.side,
formula = '$this_unit.attacks_left > 0',
{ "and", cfg.filter }
}
-- Eliminate units without attacks
for i = #units,1,-1 do
if (not H.get_child(units[i].__cfg, 'attack')) then
table.remove(units, i)
end
end
--print('#units', #units)
if (not units[1]) then return 0 end
-- Get all possible attacks
local attacks = AH.get_attacks(units, { include_occupied = true })
--print('#attacks', #attacks)
if (not attacks[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_map
if cfg.filter_second then
local enemies = wesnoth.get_units {
{ "filter_side", {{ "enemy_of", { side = wesnoth.current.side } }} },
{ "and", cfg.filter_second }
}
--print('#enemies', #enemies)
if (not enemies[1]) then return 0 end
enemy_map = LS.create()
for i,e in ipairs(enemies) do enemy_map:insert(e.x, e.y) end
end
-- Now find the best of the possible attacks
local max_rating, best_attack = -9e99, {}
for i, 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
valid_target = false
end
if valid_target then
local attacker = wesnoth.get_unit(att.src.x, att.src.y)
local enemy = wesnoth.get_unit(att.target.x, att.target.y)
local dst = { att.dst.x, att.dst.y }
local rating = BC.attack_rating(attacker, enemy, dst)
--print('rating:', rating, attacker.id, enemy.id)
if (rating > max_rating) then
max_rating = rating
best_attack = att
end
end
end
if (max_rating > -9e99) then
self.data.attack = best_attack
return cfg.ca_score
end
return 0
end
function engine:mai_simple_attack_exec()
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)
AH.movefull_outofway_stopunit(ai, attacker, self.data.attack.dst.x, self.data.attack.dst.y)
ai.attack(attacker, defender)
self.data.attack = nil
end
return engine
end
}

View file

@ -431,7 +431,7 @@ function wesnoth.wml_actions.micro_ai(cfg)
if (not cfg.id) then
H.wml_error("[micro_ai] tag (patrol_unit) is missing required parameter: id")
end
CA_parms = { { ca_id = "mai_patrol", score = cfg.ca_score or 300000, sticky = true } }
CA_parms = { { ca_id = "mai_patrol", location = 'ai/micro_ais/cas/ca_patrol.lua', score = cfg.ca_score or 300000 } }
--------- Recruiting Micro AI - side-wide AI ------------------------------------
elseif (cfg.ai_type == 'recruiting') then
@ -496,12 +496,12 @@ function wesnoth.wml_actions.micro_ai(cfg)
--------- Hang Out Micro AI - side-wide AI ------------------------------------
elseif (cfg.ai_type == 'hang_out') then
optional_keys = { "filter", "filter_location", "avoid", "mobilize_condition", "mobilize_on_gold_less_than" }
CA_parms = { { ca_id = 'mai_hang_out', score = cfg.ca_score or 170000 } }
CA_parms = { { ca_id = 'mai_hang_out', location = 'ai/micro_ais/cas/ca_hang_out.lua', score = cfg.ca_score or 170000 } }
--------- Simple Attack Micro AI - side-wide AI ---------------------------
elseif (cfg.ai_type == 'simple_attack') then
optional_keys = { "filter", "filter_second" }
CA_parms = { { ca_id = 'mai_simple_attack', score = cfg.ca_score or 110000 } }
CA_parms = { { ca_id = 'mai_simple_attack', location = 'ai/micro_ais/cas/ca_simple_attack.lua', score = cfg.ca_score or 110000 } }
-- If we got here, none of the valid ai_types was specified
else

View file

@ -0,0 +1,121 @@
local H = wesnoth.require "lua/helper.lua"
local AH = wesnoth.require "ai/lua/ai_helper.lua"
local LS = wesnoth.require "lua/location_set.lua"
local ca_hang_out = {}
function ca_hang_out:evaluation(ai, cfg, self)
cfg = cfg or {}
-- Return 0 if the mobilize condition has previously been met
for mobilze in H.child_range(self.data, "hangout_mobilize_units") do
if (mobilze.id == cfg.ca_id) then
return 0
end
end
-- Otherwise check if any of the mobilize conditions are now met
if (cfg.mobilize_condition and wesnoth.eval_conditional(cfg.mobilize_condition))
or (cfg.mobilize_on_gold_less_than and (wesnoth.sides[wesnoth.current.side].gold < cfg.mobilize_on_gold_less_than))
then
table.insert(self.data, { "hangout_mobilize_units" , { id = cfg.ca_id } } )
-- Need to unmark all units also
local units = wesnoth.get_units { side = wesnoth.current.side, { "and", cfg.filter } }
for i,u in ipairs(units) do
u.variables.mai_hangout_moved = nil
end
return 0
end
local units = wesnoth.get_units { side = wesnoth.current.side,
{ "and", cfg.filter }, formula = '$this_unit.moves > 0'
}
if units[1] then
return cfg.ca_score
end
return 0
end
function ca_hang_out:execution(ai, cfg, self)
cfg = cfg or {}
local units = wesnoth.get_units { side = wesnoth.current.side,
{ "and", cfg.filter }, formula = '$this_unit.moves > 0'
}
--print('#unit', #units)
-- 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 {
{ "filter", { side = wesnoth.current.side, canrecruit = "yes" } }
}
local width, height = wesnoth.get_map_size()
local locs = wesnoth.get_locations {
x = '1-' .. width,
y = '1-' .. height,
{ "and", filter_location }
}
--print('#locs', #locs)
-- Get map for locations to be avoided (defaults to all castle terrain)
local avoid = cfg.avoid or { terrain = 'C*,C*^*,*^C*' }
local avoid_map = LS.of_pairs(wesnoth.get_locations(avoid))
local best_hex, best_unit, max_rating = {}, {}, -9e99
for i,u in ipairs(units) do
-- Only consider units that have not been marked yet
if (not u.variables.mai_hangout_moved) then
local best_hex_unit, max_rating_unit = {}, -9e99
-- Check out all unoccupied hexes the unit can reach
local reach_map = AH.get_reachable_unocc(u)
reach_map:iter( function(x, y, v)
if (not avoid_map:get(x, y)) then
for k,l in ipairs(locs) do
-- Main rating is the distance from any of the goal hexes
local rating = -H.distance_between(x, y, l[1], l[2])
-- Fastest unit moves first
rating = rating + u.max_moves / 100.
-- Minor penalty for distance from current position of unit
-- so that there's not too much shuffling around
local rating = rating - H.distance_between(x, y, u.x, u.y) / 1000.
if (rating > max_rating_unit) then
max_rating_unit = rating
best_hex_unit = {x, y}
end
end
end
end)
-- Only consider a unit if the best hex found for it is not its current location
if (best_hex_unit[1] ~= u.x) or (best_hex_unit[2] ~= u.y) then
if (max_rating_unit > max_rating) then
max_rating = max_rating_unit
best_hex, best_unit = best_hex_unit, u
end
end
end
end
--print(best_unit.id, best_unit.x, best_unit.y, best_hex[1], best_hex[2], max_rating)
-- If no valid locations/units were found or all units are in their
-- respective best locations already, we take moves away from all units
if (max_rating == -9e99) then
for i,u in ipairs(units) do
ai.stopunit_moves(u)
-- Also remove the markers
u.variables.mai_hangout_moved = nil
end
else
-- Otherwise move unit and mark as having been used
ai.move(best_unit, best_hex[1], best_hex[2])
best_unit.variables.mai_hangout_moved = true
end
end
return ca_hang_out

View file

@ -0,0 +1,141 @@
local H = wesnoth.require "lua/helper.lua"
local AH = wesnoth.require "ai/lua/ai_helper.lua"
local ca_patrol = {}
function ca_patrol:evaluation(ai, cfg)
local patrol = wesnoth.get_units({ id = cfg.id })[1]
-- Check if unit exists as sticky BCAs are not always removed successfully
if patrol and (patrol.moves > 0) then return cfg.ca_score end
return 0
end
function ca_patrol:execution(ai, cfg, self)
local patrol = wesnoth.get_units( { id = cfg.id } )[1]
cfg.waypoint_x = AH.split(cfg.waypoint_x, ",")
cfg.waypoint_y = AH.split(cfg.waypoint_y, ",")
local n_wp = #cfg.waypoint_x -- just for convenience
-- Set up waypoints, taking into account whether 'reverse' is set
-- This works even the first time, when self.data.id_reverse is not set yet
local waypoints = {}
if self.data[patrol.id..'_reverse'] then
for i = 1,n_wp do
waypoints[i] = { tonumber(cfg.waypoint_x[n_wp-i+1]), tonumber(cfg.waypoint_y[n_wp-i+1]) }
end
else
for i = 1,n_wp do
waypoints[i] = { tonumber(cfg.waypoint_x[i]), tonumber(cfg.waypoint_y[i]) }
end
end
-- if not set, set next location (first move)
-- This needs to be in WML format, so that it persists over save/load cycles
if (not self.data[patrol.id..'_x']) then
self.data[patrol.id..'_x'] = waypoints[1][1]
self.data[patrol.id..'_y'] = waypoints[1][2]
self.data[patrol.id..'_reverse'] = false
end
while patrol.moves > 0 do
-- Check whether one of the enemies to be attacked is next to the patroller
-- If so, don't move, but attack that enemy
local enemies = wesnoth.get_units {
id = cfg.attack,
{ "filter_adjacent", { id = cfg.id } },
{ "filter_side", {{ "enemy_of", { side = wesnoth.current.side } }} }
}
if next(enemies) then break end
-- Also check whether we're next to any unit (enemy or ally) which is on the next waypoint
local unit_on_wp = wesnoth.get_units {
x = self.data[patrol.id..'_x'],
y = self.data[patrol.id..'_y'],
{ "filter_adjacent", { id = cfg.id } }
}[1]
for i,wp in ipairs(waypoints) do
-- If the patrol is on a waypoint or adjacent to one that is occupied by any unit
if ((patrol.x == wp[1]) and (patrol.y == wp[2]))
or (unit_on_wp and ((unit_on_wp.x == wp[1]) and (unit_on_wp.y == wp[2])))
then
if (i == n_wp) then
-- Move him to the first one (or reverse route), if he's on the last waypoint
-- Unless cfg.one_time_only is set
if cfg.one_time_only then
self.data[patrol.id..'_x'] = waypoints[n_wp][1]
self.data[patrol.id..'_y'] = waypoints[n_wp][2]
else
-- Go back to first WP or reverse direction
if cfg.out_and_back then
self.data[patrol.id..'_x'] = waypoints[n_wp-1][1]
self.data[patrol.id..'_y'] = waypoints[n_wp-1][2]
-- We also need to reverse the waypoints right here, as this might not be the end of the move
self.data[patrol.id..'_reverse'] = not self.data[patrol.id..'_reverse']
local tmp_wp = {}
for i,wp in ipairs(waypoints) do tmp_wp[n_wp-i+1] = wp end
waypoints = tmp_wp
else
self.data[patrol.id..'_x'] = waypoints[1][1]
self.data[patrol.id..'_y'] = waypoints[1][2]
end
end
else
-- ... else move him on the next waypoint
self.data[patrol.id..'_x'] = waypoints[i+1][1]
self.data[patrol.id..'_y'] = waypoints[i+1][2]
end
end
end
-- If we're on the last waypoint on one_time_only is set, stop here
if cfg.one_time_only and
(patrol.x == waypoints[n_wp][1]) and (patrol.y == waypoints[n_wp][2])
then
ai.stopunit_moves(patrol)
else -- otherwise move toward next WP
local x, y = wesnoth.find_vacant_tile(self.data[patrol.id..'_x'], self.data[patrol.id..'_y'], patrol)
local nh = AH.next_hop(patrol, x, y)
if nh and ((nh[1] ~= patrol.x) or (nh[2] ~= patrol.y)) then
ai.move(patrol, nh[1], nh[2])
else
ai.stopunit_moves(patrol)
end
end
end
-- Attack unit on the last waypoint under all circumstances if cfg.one_time_only is set
local enemies = {}
if cfg.one_time_only then
enemies = wesnoth.get_units{
x = waypoints[n_wp][1],
y = waypoints[n_wp][2],
{ "filter_adjacent", { id = cfg.id } },
{ "filter_side", {{ "enemy_of", { side = wesnoth.current.side } }} }
}
end
-- Otherwise attack adjacent enemy (if specified)
if (not next(enemies)) then
enemies = wesnoth.get_units{
id = cfg.attack,
{ "filter_adjacent", { id = cfg.id } },
{ "filter_side", {{ "enemy_of", { side = wesnoth.current.side } }} }
}
end
if next(enemies) then
for i,v in ipairs(enemies) do
ai.attack(patrol, v)
break
end
end
-- Check that patrol is not killed
if patrol and patrol.valid then ai.stopunit_all(patrol) end
end
return ca_patrol

View file

@ -0,0 +1,86 @@
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 = {}
function ca_simple_attack:evaluation(ai, cfg, self)
-- Find all units that can attack and match the SUF
local units = wesnoth.get_units {
side = wesnoth.current.side,
formula = '$this_unit.attacks_left > 0',
{ "and", cfg.filter }
}
-- Eliminate units without attacks
for i = #units,1,-1 do
if (not H.get_child(units[i].__cfg, 'attack')) then
table.remove(units, i)
end
end
--print('#units', #units)
if (not units[1]) then return 0 end
-- Get all possible attacks
local attacks = AH.get_attacks(units, { include_occupied = true })
--print('#attacks', #attacks)
if (not attacks[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_map
if cfg.filter_second then
local enemies = wesnoth.get_units {
{ "filter_side", {{ "enemy_of", { side = wesnoth.current.side } }} },
{ "and", cfg.filter_second }
}
--print('#enemies', #enemies)
if (not enemies[1]) then return 0 end
enemy_map = LS.create()
for i,e in ipairs(enemies) do enemy_map:insert(e.x, e.y) end
end
-- Now find the best of the possible attacks
local max_rating, best_attack = -9e99, {}
for i, 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
valid_target = false
end
if valid_target then
local attacker = wesnoth.get_unit(att.src.x, att.src.y)
local enemy = wesnoth.get_unit(att.target.x, att.target.y)
local dst = { att.dst.x, att.dst.y }
local rating = BC.attack_rating(attacker, enemy, dst)
--print('rating:', rating, attacker.id, enemy.id)
if (rating > max_rating) then
max_rating = rating
best_attack = att
end
end
end
if (max_rating > -9e99) then
self.data.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.attack.src.x, self.data.attack.src.y)
local defender = wesnoth.get_unit(self.data.attack.target.x, self.data.attack.target.y)
AH.movefull_outofway_stopunit(ai, attacker, self.data.attack.dst.x, self.data.attack.dst.y)
ai.attack(attacker, defender)
self.data.attack = nil
end
return ca_simple_attack

View file

@ -24,21 +24,6 @@
recruit=Footpad
gold=200
[ai]
version=10710
[engine]
name="lua"
code= <<
local ai = ...
local engine = {}
engine = wesnoth.require("ai/micro_ais/ais/mai_hang_out_engine.lua").init(ai, engine)
engine = wesnoth.require("ai/micro_ais/ais/mai_messenger_escort_engine.lua").init(ai, engine)
return engine
>>
[/engine]
{RCA_STAGE}
[/ai]
[/side]
[side]

View file

@ -41,21 +41,6 @@
gold=0
income=-2
[ai]
version=10710
[engine]
name="lua"
code= <<
local ai = ...
local engine = {}
engine = wesnoth.require("ai/micro_ais/ais/mai_patrol_engine.lua").init(ai, engine)
engine = wesnoth.require("ai/micro_ais/ais/mai_zone_guardian_engine.lua").init(ai, engine)
return engine
>>
[/engine]
{RCA_STAGE}
[/ai]
[/side]
# Urudin's side
@ -176,17 +161,17 @@
x,y=25,27
[/unit]
[micro_ai]
side=2
ai_type=zone_guardian
action=add
#[micro_ai]
# side=2
# ai_type=zone_guardian
# action=add
id=guard1
ca_score=299997
[filter_location]
x,y=10-26,26-28
[/filter_location]
[/micro_ai]
# id=guard1
# ca_score=299997
# [filter_location]
# x,y=10-26,26-28
# [/filter_location]
#[/micro_ai]
{PLACE_IMAGE "scenery/signpost.png" 11 4}
{SET_LABEL 11 4 _"End Scenario"}

View file

@ -36,8 +36,6 @@
canrecruit=yes
gold=10000
{MICRO_AI_SIMPLE_ATTACK}
[/side]
[side] # This side is only here because we need one persistent side for the game to go on