Lua AIs: distinguish between healing locations and villages
There are rating contributions for hexes which heal (not all of which are villages) and others for hexes that provide income (villages). Previously only villages were considered for both types of hexes.
This commit is contained in:
parent
8bca955ad5
commit
1856377d35
4 changed files with 34 additions and 27 deletions
|
@ -809,10 +809,10 @@ function battle_calcs.attack_rating(attacker, defender, dst, cfg, cache)
|
|||
damage = damage + 6 * (att_stats.slowed - att_stats.hp_chance[0])
|
||||
end
|
||||
|
||||
-- If attack is from a village (or other healing location), count that as slightly more than the healing amount
|
||||
-- If attack is from a healing location, count that as slightly more than the healing amount
|
||||
damage = damage - 1.25 * wesnoth.get_terrain_info(wesnoth.get_terrain(dst[1], dst[2])).healing
|
||||
|
||||
-- Equivalently, if attack is adjacent to an unoccupied village, that's bad
|
||||
-- Equivalently, if attack is adjacent to an unoccupied healing location, that's bad
|
||||
for xa,ya in H.adjacent_tiles(dst[1], dst[2]) do
|
||||
local healing = wesnoth.get_terrain_info(wesnoth.get_terrain(xa, ya)).healing
|
||||
if (healing > 0) and (not wesnoth.get_unit(xa, ya)) then
|
||||
|
@ -863,7 +863,7 @@ function battle_calcs.attack_rating(attacker, defender, dst, cfg, cache)
|
|||
damage = damage + 6 * (def_stats.slowed - def_stats.hp_chance[0])
|
||||
end
|
||||
|
||||
-- If defender is on a village (or other healing location), count that as slightly more than the healing amount
|
||||
-- If defender is on a healing location, count that as slightly more than the healing amount
|
||||
damage = damage - 1.25 * wesnoth.get_terrain_info(wesnoth.get_terrain(defender.x, defender.y)).healing
|
||||
|
||||
if (damage < 0) then damage = 0. end
|
||||
|
@ -905,9 +905,8 @@ function battle_calcs.attack_rating(attacker, defender, dst, cfg, cache)
|
|||
|
||||
-- If defender is on a village, add a bonus rating (we want to get rid of those preferentially)
|
||||
-- So yes, this is positive, even though it's a plus for the defender
|
||||
-- Defenders on villages also got a negative damage rating above (these don't exactly cancel each other though)
|
||||
local is_village = wesnoth.get_terrain_info(wesnoth.get_terrain(defender.x, defender.y)).village
|
||||
if is_village then
|
||||
-- Note: defenders on healing locations also got a negative damage rating above (these don't exactly cancel each other though)
|
||||
if wesnoth.get_terrain_info(wesnoth.get_terrain(defender.x, defender.y)).village then
|
||||
defender_value = defender_value * (1. + 10. / attacker.max_hitpoints)
|
||||
end
|
||||
|
||||
|
|
|
@ -42,14 +42,14 @@ function ca_spread_poison:evaluation(cfg, data)
|
|||
-- Don't try to poison a unit that cannot be poisoned
|
||||
local cant_poison = defender.status.poisoned or defender.status.unpoisonable
|
||||
|
||||
-- For now, we also simply don't poison units on villages (unless standard combat CA does it)
|
||||
-- For now, we also simply don't poison units on healing locations (unless standard combat CA does it)
|
||||
local defender_terrain = wesnoth.get_terrain(defender.x, defender.y)
|
||||
local on_village = wesnoth.get_terrain_info(defender_terrain).village
|
||||
local healing = wesnoth.get_terrain_info(defender_terrain).healing
|
||||
|
||||
-- Also, poisoning units that would level up through the attack or could level on their turn as a result is very bad
|
||||
local about_to_level = defender.max_experience - defender.experience <= (attacker.level * 2 * wesnoth.game_config.combat_experience)
|
||||
|
||||
if (not cant_poison) and (not on_village) and (not about_to_level) then
|
||||
if (not cant_poison) and (healing == 0) and (not about_to_level) then
|
||||
-- Strongest enemy gets poisoned first
|
||||
local rating = defender.hitpoints
|
||||
|
||||
|
|
|
@ -49,13 +49,17 @@ function ca_fast_attack_utils.gamedata_setup()
|
|||
local village_map = {}
|
||||
for _,village in ipairs(wesnoth.get_villages()) do
|
||||
if (not village_map[village[1]]) then village_map[village[1]] = {} end
|
||||
village_map[village[1]][village[2]] = {
|
||||
owner = wesnoth.get_village_owner(village[1], village[2]),
|
||||
healing = wesnoth.get_terrain_info(wesnoth.get_terrain(village[1], village[2])).healing
|
||||
}
|
||||
village_map[village[1]][village[2]] = true
|
||||
end
|
||||
gamedata.village_map = village_map
|
||||
|
||||
local healing_map = {}
|
||||
for _,loc in ipairs(AH.get_healing_locations {}) do
|
||||
if (not healing_map[loc[1]]) then healing_map[loc[1]] = {} end
|
||||
healing_map[loc[1]][loc[2]] = wesnoth.get_terrain_info(wesnoth.get_terrain(loc[1], loc[2])).healing
|
||||
end
|
||||
gamedata.healing_map = healing_map
|
||||
|
||||
-- Only uses one leader per side right now, but only used for finding direction
|
||||
-- of move -> sufficient for this.
|
||||
gamedata.leaders = {}
|
||||
|
@ -181,7 +185,7 @@ function ca_fast_attack_utils.is_acceptable_attack(damage_taken, damage_done, ag
|
|||
return (damage_done / damage_taken) >= (1 - aggression)
|
||||
end
|
||||
|
||||
function ca_fast_attack_utils.damage_rating_unit(attacker_info, defender_info, att_stat, def_stat, healing, cfg)
|
||||
function ca_fast_attack_utils.damage_rating_unit(attacker_info, defender_info, att_stat, def_stat, is_village, healing, cfg)
|
||||
-- Calculate the rating for the damage received by a single attacker on a defender.
|
||||
-- The attack att_stat both for the attacker and the defender need to be precalculated for this.
|
||||
-- Unit information is passed in unit_infos format, rather than as unit proxy tables for speed reasons.
|
||||
|
@ -191,8 +195,10 @@ function ca_fast_attack_utils.damage_rating_unit(attacker_info, defender_info, a
|
|||
-- Input parameters:
|
||||
-- @attacker_info, @defender_info: unit_info tables produced by ca_fast_attack_utils.get_unit_info()
|
||||
-- @att_stat, @def_stat: attack statistics for the two units
|
||||
-- @healing: the healing given by a village
|
||||
-- @is_village: whether the hex from which the attacker attacks is a village
|
||||
-- Set to nil or false if not, to anything if it is a village (does not have to be a boolean)
|
||||
-- @healing: the amount of healing given by the hex from which the attacker attacks
|
||||
-- Set to nil or false if there is no healing
|
||||
--
|
||||
-- Optional parameters:
|
||||
-- @cfg: the optional weights listed right below (currently only leader_weight)
|
||||
|
@ -210,7 +216,7 @@ function ca_fast_attack_utils.damage_rating_unit(attacker_info, defender_info, a
|
|||
damage = damage + 4 * (att_stat.slowed - att_stat.hp_chance[0])
|
||||
end
|
||||
|
||||
-- If attack is from a village, count its healing_value
|
||||
-- If attack is from a healing location, count its healing_value
|
||||
if healing then
|
||||
damage = damage - healing
|
||||
-- Otherwise only: if attacker can regenerate, add the regeneration bonus
|
||||
|
@ -290,22 +296,24 @@ function ca_fast_attack_utils.attack_rating(attacker_infos, defender_info, dsts,
|
|||
|
||||
local attacker_rating = 0
|
||||
for i,attacker_info in ipairs(attacker_infos) do
|
||||
local attacker_healing = gamedata.village_map[dsts[i][1]]
|
||||
local attacker_on_village = gamedata.village_map[dsts[i][1]]
|
||||
and gamedata.village_map[dsts[i][1]][dsts[i][2]]
|
||||
and gamedata.village_map[dsts[i][1]][dsts[i][2]].healing
|
||||
local attacker_healing = gamedata.healing_map[dsts[i][1]]
|
||||
and gamedata.healing_map[dsts[i][1]][dsts[i][2]]
|
||||
attacker_rating = attacker_rating + ca_fast_attack_utils.damage_rating_unit(
|
||||
attacker_info, defender_info, att_stats[i], def_stat, attacker_healing, cfg
|
||||
attacker_info, defender_info, att_stats[i], def_stat, attacker_on_village, attacker_healing, cfg
|
||||
)
|
||||
end
|
||||
|
||||
-- attacker_info is passed only to figure out whether the attacker might level up
|
||||
-- TODO: This is only works for the first attacker in a combo at the moment
|
||||
local defender_x, defender_y = defender_info.x, defender_info.y
|
||||
local defender_healing = gamedata.village_map[defender_x]
|
||||
local defender_on_village = gamedata.village_map[defender_x]
|
||||
and gamedata.village_map[defender_x][defender_y]
|
||||
and gamedata.village_map[defender_x][defender_y].healing
|
||||
local defender_healing = gamedata.healing_map[defender_x]
|
||||
and gamedata.healing_map[defender_x][defender_y]
|
||||
local defender_rating = ca_fast_attack_utils.damage_rating_unit(
|
||||
defender_info, attacker_infos[1], def_stat, att_stats[1], defender_healing, cfg
|
||||
defender_info, attacker_infos[1], def_stat, att_stats[1], defender_on_village, defender_healing, cfg
|
||||
)
|
||||
|
||||
-- Now we add some extra ratings. They are positive for attacks that should be preferred
|
||||
|
@ -319,8 +327,8 @@ function ca_fast_attack_utils.attack_rating(attacker_infos, defender_info, dsts,
|
|||
extra_rating = extra_rating + defender_starting_damage_fraction * 0.33
|
||||
|
||||
-- If defender is on a village, add a bonus rating (we want to get rid of those preferentially)
|
||||
-- This is in addition to the damage bonus already included above (but as an extra rating)
|
||||
if defender_healing then
|
||||
-- This is in addition to the healing bonus already included above (but as an extra rating)
|
||||
if defender_on_village then
|
||||
extra_rating = extra_rating + 10.
|
||||
end
|
||||
|
||||
|
|
|
@ -35,11 +35,11 @@ function ca_healer_move:evaluation(cfg, data)
|
|||
local healees, healees_MP = {}, {}
|
||||
for _,healee in ipairs(all_healees) do
|
||||
-- Potential healees are units without MP that don't already have a healer (also without MP) next to them
|
||||
-- Also, they cannot be on a village or regenerate
|
||||
-- Also, they cannot be on a healing location or regenerate
|
||||
if (healee.moves == 0) then
|
||||
if (not healee:matches { ability = "regenerates" }) then
|
||||
local is_village = wesnoth.get_terrain_info(wesnoth.get_terrain(healee.x, healee.y)).village
|
||||
if (not is_village) then
|
||||
local healing = wesnoth.get_terrain_info(wesnoth.get_terrain(healee.x, healee.y)).healing
|
||||
if (healing == 0) then
|
||||
local is_healee = true
|
||||
for _,healer in ipairs(healers_noMP) do
|
||||
if (M.distance_between(healee.x, healee.y, healer.x, healer.y) == 1) then
|
||||
|
|
Loading…
Add table
Reference in a new issue