wesnoth/data/ai/micro_ais/cas/ca_messenger_move.lua
mattsc 9976eac873 Micro AI CA files: replace tabs by spaces
I had not realized that TextWrangler changes spaces to tabs when
shifting blocks of text to the left, which had been done for all CA
files when converting the engine files.
2013-11-14 10:54:14 -08:00

125 lines
4.8 KiB
Lua

local H = wesnoth.require "lua/helper.lua"
local AH = wesnoth.require "ai/lua/ai_helper.lua"
local ca_messenger_move = {}
local messenger_next_waypoint = wesnoth.require "ai/micro_ais/cas/ca_messenger_f_next_waypoint.lua"
function ca_messenger_move:evaluation(ai, cfg)
-- Move the messenger (unit with passed id) toward goal, attack adjacent unit if possible
-- without retaliation or little expected damage with high chance of killing the enemy
local messenger = wesnoth.get_units{ id = cfg.id, formula = '$this_unit.moves > 0' }[1]
if messenger then
return cfg.ca_score
end
return 0
end
function ca_messenger_move:execution(ai, cfg, self)
local messenger = wesnoth.get_units{ id = cfg.id, formula = '$this_unit.moves > 0' }[1]
local x, y = messenger_next_waypoint(messenger, cfg, self)
if (messenger.x ~= x) or (messenger.y ~= y) then
x, y = wesnoth.find_vacant_tile( x, y, messenger)
end
local next_hop = AH.next_hop(messenger, x, y)
if (not next_hop) then next_hop = { messenger.x, messenger.y } end
-- Compare this to the "ideal path"
local path, cost = wesnoth.find_path(messenger, x, y, { ignore_units = 'yes' })
local opt_hop, opt_cost = {messenger.x, messenger.y}, 0
for i, p in ipairs(path) do
local sub_path, sub_cost = wesnoth.find_path(messenger, p[1], p[2])
if sub_cost > messenger.moves then
break
else
local unit_in_way = wesnoth.get_unit(p[1], p[2])
if not unit_in_way then
opt_hop, nh_cost = p, sub_cost
end
end
end
--print(next_hop[1], next_hop[2], opt_hop[1], opt_hop[2])
-- Now compare how long it would take from the end of both of these options
local x1, y1 = messenger.x, messenger.y
wesnoth.put_unit(next_hop[1], next_hop[2], messenger)
local tmp, cost1 = wesnoth.find_path(messenger, x, y, {ignore_units = 'yes'})
wesnoth.put_unit(opt_hop[1], opt_hop[2], messenger)
local tmp, cost2 = wesnoth.find_path(messenger, x, y, {ignore_units = 'yes'})
wesnoth.put_unit(x1, y1, messenger)
--print(cost1, cost2)
-- If cost2 is significantly less, that means that the other path might overall be faster
-- even though it is currently blocked
if (cost2 + messenger.max_moves/2 < cost1) then next_hop = opt_hop end
--print(next_hop[1], next_hop[2])
if next_hop and ((next_hop[1] ~= messenger.x) or (next_hop[2] ~= messenger.y)) then
ai.move(messenger, next_hop[1], next_hop[2])
else
ai.stopunit_moves(messenger)
end
-- We also test whether an attack without retaliation or with little damage is possible
if (not H.get_child(messenger.__cfg, 'attack')) then return end
local targets = wesnoth.get_units {
{ "filter_side", { {"enemy_of", {side = wesnoth.current.side} } } },
{ "filter_adjacent", { id = cfg.id } }
}
local max_rating, best_tar, best_weapon = -9e99, {}, -1
for i,t in ipairs(targets) do
local n_weapon = 0
for weapon in H.child_range(messenger.__cfg, "attack") do
n_weapon = n_weapon + 1
local att_stats, def_stats = wesnoth.simulate_combat(messenger, n_weapon, t)
local rating = -9e99
-- This is an acceptable attack if:
-- 1. There is no counter attack
-- 2. Probability of death is >=67% for enemy, 0% for attacker (default values)
local enemy_death_chance = cfg.enemy_death_chance or 0.67
local messenger_death_chance = cfg.messenger_death_chance or 0
if (att_stats.hp_chance[messenger.hitpoints] == 1)
or (def_stats.hp_chance[0] >= tonumber(enemy_death_chance)) and (att_stats.hp_chance[0] <= tonumber(messenger_death_chance))
then
rating = t.max_hitpoints + def_stats.hp_chance[0]*100 + att_stats.average_hp - def_stats.average_hp
end
--print(messenger.id, t.id,weapon.name, rating)
if rating > max_rating then
max_rating, best_tar, best_weapon = rating, t, n_weapon
end
end
end
if max_rating > -9e99 then
ai.attack(messenger, best_tar, best_weapon)
else
-- Otherwise, always attack enemy on last waypoint
local waypoint_x = AH.split(cfg.waypoint_x, ",")
local waypoint_y = AH.split(cfg.waypoint_y, ",")
local target = wesnoth.get_units {
x = tonumber(waypoint_x[#waypoint_x]),
y = tonumber(waypoint_y[#waypoint_y]),
{ "filter_side", { {"enemy_of", {side = wesnoth.current.side} } } },
{ "filter_adjacent", { id = cfg.id } }
}[1]
if target then
ai.attack(messenger, target)
end
end
-- Finally, make sure unit is really done after this
ai.stopunit_attacks(messenger)
end
return ca_messenger_move