mirror of
https://github.com/wesnoth/wesnoth
synced 2025-05-17 23:56:04 +00:00
Experimental AI: correctly deal with hidden and petrified units
This commit is contained in:
parent
339b4f3ee1
commit
f2406ac829
@ -14,6 +14,9 @@ return {
|
||||
-- (default always returns false)
|
||||
-- leader_takes_village: function that returns true if and only if the leader is going to move to capture a village this turn
|
||||
-- (default always returns true)
|
||||
-- Note: the recruiting code assumes full knowledge of units on the map and the recruit lists of other sides for the purpose of
|
||||
-- finding the best unit types to recruit. It does not work otherwise. It assumes normal vision of the AI side (that is, it disregards
|
||||
-- hidden enemy units) for determining from which keep hex the leader should recruit and on which castle hexes to recruit new units
|
||||
init = function(ai_cas, params)
|
||||
if not params then
|
||||
params = {}
|
||||
@ -354,7 +357,7 @@ return {
|
||||
local no_space = true
|
||||
for i,c in ipairs(data.castle.locs) do
|
||||
local unit = wesnoth.get_unit(c[1], c[2])
|
||||
if (not unit) then
|
||||
if (not AH.is_visible_unit(wesnoth.current.side, unit)) then
|
||||
no_space = false
|
||||
break
|
||||
end
|
||||
@ -612,19 +615,19 @@ return {
|
||||
-- and also the closest enemy
|
||||
local max_rating = -1
|
||||
|
||||
local enemy_leaders = AH.get_live_units { canrecruit = 'yes',
|
||||
{ "filter_side", { { "enemy_of", {side = wesnoth.current.side} } } }
|
||||
}
|
||||
local enemy_leaders = AH.get_attackable_enemies { canrecruit = 'yes' }
|
||||
local closest_enemy_distance, closest_enemy_location = AH.get_closest_enemy()
|
||||
|
||||
for i,c in ipairs(data.castle.locs) do
|
||||
local rating = 0
|
||||
local unit = wesnoth.get_unit(c[1], c[2])
|
||||
if (not unit) then
|
||||
if (not AH.is_visible_unit(wesnoth.current.side, unit)) then
|
||||
for j,e in ipairs(enemy_leaders) do
|
||||
rating = rating + 1 / H.distance_between(c[1], c[2], e.x, e.y) ^ 2.
|
||||
end
|
||||
rating = rating + 1 / H.distance_between(c[1], c[2], closest_enemy_location.x, closest_enemy_location.y) ^ 2.
|
||||
if closest_enemy_location then
|
||||
rating = rating + 1 / H.distance_between(c[1], c[2], closest_enemy_location.x, closest_enemy_location.y) ^ 2.
|
||||
end
|
||||
if (rating > max_rating) then
|
||||
max_rating, best_hex = rating, { c[1], c[2] }
|
||||
end
|
||||
@ -650,9 +653,9 @@ return {
|
||||
local target_hex = recruit_data.recruit.target_hex
|
||||
local distance_to_enemy, enemy_location
|
||||
if target_hex[1] then
|
||||
distance_to_enemy, enemy_location = AH.get_closest_enemy(target_hex)
|
||||
distance_to_enemy, enemy_location = AH.get_closest_enemy(target_hex, wesnoth.current.side, { viewing_side = 0 })
|
||||
else
|
||||
distance_to_enemy, enemy_location = AH.get_closest_enemy(best_hex)
|
||||
distance_to_enemy, enemy_location = AH.get_closest_enemy(best_hex, wesnoth.current.side, { viewing_side = 0 })
|
||||
end
|
||||
|
||||
local gold_limit = 9e99
|
||||
|
@ -67,6 +67,9 @@ return {
|
||||
|
||||
-------- Castle Switch CA --------------
|
||||
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
|
||||
-- the enemy leaders are likely to be while the AI does not know how to do that.
|
||||
local potential_enemy_leaders = AH.get_live_units { canrecruit = 'yes',
|
||||
{ "filter_side", { { "enemy_of", {side = wesnoth.current.side} } } }
|
||||
}
|
||||
@ -228,7 +231,7 @@ return {
|
||||
local should_wait = false
|
||||
for i,loc in ipairs(castle) do
|
||||
local unit = wesnoth.get_unit(loc[1], loc[2])
|
||||
if not unit then
|
||||
if (not AH.is_visible_unit(wesnoth.current.side, unit)) then
|
||||
should_wait = false
|
||||
break
|
||||
elseif unit.moves > 0 then
|
||||
@ -273,9 +276,7 @@ return {
|
||||
return 0
|
||||
end
|
||||
|
||||
local enemies = AH.get_live_units {
|
||||
{ "filter_side", {{"enemy_of", {side = wesnoth.current.side} }} }
|
||||
}
|
||||
local enemies = AH.get_attackable_enemies()
|
||||
|
||||
local villages = wesnoth.get_villages()
|
||||
-- Just in case:
|
||||
@ -331,7 +332,7 @@ return {
|
||||
for i,u in ipairs(units) do
|
||||
-- Skip villages that have units other than 'u' itself on them
|
||||
local village_occupied = false
|
||||
if unit_in_way and ((unit_in_way.x ~= u.x) or (unit_in_way.y ~= u.y)) then
|
||||
if AH.is_visible_unit(wesnoth.current.side, unit_in_way) and ((unit_in_way ~= u)) then
|
||||
village_occupied = true
|
||||
end
|
||||
|
||||
@ -486,21 +487,13 @@ return {
|
||||
|
||||
function generic_rush:spread_poison_exec()
|
||||
local attacker = wesnoth.get_unit(self.data.attack.src.x, self.data.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 print_time(' Executing spread_poison CA') end
|
||||
if AH.show_messages() then W.message { speaker = attacker.id, message = 'Poison attack' } end
|
||||
|
||||
local defender = wesnoth.get_unit(self.data.attack.target.x, self.data.attack.target.y)
|
||||
|
||||
AH.movefull_stopunit(ai, attacker, self.data.attack.dst.x, self.data.attack.dst.y)
|
||||
if (not attacker) or (not attacker.valid) then return end
|
||||
if (not defender) or (not defender.valid) then return end
|
||||
|
||||
-- Find the poison weapon
|
||||
-- If several attacks have poison, this will always find the last one
|
||||
local is_poisoner, poison_weapon = AH.has_weapon_special(attacker, "poison")
|
||||
|
||||
AH.checked_attack(ai, attacker, defender, poison_weapon)
|
||||
AH.robust_move_and_attack(ai, attacker, self.data.attack.dst, self.data.attack.target, { weapon = poison_weapon })
|
||||
|
||||
self.data.attack = nil
|
||||
end
|
||||
@ -544,7 +537,7 @@ return {
|
||||
end
|
||||
|
||||
function generic_rush:retreat_injured_units_exec()
|
||||
AH.movefull_outofway_stopunit(ai, self.data.retreat_unit, self.data.retreat_loc)
|
||||
AH.robust_move_and_attack(ai, self.data.retreat_unit, self.data.retreat_loc)
|
||||
self.data.retreat_unit = nil
|
||||
self.data.retreat_loc = nil
|
||||
end
|
||||
|
@ -109,9 +109,7 @@ end
|
||||
|
||||
function retreat_functions.get_retreat_injured_units(healees, regenerates)
|
||||
-- Only retreat to safe locations
|
||||
local enemies = AH.get_live_units {
|
||||
{ "filter_side", {{"enemy_of", {side = wesnoth.current.side} }} }
|
||||
}
|
||||
local enemies = AH.get_attackable_enemies()
|
||||
local enemy_attack_map = BC.get_attack_map(enemies)
|
||||
|
||||
local healing_locs = retreat_functions.get_healing_locations()
|
||||
@ -151,7 +149,9 @@ function retreat_functions.get_retreat_injured_units(healees, regenerates)
|
||||
|
||||
for j,loc in ipairs(possible_locations) do
|
||||
local unit_in_way = wesnoth.get_unit(loc[1], loc[2])
|
||||
if (not unit_in_way) or ((unit_in_way.moves > 0) and (unit_in_way.side == wesnoth.current.side)) then
|
||||
if (not AH.is_visible_unit(wesnoth.current.side, unit_in_way))
|
||||
or ((unit_in_way.moves > 0) and (unit_in_way.side == wesnoth.current.side))
|
||||
then
|
||||
local rating = base_rating
|
||||
local heal_score = 0
|
||||
if regenerates then
|
||||
|
Loading…
x
Reference in New Issue
Block a user