Bugfixes and improvements for experimental multiplayer AI.
Avoid crash near end of games with turn limits. Properly identify poison immune units. Better timing for keep switching. Handle more weapon specials involving damage.
This commit is contained in:
parent
3673f79c8a
commit
0f15ff94db
4 changed files with 73 additions and 9 deletions
|
@ -2,8 +2,12 @@ Version 1.11.1+svn:
|
|||
* AI:
|
||||
* Experimental Multiplayer AI
|
||||
* Improve recruitment, notably first turn choices and units with poison
|
||||
and charge
|
||||
* Improved selection of units for village stealing
|
||||
* Remove dependency on AI-demos add-on
|
||||
* Fix bug when playing on maps with a turn limit
|
||||
* Fix bug handling regeneration
|
||||
* Minor improvements in switching between castles
|
||||
* Campaigns:
|
||||
* Son of the Black Eye:
|
||||
* Prevent infinite loop if fewer than two transport ships (bug #20389)
|
||||
|
|
|
@ -110,7 +110,7 @@ return {
|
|||
local defense = defender_defense
|
||||
local poison = false
|
||||
local damage_multiplier = 1
|
||||
-- TODO: handle more abilities (charge)
|
||||
|
||||
for special in H.child_range(attack, 'specials') do
|
||||
local mod
|
||||
if H.get_child(special, 'poison') and can_poison then
|
||||
|
@ -130,13 +130,15 @@ return {
|
|||
end
|
||||
end
|
||||
|
||||
-- Handle backstab
|
||||
-- Handle backstab, charge
|
||||
mod = H.get_child(special, 'damage')
|
||||
if mod then
|
||||
if mod and mod.active_on ~= "defense" then
|
||||
if mod.backstab then
|
||||
-- Assume backstab happens on only 1/2 of attacks
|
||||
-- TODO: find out what actual probability of getting to backstab is
|
||||
damage_multiplier = damage_multiplier*(mod.multiply*0.5 + 0.5)
|
||||
else
|
||||
damage_multiplier = damage_multiplier*mod.multiply
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -210,7 +212,7 @@ return {
|
|||
name = "X",
|
||||
random_gender = false
|
||||
}
|
||||
local can_poison = living(unit) or wesnoth.unit_ability(unit, 'regenerate')
|
||||
local can_poison = living(unit) and (not wesnoth.unit_ability(unit, 'regenerate'))
|
||||
local flat_defense = wesnoth.unit_defense(unit, "Gt")
|
||||
local best_defense = get_best_defense(unit)
|
||||
|
||||
|
@ -644,7 +646,12 @@ return {
|
|||
eta = eta + 1
|
||||
end
|
||||
-- divide the lawful bonus by eta before running it through the function because the function converts from 0 centered to 1 centered
|
||||
local lawful_bonus = wesnoth.get_time_of_day(wesnoth.current.turn + eta).lawful_bonus / eta^2
|
||||
|
||||
local lawful_bonus = 1
|
||||
local eta_turn = wesnoth.current.turn + eta
|
||||
if eta_turn <= wesnoth.game_config.last_turn then
|
||||
lawful_bonus = wesnoth.get_time_of_day(wesnoth.current.turn + eta).lawful_bonus / eta^2
|
||||
end
|
||||
local damage_bonus = AH.get_unit_time_of_day_bonus(recruit_unit.__cfg.alignment, lawful_bonus)
|
||||
-- Estimate effectiveness on offense and defense
|
||||
local offense_score =
|
||||
|
|
|
@ -74,7 +74,7 @@ return {
|
|||
end
|
||||
|
||||
if self.data.leader_target then
|
||||
return 290000
|
||||
return self.data.leader_score
|
||||
end
|
||||
|
||||
local width,height,border = wesnoth.get_map_size()
|
||||
|
@ -88,7 +88,7 @@ return {
|
|||
}} }}, -- That are not too close to an enemy leader
|
||||
{ "not", {
|
||||
x = leader.x, y = leader.y, terrain = "K*^*,*^Kov",
|
||||
radius = 2,
|
||||
radius = 3,
|
||||
{ "filter_radius", { terrain = 'C*^*,K*^*,*^Kov,*^Cov' } }
|
||||
}}, -- That are not close and connected to a keep the leader is on
|
||||
{ "filter_adjacent_location", {
|
||||
|
@ -115,7 +115,7 @@ return {
|
|||
-- Prefer closer keeps to enemy
|
||||
local turns = math.ceil(cost/leader.max_moves)
|
||||
if turns <= 2 then
|
||||
score = 1/(math.ceil(turns))
|
||||
score = 1/turns
|
||||
for j,e in ipairs(enemy_leaders) do
|
||||
score = score + 1 / H.distance_between(loc[1], loc[2], e.x, e.y)
|
||||
end
|
||||
|
@ -128,6 +128,30 @@ return {
|
|||
end
|
||||
end
|
||||
|
||||
-- If we're on a keep,
|
||||
-- don't move to another keep unless it's much better when uncaptured villages are present
|
||||
if best_score > 0 and wesnoth.get_terrain_info(wesnoth.get_terrain(leader.x, leader.y)).keep then
|
||||
local close_unowned_village = (wesnoth.get_villages {
|
||||
{ "and", {
|
||||
x = leader.x,
|
||||
y = leader.y,
|
||||
radius = leader.max_moves
|
||||
}},
|
||||
owner_side = 0
|
||||
})[1]
|
||||
if close_unowned_village then
|
||||
local score = 1/best_turns
|
||||
for j,e in ipairs(enemy_leaders) do
|
||||
-- count all distances as three less than they actually are
|
||||
score = score + 1 / (H.distance_between(leader.x, leader.y, e.x, e.y) - 3)
|
||||
end
|
||||
|
||||
if score > best_score then
|
||||
best_score = 0
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if best_score > 0 then
|
||||
local next_hop = AH.next_hop(leader, best_loc[1], best_loc[2])
|
||||
|
||||
|
@ -157,8 +181,34 @@ return {
|
|||
end
|
||||
|
||||
self.data.leader_target = next_hop
|
||||
|
||||
-- if we're on a keep, wait until there are no movable units on the castle before moving off
|
||||
self.data.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,
|
||||
{ "and", {
|
||||
x = leader.x, y = leader.y, radius = 200,
|
||||
{ "filter_radius", { terrain = 'C*^*,K*^*,*^Kov,*^Cov' } }
|
||||
}}
|
||||
}
|
||||
local should_wait = false
|
||||
for i,loc in ipairs(castle) do
|
||||
local unit = wesnoth.get_unit(loc[1], loc[2])
|
||||
if not unit then
|
||||
should_wait = false
|
||||
break
|
||||
elseif unit.moves > 0 then
|
||||
should_wait = true
|
||||
end
|
||||
end
|
||||
if should_wait then
|
||||
self.data.leader_score = 15000
|
||||
end
|
||||
end
|
||||
|
||||
AH.done_eval_messages(start_time, ca_name)
|
||||
return 290000
|
||||
return self.data.leader_score
|
||||
end
|
||||
|
||||
AH.done_eval_messages(start_time, ca_name)
|
||||
|
|
|
@ -8,6 +8,9 @@ Version 1.11.1+svn:
|
|||
* Improve recruitment, notably first turn choices and units with poison.
|
||||
* Improve selection of units for village stealing.
|
||||
* Remove dependency on AI-demos add-on.
|
||||
* Fix bug when playing on maps with a turn limit.
|
||||
* Fix bug handling regeneration.
|
||||
* Minor improvements in switching between castles.
|
||||
|
||||
* Campaigns:
|
||||
* Son of the Black Eye:
|
||||
|
|
Loading…
Add table
Reference in a new issue