This commit is contained in:
Chris Beck 2014-04-14 16:31:38 -04:00
commit 51d31196bc
28 changed files with 268 additions and 317 deletions

View file

@ -19,38 +19,34 @@ function ca_big_animals:evaluation(ai, cfg)
end
function ca_big_animals:execution(ai, cfg)
-- Big animals just move toward goal that gets set occasionally
-- Avoid the other big animals (bears, yetis, spiders) and the dogs, otherwise attack whatever is in their range
-- The only difference in behavior is the area in which the units move
-- Big animals just move toward a goal that gets (re)set occasionally
-- and attack whatever is in their range (except for some units that they avoid)
local big_animals = get_big_animals(cfg)
local avoid = LS.of_pairs(wesnoth.get_locations { radius = 1,
local avoid_map = LS.of_pairs(wesnoth.get_locations { radius = 1,
{ "filter", { { "and", cfg.avoid_unit },
{ "filter_side", {{"enemy_of", {side = wesnoth.current.side} }} }
{ "filter_side", { { "enemy_of", { side = wesnoth.current.side } } } }
} }
})
--AH.put_labels(avoid)
for i,unit in ipairs(big_animals) do
for _,unit in ipairs(big_animals) do
local goal = MAIUV.get_mai_unit_variables(unit, cfg.ai_id)
-- Unit gets a new goal if none exist or on any move with 10% random chance
-- Unit gets a new goal if none is set or on any move with a 10% random chance
local r = math.random(10)
if (not goal.goal_x) or (r == 1) then
local locs = AH.get_passable_locations(cfg.filter_location or {})
local rand = math.random(#locs)
--print(type, ': #locs', #locs, rand)
goal.goal_x, goal.goal_y = locs[rand][1], locs[rand][2]
MAIUV.set_mai_unit_variables(unit, cfg.ai_id, goal)
end
--print('Big animal goto: ', unit.id, goal.goal_x, goal.goal_y, r)
-- hexes the unit can reach
local reach_map = AH.get_reachable_unocc(unit)
local wander_terrain = cfg.filter_location_wander or {}
reach_map:iter( function(x, y, v)
-- Remove tiles that do not comform to the wander terrain filter
if (not wesnoth.match_location(x, y, wander_terrain) ) then
if (not wesnoth.match_location(x, y, wander_terrain)) then
reach_map:remove(x, y)
end
end)
@ -58,56 +54,52 @@ function ca_big_animals:execution(ai, cfg)
-- Now find the one of these hexes that is closest to the goal
local max_rating, best_hex = -9e99, {}
reach_map:iter( function(x, y, v)
-- Distance from goal is first rating
local rating = - H.distance_between(x, y, goal.goal_x, goal.goal_y)
-- Proximity to an enemy unit is a plus
local enemy_hp = 500
for xa, ya in H.adjacent_tiles(x, y) do
for xa,ya in H.adjacent_tiles(x, y) do
local enemy = wesnoth.get_unit(xa, ya)
if enemy and (enemy.side ~= wesnoth.current.side) then
if enemy and wesnoth.is_enemy(enemy.side, wesnoth.current.side) then
if (enemy.hitpoints < enemy_hp) then enemy_hp = enemy.hitpoints end
end
end
rating = rating + 500 - enemy_hp -- prefer attack on weakest enemy
rating = rating + 500 - enemy_hp -- Prefer attack on weakest enemy
-- However, hexes that enemy bears, yetis and spiders can reach get a massive negative hit
-- meaning that they will only ever be chosen if there's no way around them
if avoid:get(x, y) then rating = rating - 1000 end
-- Hexes reachable by units to be be avoided get a massive negative hit
if avoid_map:get(x, y) then rating = rating - 1000 end
reach_map:insert(x, y, rating)
if (rating > max_rating) then
max_rating, best_hex = rating, { x, y }
end
end)
--print(' best_hex: ', best_hex[1], best_hex[2])
--AH.put_labels(reach_map)
if (best_hex[1] ~= unit.x) or (best_hex[2] ~= unit.y) then
AH.checked_move(ai, unit, best_hex[1], best_hex[2]) -- partial move only
AH.checked_move(ai, unit, best_hex[1], best_hex[2]) -- Partial move only
if (not unit) or (not unit.valid) then return end
else -- If animal did not move, we need to stop it (also delete the goal)
else -- If unit did not move, we need to stop it (also delete the goal)
AH.checked_stopunit_moves(ai, unit)
if (not unit) or (not unit.valid) then return end
MAIUV.delete_mai_unit_variables(unit, cfg.ai_id)
end
-- Or if this gets the unit to the goal, we also delete the goal
-- If this gets the unit to the goal, we also delete the goal
if (unit.x == goal.goal_x) and (unit.y == goal.goal_y) then
MAIUV.delete_mai_unit_variables(unit, cfg.ai_id)
end
-- Finally, if the unit ended up next to enemies, attack the weakest of those
local min_hp, target = 9e99, {}
for x, y in H.adjacent_tiles(unit.x, unit.y) do
local enemy = wesnoth.get_unit(x, y)
if enemy and (enemy.side ~= wesnoth.current.side) then
local min_hp, target = 9e99
for xa,ya in H.adjacent_tiles(unit.x, unit.y) do
local enemy = wesnoth.get_unit(xa, ya)
if enemy and wesnoth.is_enemy(enemy.side, wesnoth.current.side) then
if (enemy.hitpoints < min_hp) then
min_hp, target = enemy.hitpoints, enemy
end
end
end
if target.id then
if target then
AH.checked_attack(ai, unit, target)
end
end

View file

@ -36,13 +36,13 @@ function ca_coward:execution(ai, cfg)
return
end
for i,r in ipairs(reach) do
for i,hex in ipairs(reach) do
-- Only consider unoccupied hexes
local occ_hex = wesnoth.get_units { x = r[1], y = r[2], { "not", { id = coward.id } } }[1]
local occ_hex = wesnoth.get_units { x = hex[1], y = hex[2], { "not", { id = coward.id } } }[1]
if not occ_hex then
local rating = 0
for _,e in ipairs(enemies) do
local dist = H.distance_between(r[1], r[2], e.x, e.y)
for _,enemy in ipairs(enemies) do
local dist = H.distance_between(hex[1], hex[2], enemy.x, enemy.y)
rating = rating - 1 / dist^2
end
@ -58,10 +58,10 @@ function ca_coward:execution(ai, cfg)
local best_pos = AH.filter(reach, function(tmp) return tmp[3] > reach[1][3] * 2 end)
-- Now take 'seek' and 'avoid' into account
for i,b in ipairs(best_pos) do
for i,pos in ipairs(best_pos) do
-- Weighting based on distance from 'seek' and 'avoid'
local dist_seek = AH.generalized_distance(b[1], b[2], cfg.seek_x, cfg.seek_y)
local dist_avoid = AH.generalized_distance(b[1], b[2], cfg.avoid_x, cfg.avoid_y)
local dist_seek = AH.generalized_distance(pos[1], pos[2], cfg.seek_x, cfg.seek_y)
local dist_avoid = AH.generalized_distance(pos[1], pos[2], cfg.avoid_x, cfg.avoid_y)
local rating = 1 / (dist_seek + 1) - 1 / (dist_avoid + 1)^2 * 0.75
best_pos[i][4] = rating
@ -74,9 +74,9 @@ function ca_coward:execution(ai, cfg)
-- As final step, if there are more than one remaining locations,
-- we take the one with the minimum score in the distance-from-enemy criterion
local max_rating, best_hex = -9e99
for _,b in ipairs(best_overall) do
if (b[3] > max_rating) then
max_rating, best_hex = b[3], b
for _,pos in ipairs(best_overall) do
if (pos[3] > max_rating) then
max_rating, best_hex = pos[3], pos
end
end

View file

@ -4,7 +4,7 @@ local AH = wesnoth.require "ai/lua/ai_helper.lua"
local LS = wesnoth.require "lua/location_set.lua"
local function get_forest_animals(cfg)
-- We want the deer/rabbits to move first, tuskers later
-- We want the deer/rabbits to move first, tuskers afterward
local deer_type = cfg.deer_type or "no_unit_of_this_type"
local rabbit_type = cfg.rabbit_type or "no_unit_of_this_type"
local forest_animals = AH.get_units_with_moves {
@ -14,16 +14,16 @@ local function get_forest_animals(cfg)
local tusker_type = cfg.tusker_type or "no_unit_of_this_type"
local all_tuskers = wesnoth.get_units { side = wesnoth.current.side, type = tusker_type }
for i,t in ipairs(all_tuskers) do
if (t.moves > 0) then table.insert(forest_animals, t) end
for _,tusker in ipairs(all_tuskers) do
if (tusker.moves > 0) then table.insert(forest_animals, tusker) end
end
-- Tusklets get moved by this CA if there are no tuskers left
if not all_tuskers[1] then
local tusklet_type = cfg.tusklet_type or "no_unit_of_this_type"
local tusklets = wesnoth.get_units { side = wesnoth.current.side, type = tusklet_type }
for i,t in ipairs(tusklets) do
if (t.moves > 0) then table.insert(forest_animals, t) end
for _,tusklet in ipairs(tusklets) do
if (tusklet.moves > 0) then table.insert(forest_animals, tusklet) end
end
end
@ -38,10 +38,9 @@ function ca_forest_animals_move:evaluation(ai, cfg)
end
function ca_forest_animals_move:execution(ai, cfg)
local forest_animals = get_forest_animals(cfg)
-- These animals run from any enemy
local enemies = wesnoth.get_units { { "filter_side", {{"enemy_of", {side = wesnoth.current.side} }} } }
local forest_animals = get_forest_animals(cfg)
local enemies = wesnoth.get_units { { "filter_side", { { "enemy_of", {side = wesnoth.current.side } } } } }
-- Get the locations of all the rabbit holes
W.store_items { variable = 'holes_wml' }
@ -49,73 +48,64 @@ function ca_forest_animals_move:execution(ai, cfg)
W.clear_variable { name = 'holes_wml' }
-- If cfg.rabbit_hole_img is set, only items with that image or halo count as holes
local holes = {}
for _, item in ipairs(all_items) do
if cfg.rabbit_hole_img then
local holes
if cfg.rabbit_hole_img then
for _,item in ipairs(all_items) do
if (item.image == cfg.rabbit_hole_img) or (item.halo == cfg.rabbit_hole_img) then
table.insert(holes, item)
end
else
table.insert(holes, item)
end
else
holes = all_items
end
local hole_map = LS.create()
for i,h in ipairs(holes) do hole_map:insert(h.x, h.y, 1) end
--AH.put_labels(hole_map)
for _,hole in ipairs(holes) do hole_map:insert(hole.x, hole.y, 1) end
-- Each unit moves independently
for i,unit in ipairs(forest_animals) do
--print('Unit', i, unit.x, unit.y)
for _,unit in ipairs(forest_animals) do
-- Behavior is different depending on whether a predator is close or not
local close_enemies = {}
for j,e in ipairs(enemies) do
if (H.distance_between(unit.x, unit.y, e.x, e.y) <= unit.max_moves+1) then
table.insert(close_enemies, e)
for _,enemy in ipairs(enemies) do
if (H.distance_between(unit.x, unit.y, enemy.x, enemy.y) <= unit.max_moves+1) then
table.insert(close_enemies, enemy)
end
end
--print(' #close_enemies', #close_enemies)
-- If no close enemies, do a random move
local wander_terrain = cfg.filter_location or {}
if (not close_enemies[1]) then
-- All hexes the unit can reach that are unoccupied
local reach = AH.get_reachable_unocc(unit)
local locs = wesnoth.get_locations(wander_terrain)
local locs_map = LS.of_pairs(locs)
--print(' #all reachable', reach:size())
local wander_locs = wesnoth.get_locations(wander_terrain)
local locs_map = LS.of_pairs(wander_locs)
-- Select only those that satisfy wander_terrain
local reachable_terrain = {}
local reachable_wander_terrain = {}
reach:iter( function(x, y, v)
local terrain = wesnoth.get_terrain(x,y)
--print(x, y, terrain)
if locs_map:get(x,y) then -- doesn't work with '^', so start search at char 2
table.insert(reachable_terrain, {x, y})
if locs_map:get(x,y) then
table.insert(reachable_wander_terrain, {x, y})
end
end)
--print(' #reachable_terrain', #reachable_terrain)
-- Choose one of the possible locations at random
if reachable_terrain[1] then
local rand = math.random(#reachable_terrain)
if reachable_wander_terrain[1] then
local rand = math.random(#reachable_wander_terrain)
-- This is not a full move, as running away might happen next
if (unit.x ~= reachable_terrain[rand][1]) or (unit.y ~= reachable_terrain[rand][2]) then
AH.checked_move(ai, unit, reachable_terrain[rand][1], reachable_terrain[rand][2])
if (unit.x ~= reachable_wander_terrain[rand][1]) or (unit.y ~= reachable_wander_terrain[rand][2]) then
AH.checked_move(ai, unit, reachable_wander_terrain[rand][1], reachable_wander_terrain[rand][2])
end
else -- or if no close reachable terrain was found, move toward the closest
local locs = wesnoth.get_locations(wander_terrain)
else -- Or if no close reachable terrain was found, move toward the closest
local best_hex, min_dist = {}, 9e99
for j,l in ipairs(locs) do
local d = H.distance_between(l[1], l[2], unit.x, unit.y)
if d < min_dist then
best_hex, min_dist = l,d
for _,loc in ipairs(wander_locs) do
local dist = H.distance_between(loc[1], loc[2], unit.x, unit.y)
if dist < min_dist then
best_hex, min_dist = loc, dist
end
end
if (best_hex[1]) then
local x,y = wesnoth.find_vacant_tile(best_hex[1], best_hex[2], unit)
local next_hop = AH.next_hop(unit, x, y)
--print(next_hop[1], next_hop[2])
if (unit.x ~= next_hop[1]) or (unit.y ~= next_hop[2]) then
AH.checked_move(ai, unit, next_hop[1], next_hop[2])
end
@ -125,17 +115,13 @@ function ca_forest_animals_move:execution(ai, cfg)
-- Now we check for close enemies again, as we might just have moved within reach of some
local close_enemies = {}
-- We use a trick here to exclude the case when the unit might have been
-- removed in an event above
if unit and unit.valid then
for j,e in ipairs(enemies) do
if (H.distance_between(unit.x, unit.y, e.x, e.y) <= unit.max_moves+1) then
table.insert(close_enemies, e)
for _,enemy in ipairs(enemies) do
if (H.distance_between(unit.x, unit.y, enemy.x, enemy.y) <= unit.max_moves+1) then
table.insert(close_enemies, enemy)
end
end
end
--print(' #close_enemies after move', #close_enemies, #enemies, unit.id)
-- If there are close enemies, run away (and rabbits disappear into holes)
local rabbit_type = cfg.rabbit_type or "no_unit_of_this_type"
@ -144,33 +130,34 @@ function ca_forest_animals_move:execution(ai, cfg)
-- Returns nil if the only hex that can be reached is the one the unit is on
local farthest_hex = AH.find_best_move(unit, function(x, y)
local rating = 0
for i,e in ipairs(close_enemies) do
local d = H.distance_between(e.x, e.y, x, y)
rating = rating - 1 / d^2
for _,enemy in ipairs(close_enemies) do
local dist = H.distance_between(enemy.x, enemy.y, x, y)
rating = rating - 1 / dist^2
end
-- If this is a rabbit, try to go for holes
if (unit.type == rabbit_type) and hole_map:get(x, y) then
rating = rating + 1000
-- but if possible, go to another hole
-- But if possible, go to another hole if unit is on one
if (x == unit.x) and (y == unit.y) then rating = rating - 10 end
end
return rating
end)
--print(' farthest_hex: ', farthest_hex[1], farthest_hex[2])
-- This will always find at least the hex the unit is on
-- so no check is necessary
AH.movefull_stopunit(ai, unit, farthest_hex)
-- If this is a rabbit ending on a hole -> disappears
if (unit.type == rabbit_type) and hole_map:get(farthest_hex[1], farthest_hex[2]) then
if unit and unit.valid
and (unit.type == rabbit_type) and hole_map:get(farthest_hex[1], farthest_hex[2])
then
local command = "wesnoth.put_unit(x1, y1)"
ai.synced_command(command, farthest_hex[1], farthest_hex[2])
end
end
-- Finally, take moves away, as only partial move might have been done
-- Also attacks, as these units never attack
-- Also take attacks away, as these units never attack
if unit and unit.valid then AH.checked_stopunit_all(ai, unit) end
end
end

View file

@ -5,9 +5,8 @@ local AH = wesnoth.require "ai/lua/ai_helper.lua"
local ca_forest_animals_new_rabbit = {}
function ca_forest_animals_new_rabbit:evaluation(ai, cfg)
-- Put new rabbits out the if there are fewer than cfg.rabbit_number
-- but only if cfg.rabbit_type is set, otherwise do nothing
-- If this gets executed, we'll let the CA black-list itself
-- Put new rabbits on map if there are fewer than cfg.rabbit_number
-- To end this, we'll let the CA black-list itself
if (not cfg.rabbit_type) then return 0 end
return cfg.ca_score
@ -25,11 +24,12 @@ function ca_forest_animals_new_rabbit:execution(ai, cfg)
-- Eliminate all holes that have an enemy within 'rabbit_enemy_distance' hexes
-- We also add a random number to the ones we keep, for selection of the holes later
local holes = {}
for _, item in ipairs(all_items) do
for _,item in ipairs(all_items) do
local enemies = wesnoth.get_units {
{ "filter_side", {{"enemy_of", {side = wesnoth.current.side} }} },
{ "filter_side", { { "enemy_of", { side = wesnoth.current.side } } } },
{ "filter_location", { x = item.x, y = item.y, radius = rabbit_enemy_distance } }
}
if (not enemies[1]) then
-- If cfg.rabbit_hole_img is set, only items with that image or halo count as holes
if cfg.rabbit_hole_img then
@ -46,13 +46,10 @@ function ca_forest_animals_new_rabbit:execution(ai, cfg)
table.sort(holes, function(a, b) return a.random > b.random end)
local rabbits = wesnoth.get_units { side = wesnoth.current.side, type = cfg.rabbit_type }
--print('total number:', number)
number = number - #rabbits
--print('to add number:', number)
number = math.min(number, #holes)
--print('to add number possible:', number)
-- Now we just can take the first 'number' (randomized) holes
-- Now we simply take the first 'number' (randomized) holes
local tmp_unit = wesnoth.get_units { side = wesnoth.current.side }[1]
for i = 1,number do
local x, y = -1, -1
@ -66,7 +63,7 @@ function ca_forest_animals_new_rabbit:execution(ai, cfg)
.. wesnoth.current.side
.. ", type = '"
.. cfg.rabbit_type
.. "' } )"
.. "' })"
ai.synced_command(command, x, y)
end
end

View file

@ -22,9 +22,7 @@ local ca_forest_animals_tusker_attack = {}
function ca_forest_animals_tusker_attack:evaluation(ai, cfg)
-- Check whether there is an enemy next to a tusklet and attack it ("protective parents" AI)
-- Both cfg.tusker_type and cfg.tusklet_type need to be set for this to kick in
if (not cfg.tusker_type) or (not cfg.tusklet_type) then return 0 end
if (not get_tuskers(cfg)[1]) then return 0 end
if (not get_adjacent_enemies(cfg)[1]) then return 0 end
return cfg.ca_score
@ -35,37 +33,37 @@ function ca_forest_animals_tusker_attack:execution(ai, cfg)
local adjacent_enemies = get_adjacent_enemies(cfg)
-- Find the closest enemy to any tusker
local min_dist, attacker, target = 9e99, {}, {}
for i,t in ipairs(tuskers) do
for j,e in ipairs(adjacent_enemies) do
local dist = H.distance_between(t.x, t.y, e.x, e.y)
local min_dist, attacker, target = 9e99
for _,tusker in ipairs(tuskers) do
for _,enemy in ipairs(adjacent_enemies) do
local dist = H.distance_between(tusker.x, tusker.y, enemy.x, enemy.y)
if (dist < min_dist) then
min_dist, attacker, target = dist, t, e
min_dist, attacker, target = dist, tusker, enemy
end
end
end
--print(attacker.id, target.id)
-- The tusker moves as close to enemy as possible
-- Closeness to tusklets is secondary criterion
local adj_tusklets = wesnoth.get_units { side = wesnoth.current.side, type = cfg.tusklet_type,
local adj_tusklets = wesnoth.get_units {
side = wesnoth.current.side,
type = cfg.tusklet_type,
{ "filter_adjacent", { id = target.id } }
}
local best_hex = AH.find_best_move(attacker, function(x, y)
local rating = - H.distance_between(x, y, target.x, target.y)
for i,t in ipairs(adj_tusklets) do
if (H.distance_between(x, y, t.x, t.y) == 1) then rating = rating + 0.1 end
for _,tusklet in ipairs(adj_tusklets) do
if (H.distance_between(x, y, tusklet.x, tusklet.y) == 1) then rating = rating + 0.1 end
end
return rating
end)
--print('attacker', attacker.x, attacker.y, ' -> ', best_hex[1], best_hex[2])
AH.movefull_stopunit(ai, attacker, best_hex)
if (not attacker) or (not attacker.valid) then return end
if (not target) or (not target.valid) then return end
-- If adjacent, attack
local dist = H.distance_between(attacker.x, attacker.y, target.x, target.y)
if (dist == 1) then
AH.checked_attack(ai, attacker, target)

View file

@ -21,11 +21,9 @@ local ca_forest_animals_tusklet_move = {}
function ca_forest_animals_tusklet_move:evaluation(ai, cfg)
-- Tusklets will simply move toward the closest tusker, without regard for anything else
-- Except if no tuskers are left, in which case the previous CA takes over and does a random move
-- Except if no tuskers are left, in which case ca_forest_animals_move takes over and does a random move
-- Both cfg.tusker_type and cfg.tusklet_type need to be set for this to kick in
if (not cfg.tusker_type) or (not cfg.tusklet_type) then return 0 end
if (not get_tusklets(cfg)[1]) then return 0 end
if (not get_tuskers(cfg)[1]) then return 0 end
return cfg.ca_score
@ -35,22 +33,19 @@ function ca_forest_animals_tusklet_move:execution(ai, cfg)
local tusklets = get_tusklets(cfg)
local tuskers = get_tuskers(cfg)
for i,tusklet in ipairs(tusklets) do
-- find closest tusker
local goto_tusker, min_dist = {}, 9999
for i,t in ipairs(tuskers) do
local dist = H.distance_between(t.x, t.y, tusklet.x, tusklet.y)
for _,tusklet in ipairs(tusklets) do
local goto_tusker, min_dist = {}, 9e99
for _,tusker in ipairs(tuskers) do
local dist = H.distance_between(tusker.x, tusker.y, tusklet.x, tusklet.y)
if (dist < min_dist) then
min_dist, goto_tusker = dist, t
min_dist, goto_tusker = dist, tusker
end
end
--print('closets tusker:', goto_tusker.x, goto_tusker.y, goto_tusker.id)
-- Move tusklet toward that tusker
local best_hex = AH.find_best_move(tusklet, function(x, y)
return -H.distance_between(x, y, goto_tusker.x, goto_tusker.y)
return - H.distance_between(x, y, goto_tusker.x, goto_tusker.y)
end)
--print('tusklet', tusklet.x, tusklet.y, ' -> ', best_hex[1], best_hex[2])
AH.movefull_stopunit(ai, tusklet, best_hex)
-- Also make sure tusklets never attack

View file

@ -19,7 +19,7 @@ end
local function get_enemies(cfg, radius)
local enemies = wesnoth.get_units {
{ "filter_side", { {"enemy_of", {side = wesnoth.current.side} } } },
{ "filter_side", { { "enemy_of", { side = wesnoth.current.side } } } },
{ "filter_location",
{ radius = radius,
{ "filter", { side = wesnoth.current.side, { "and", cfg.filter_second } } } }
@ -44,42 +44,40 @@ end
function ca_herding_attack_close_enemy:execution(ai, cfg)
local sheep = get_sheep(cfg)
local dogs = get_dogs(cfg)
local sheep = wesnoth.get_units { side = wesnoth.current.side, {"and", cfg.filter_second} }
-- We start with enemies within attack_distance (default: 4) hexes, which will be attacked
local radius = cfg.attack_distance or 4
local enemies = get_enemies(cfg, radius)
max_rating, best_dog, best_enemy, best_hex = -9e99, {}, {}, {}
for i,e in ipairs(enemies) do
for j,d in ipairs(dogs) do
local reach_map = AH.get_reachable_unocc(d)
for _,enemy in ipairs(enemies) do
for _,dog in ipairs(dogs) do
local reach_map = AH.get_reachable_unocc(dog)
reach_map:iter( function(x, y, v)
-- most important: distance to enemy
local rating = - H.distance_between(x, y, e.x, e.y) * 100.
-- Most important: distance from enemy
local rating = - H.distance_between(x, y, enemy.x, enemy.y) * 100.
-- 2nd: distance from any sheep
for k,s in ipairs(sheep) do
rating = rating - H.distance_between(x, y, s.x, s.y)
for _,single_sheep in ipairs(sheep) do
rating = rating - H.distance_between(x, y, single_sheep.x, single_sheep.y)
end
-- 3rd: most distant dog goes first
rating = rating + H.distance_between(e.x, e.y, d.x, d.y) / 100.
rating = rating + H.distance_between(enemy.x, enemy.y, dog.x, dog.y) / 100.
reach_map:insert(x, y, rating)
if (rating > max_rating) then
max_rating = rating
best_hex = { x, y }
best_dog, best_enemy = d, e
best_dog, best_enemy, best_hex = dog, enemy, { x, y }
end
end)
--AH.put_labels(reach_map)
--W.message { speaker = d.id, message = 'My turn' }
end
end
-- If we found a move, we do it, and attack if possible
if max_rating > -9e99 then
--print('Dog moving in to attack')
AH.movefull_stopunit(ai, best_dog, best_hex)
if (not best_dog) or (not best_dog.valid) then return end
if (not best_enemy) or (not best_enemy.valid) then return end
if H.distance_between(best_dog.x, best_dog.y, best_enemy.x, best_enemy.y) == 1 then
AH.checked_attack(ai, best_dog, best_enemy)
end
@ -87,50 +85,44 @@ function ca_herding_attack_close_enemy:execution(ai, cfg)
end
-- If we got here, no enemies to attack where found, so we go on to block other enemies
--print('Dogs: No enemies close enough to warrant attack')
-- Now we get all enemies within attention_distance hexes
local radius = cfg.attention_distance or 8
local enemies = get_enemies(cfg, radius)
-- Find closest sheep/enemy pair first
local min_dist, closest_sheep, closest_enemy = 9e99, {}, {}
for i,e in ipairs(enemies) do
for j,s in ipairs(sheep) do
local d = H.distance_between(e.x, e.y, s.x, s.y)
if d < min_dist then
min_dist = d
closest_sheep, closest_enemy = s, e
for _,enemy in ipairs(enemies) do
for _,single_sheep in ipairs(sheep) do
local dist = H.distance_between(enemy.x, enemy.y, single_sheep.x, single_sheep.y)
if dist < min_dist then
min_dist = dist
closest_sheep, closest_enemy = single_sheep, enemy
end
end
end
--print('Closest enemy, sheep:', closest_enemy.id, closest_sheep.id)
-- Move dogs in between enemies and sheep
max_rating, best_dog, best_hex = -9e99, {}, {}
for i,d in ipairs(dogs) do
local reach_map = AH.get_reachable_unocc(d)
for _,dog in ipairs(dogs) do
local reach_map = AH.get_reachable_unocc(dog)
reach_map:iter( function(x, y, v)
-- We want equal distance between enemy and closest sheep
local rating = - math.abs(H.distance_between(x, y, closest_sheep.x, closest_sheep.y) - H.distance_between(x, y, closest_enemy.x, closest_enemy.y)) * 100
local rating = - math.abs(
H.distance_between(x, y, closest_sheep.x, closest_sheep.y)
- H.distance_between(x, y, closest_enemy.x, closest_enemy.y)
) * 100
-- 2nd: closeness to sheep
rating = rating - H.distance_between(x, y, closest_sheep.x, closest_sheep.y)
reach_map:insert(x, y, rating)
-- 3rd: most distant dog goes first
rating = rating + H.distance_between(closest_enemy.x, closest_enemy.y, d.x, d.y) / 100.
rating = rating + H.distance_between(closest_enemy.x, closest_enemy.y, dog.x, dog.y) / 100.
reach_map:insert(x, y, rating)
if (rating > max_rating) then
max_rating = rating
best_hex = { x, y }
best_dog = d
max_rating, best_hex, best_dog = rating, { x, y }, dog
end
end)
--AH.put_labels(reach_map)
--W.message { speaker = d.id, message = 'My turn' }
end
-- Move dog to intercept
--print('Dog moving in to intercept')
AH.movefull_stopunit(ai, best_dog, best_hex)
end

View file

@ -30,7 +30,6 @@ function ca_herding_dog_move:execution(ai, cfg)
av_dist = av_dist + H.distance_between(x, y, cfg.herd_x, cfg.herd_y)
end)
av_dist = av_dist / herding_perimeter:size()
--print('Average distance:', av_dist)
local best_hex = AH.find_best_move(dog, function(x, y)
-- Prefer hexes on herding_perimeter, or close to it
@ -39,13 +38,14 @@ function ca_herding_dog_move:execution(ai, cfg)
if herding_perimeter:get(x, y) then
rating = rating + 1000 + math.random(99) / 100.
else
rating = rating - math.abs(H.distance_between(x, y, cfg.herd_x, cfg.herd_y) - av_dist) + math.random(99) / 100.
rating = rating
- math.abs(H.distance_between(x, y, cfg.herd_x, cfg.herd_y) - av_dist)
+ math.random(99) / 100.
end
return rating
end)
--print('Dog wandering')
AH.movefull_stopunit(ai, dog, best_hex)
end

View file

@ -5,14 +5,18 @@ return function(cfg)
-- Find the area that the sheep can occupy
-- First, find all contiguous hexes around center hex that are inside herding_perimeter
local herding_area = LS.of_pairs(wesnoth.get_locations {
x = cfg.herd_x, y = cfg.herd_y, radius = 999,
{"filter_radius", { { "not", cfg.filter_location } } }
} )
x = cfg.herd_x,
y = cfg.herd_y,
radius = 999,
{ "filter_radius", { { "not", cfg.filter_location } } }
})
-- Then, also exclude hexes next to herding_perimeter; some of the functions work better like that
herding_area:iter( function(x, y, v)
for xa, ya in H.adjacent_tiles(x, y) do
if (wesnoth.match_location(xa, ya, cfg.filter_location) ) then herding_area:remove(x, y) end
if (wesnoth.match_location(xa, ya, cfg.filter_location) ) then
herding_area:remove(x, y)
end
end
end)

View file

@ -15,12 +15,15 @@ local function get_sheep_to_herd(cfg)
local all_sheep = wesnoth.get_units {
side = wesnoth.current.side,
{ "and", cfg.filter_second },
{ "not", { { "filter_adjacent", { side = wesnoth.current.side, {"and", cfg.filter} } } } }
{ "not", { { "filter_adjacent", { side = wesnoth.current.side, { "and", cfg.filter } } } } }
}
local sheep_to_herd = {}
local herding_area = herding_area(cfg)
for i,s in ipairs(all_sheep) do
if (not herding_area:get(s.x, s.y)) then table.insert(sheep_to_herd, s) end
for _,single_sheep in ipairs(all_sheep) do
if (not herding_area:get(single_sheep.x, single_sheep.y)) then
table.insert(sheep_to_herd, single_sheep)
end
end
return sheep_to_herd
end
@ -30,10 +33,9 @@ local ca_herding_herd_sheep = {}
function ca_herding_herd_sheep:evaluation(ai, cfg)
-- If dogs have moves left, and there is a sheep with moves left outside the
-- herding area, chase it back
if get_dogs(cfg)[1] then
if get_sheep_to_herd(cfg)[1] then return cfg.ca_score end
end
return 0
if (not get_dogs(cfg)[1]) then return 0 end
if (not get_sheep_to_herd(cfg)[1]) then return 0 end
return cfg.ca_score
end
function ca_herding_herd_sheep:execution(ai, cfg)
@ -42,48 +44,39 @@ function ca_herding_herd_sheep:execution(ai, cfg)
local max_rating, best_dog, best_hex = -9e99, {}, {}
local c_x, c_y = cfg.herd_x, cfg.herd_y
for i,s in ipairs(sheep_to_herd) do
-- This is the rating that depends only on the sheep's position
for _,single_sheep in ipairs(sheep_to_herd) do
-- Farthest sheep goes first
local sheep_rating = H.distance_between(c_x, c_y, s.x, s.y) / 10.
local sheep_rating = H.distance_between(c_x, c_y, single_sheep.x, single_sheep.y) / 10.
-- Sheep with no movement left gets big hit
if (s.moves == 0) then sheep_rating = sheep_rating - 100. end
if (single_sheep.moves == 0) then sheep_rating = sheep_rating - 100. end
for i,d in ipairs(dogs) do
local reach_map = AH.get_reachable_unocc(d)
for _,dog in ipairs(dogs) do
local reach_map = AH.get_reachable_unocc(dog)
reach_map:iter( function(x, y, v)
local dist = H.distance_between(x, y, s.x, s.y)
local dist = H.distance_between(x, y, single_sheep.x, single_sheep.y)
local rating = sheep_rating - dist
-- Needs to be on "far side" of sheep, wrt center for adjacent hexes
if (H.distance_between(x, y, c_x, c_y) <= H.distance_between(s.x, s.y, c_x, c_y))
if (H.distance_between(x, y, c_x, c_y) <= H.distance_between(single_sheep.x, single_sheep.y, c_x, c_y))
and (dist == 1)
then rating = rating - 1000 end
-- And the closer dog goes first (so that it might be able to chase another sheep afterward)
rating = rating - H.distance_between(x, y, d.x, d.y) / 100.
rating = rating - H.distance_between(x, y, dog.x, dog.y) / 100.
-- Finally, prefer to stay on path, if possible
if (wesnoth.match_location(x, y, cfg.filter_location) ) then rating = rating + 0.001 end
reach_map:insert(x, y, rating)
if (rating > max_rating) then
max_rating = rating
best_dog = d
best_hex = { x, y }
max_rating, best_dog, best_hex = rating, dog, { x, y }
end
end)
--AH.put_labels(reach_map)
--W.message{ speaker = d.id, message = 'My turn' }
end
end
-- Now we move the best dog
-- If it's already in the best position, we just take moves away from it
-- (to avoid black-listing of CA, in the worst case)
if (best_hex[1] == best_dog.x) and (best_hex[2] == best_dog.y) then
AH.checked_stopunit_moves(ai, best_dog)
else
--print('Dog moving to herd sheep')
AH.checked_move(ai, best_dog, best_hex[1], best_hex[2]) -- partial move only
AH.checked_move(ai, best_dog, best_hex[1], best_hex[2]) -- partial move only!
end
end

View file

@ -1,6 +1,5 @@
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 herding_area = wesnoth.require "ai/micro_ais/cas/ca_herding_f_herding_area.lua"
@ -34,13 +33,11 @@ function ca_herding_sheep_move:execution(ai, cfg)
end
end
end)
--AH.put_labels(reach_map)
-- Choose one of the possible locations at random (or the current location, if no move possible)
local x, y = sheep.x, sheep.y
if (reach_map:size() > 0) then
x, y = AH.LS_random_hex(reach_map)
--print('Sheep -> :', x, y)
end
-- If this move remains within herding area or dogs have no moves left, or sheep doesn't move

View file

@ -22,8 +22,8 @@ function ca_herding_sheep_runs_dog:execution(ai, cfg)
-- Simply get the first sheep, order does not matter
local sheep = get_next_sheep(cfg)
-- Get the first dog it is adjacent to
local dog = wesnoth.get_units { side = wesnoth.current.side, {"and", cfg.filter},
-- Get the first dog that the sheep is adjacent to
local dog = wesnoth.get_units { side = wesnoth.current.side, { "and", cfg.filter },
{ "filter_adjacent", { x = sheep.x, y = sheep.y } }
}[1]

View file

@ -25,20 +25,20 @@ function ca_herding_sheep_runs_enemy:evaluation(ai, cfg)
end
function ca_herding_sheep_runs_enemy:execution(ai, cfg)
-- Simply start with the first of the sheep, order does not matter
-- Simply start with the first sheep, order does not matter
local sheep = get_next_sheep(cfg)
-- And find the close enemies
local enemies = wesnoth.get_units {
{ "filter_side", {{"enemy_of", {side = wesnoth.current.side} }} },
{ "filter_side", { { "enemy_of", { side = wesnoth.current.side } } } },
{ "filter_location", { x = sheep.x, y = sheep.y , radius = (cfg.attention_distance or 8) } }
}
--print('#enemies', #enemies)
-- Maximize distance between sheep and enemies
local best_hex = AH.find_best_move(sheep, function(x, y)
local rating = 0
for i,e in ipairs(enemies) do rating = rating + H.distance_between(x, y, e.x, e.y) end
for _,enemy in ipairs(enemies) do
rating = rating + H.distance_between(x, y, enemy.x, enemy.y)
end
return rating
end)

View file

@ -83,7 +83,7 @@ function ca_patrol:execution(ai, cfg)
MAIUV.set_mai_unit_variables(patrol, cfg.ai_id, patrol_vars)
local tmp_wp = {}
for j,wp in ipairs(waypoints) do tmp_wp[n_wp-j+1] = wp end
for j,wp2 in ipairs(waypoints) do tmp_wp[n_wp-j+1] = wp2 end
waypoints = tmp_wp
else
patrol_vars.patrol_x = waypoints[1][1]

View file

@ -1,7 +1,6 @@
local AH = wesnoth.require("ai/lua/ai_helper.lua")
local internal_recruit_cas = {}
local internal_params = {}
-- The following external engine creates the CA functions recruit_rushers_eval and recruit_rushers_exec
-- It also exposes find_best_recruit and find_best_recruit_hex for use by other recruit engines

View file

@ -22,7 +22,7 @@ function ca_simple_attack:evaluation(ai, cfg, self)
if (not enemies[1]) then return 0 end
enemy_map = LS.create()
for _,e in ipairs(enemies) do enemy_map:insert(e.x, e.y) end
for _,enemy in ipairs(enemies) do enemy_map:insert(enemy.x, enemy.y) end
end
-- Now find the best of the possible attacks

View file

@ -38,13 +38,13 @@ function ca_stationed_guardian:execution(ai, cfg)
-- Enemies must be within cfg.distance of guardian, (s_x, s_y) *and* (g_x, g_y)
-- simultaneously for guardian to attack
local target, min_dist = {}, 9e99
for _,e in ipairs(enemies) do
local dist_s = H.distance_between(cfg.station_x, cfg.station_y, e.x, e.y)
local dist_g = H.distance_between(cfg.guard_x, cfg.guard_y, e.x, e.y)
for _,enemy in ipairs(enemies) do
local dist_s = H.distance_between(cfg.station_x, cfg.station_y, enemy.x, enemy.y)
local dist_g = H.distance_between(cfg.guard_x, cfg.guard_y, enemy.x, enemy.y)
-- If valid target found, save the one with the shortest distance from (g_x, g_y)
if (dist_s <= cfg.distance) and (dist_g <= cfg.distance) and (dist_g < min_dist) then
target, min_dist = e, dist_g
target, min_dist = enemy, dist_g
end
end
@ -53,15 +53,15 @@ function ca_stationed_guardian:execution(ai, cfg)
-- Find tiles adjacent to the target
-- Save the one with the highest defense rating that guardian can reach
local best_defense, attack_loc = -9e99, {}
for x,y in H.adjacent_tiles(target.x, target.y) do
for xa,ya in H.adjacent_tiles(target.x, target.y) do
-- Only consider unoccupied hexes
local occ_hex = wesnoth.get_units { x = x, y = y, { "not", { id = guardian.id } } }[1]
local occ_hex = wesnoth.get_units { x = xa, y = ya, { "not", { id = guardian.id } } }[1]
if not occ_hex then
local defense = 100 - wesnoth.unit_defense(guardian, wesnoth.get_terrain(x, y))
local nh = AH.next_hop(guardian, x, y)
local defense = 100 - wesnoth.unit_defense(guardian, wesnoth.get_terrain(xa, ya))
local nh = AH.next_hop(guardian, xa, ya)
if nh then
if (nh[1] == x) and (nh[2] == y) and (defense > best_defense) then
best_defense, attack_loc = defense, {x, y}
if (nh[1] == xa) and (nh[2] == ya) and (defense > best_defense) then
best_defense, attack_loc = defense, { xa, ya }
end
end
end
@ -80,13 +80,13 @@ function ca_stationed_guardian:execution(ai, cfg)
-- Go through all hexes the guardian can reach, find closest to target
-- Cannot use next_hop here since target hex is occupied by enemy
local nh, min_dist = {}, 9e99
for _,r in ipairs(reach) do
for _,hex in ipairs(reach) do
-- Only consider unoccupied hexes
local occ_hex = wesnoth.get_units { x = r[1], y = r[2], { "not", { id = guardian.id } } }[1]
local occ_hex = wesnoth.get_units { x = hex[1], y = hex[2], { "not", { id = guardian.id } } }[1]
if not occ_hex then
local dist = H.distance_between(r[1], r[2], target.x, target.y)
local dist = H.distance_between(hex[1], hex[2], target.x, target.y)
if (dist < min_dist) then
min_dist, nh = d, { r[1], r[2] }
min_dist, nh = dist, { hex[1], hex[2] }
end
end
end

View file

@ -5,8 +5,8 @@ local ca_swarm_move = {}
function ca_swarm_move:evaluation(ai, cfg)
local units = wesnoth.get_units { side = wesnoth.current.side }
for _,u in ipairs(units) do
if (u.moves > 0) then return cfg.ca_score end
for _,unit in ipairs(units) do
if (unit.moves > 0) then return cfg.ca_score end
end
return 0
@ -19,11 +19,11 @@ function ca_swarm_move:execution(ai, cfg)
-- If no close enemies, swarm will move semi-randomly, staying close together, but away from enemies
local all_units = wesnoth.get_units { side = wesnoth.current.side }
local units, units_no_moves = {}, {}
for _,u in ipairs(all_units) do
if (u.moves > 0) then
table.insert(units, u)
for _,unit in ipairs(all_units) do
if (unit.moves > 0) then
table.insert(units, unit)
else
table.insert(units_no_moves, u)
table.insert(units_no_moves, unit)
end
end
@ -40,9 +40,9 @@ function ca_swarm_move:execution(ai, cfg)
-- Only units within 'vision_distance' count for rejoining
local close_units_no_moves = {}
for _,u in ipairs(units_no_moves) do
if (H.distance_between(unit.x, unit.y, u.x, u.y) <= vision_distance) then
table.insert(close_units_no_moves, u)
for _,unit_noMP in ipairs(units_no_moves) do
if (H.distance_between(unit.x, unit.y, unit_noMP.x, unit_noMP.y) <= vision_distance) then
table.insert(close_units_no_moves, unit_noMP)
end
end
@ -50,14 +50,14 @@ function ca_swarm_move:execution(ai, cfg)
if (not close_units_no_moves[1]) then
rating = rating + H.distance_between(x, y, unit.x, unit.y)
else -- Otherwise, minimize distance from units that have already moved
for _,u in ipairs(close_units_no_moves) do
rating = rating - H.distance_between(x, y, u.x, u.y)
for _,close_unit in ipairs(close_units_no_moves) do
rating = rating - H.distance_between(x, y, close_unit.x, close_unit.y)
end
end
-- We also try to stay out of attack range of any enemy
for _,e in ipairs(enemies) do
local dist = H.distance_between(x, y, e.x, e.y)
for _,enemy in ipairs(enemies) do
local dist = H.distance_between(x, y, enemy.x, enemy.y)
if (dist < enemy_distance) then
rating = rating - (enemy_distance - dist) * 10.
end

View file

@ -33,17 +33,17 @@ function ca_swarm_scatter:execution(ai, cfg)
-- but only for units that are within 'vision_distance' of one of those enemies
for _,unit in ipairs(units) do
local unit_enemies = {}
for _,e in ipairs(enemies) do
if (H.distance_between(unit.x, unit.y, e.x, e.y) <= vision_distance) then
table.insert(unit_enemies, e)
for _,enemy in ipairs(enemies) do
if (H.distance_between(unit.x, unit.y, enemy.x, enemy.y) <= vision_distance) then
table.insert(unit_enemies, enemy)
end
end
if unit_enemies[1] then
local best_hex = AH.find_best_move(unit, function(x, y)
local rating = 0
for _,e in ipairs(unit_enemies) do
rating = rating + H.distance_between(x, y, e.x, e.y)
for _,enemy in ipairs(unit_enemies) do
rating = rating + H.distance_between(x, y, enemy.x, enemy.y)
end
return rating
end)

View file

@ -1,7 +1,6 @@
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 function get_wolves(cfg)
local wolves = AH.get_units_with_moves {
@ -31,50 +30,44 @@ function ca_wolves_move:execution(ai, cfg)
local wolves = get_wolves(cfg)
local prey = get_prey(cfg)
-- When wandering (later) they avoid dogs, but not here
local avoid_units = wesnoth.get_units { type = cfg.avoid_type,
{ "filter_side", {{"enemy_of", {side = wesnoth.current.side} }} }
{ "filter_side", { { "enemy_of", { side = wesnoth.current.side } } } }
}
--print('#avoid_units', #avoid_units)
-- negative hit for hexes these types of units can attack
local avoid = BC.get_attack_map(avoid_units).units -- max_moves=true is always set for enemy units
local avoid_map = BC.get_attack_map(avoid_units).units
-- Find prey that is closest to all 3 wolves
local target, min_dist = {}, 9999
for i,p in ipairs(prey) do
-- Find prey that is closest to the wolves
local target, min_dist = {}, 9e99
for _,prey_unit in ipairs(prey) do
local dist = 0
for j,w in ipairs(wolves) do
dist = dist + H.distance_between(w.x, w.y, p.x, p.y)
for _,wolf in ipairs(wolves) do
dist = dist + H.distance_between(wolf.x, wolf.y, prey_unit.x, prey_unit.y)
end
if (dist < min_dist) then
min_dist, target = dist, p
min_dist, target = dist, prey_unit
end
end
--print('target:', target.x, target.y, target.id)
-- Now sort wolf from furthest to closest
-- Now sort wolf from farthest to closest
table.sort(wolves, function(a, b)
return H.distance_between(a.x, a.y, target.x, target.y) > H.distance_between(b.x, b.y, target.x, target.y)
end)
-- First wolf moves toward target, but tries to stay away from map edges
local w,h,b = wesnoth.get_map_size()
local width, height = wesnoth.get_map_size()
local wolf1 = AH.find_best_move(wolves[1], function(x, y)
local d_1t = H.distance_between(x, y, target.x, target.y)
local rating = -d_1t
if x <= 5 then rating = rating - (6 - x) / 1.4 end
if y <= 5 then rating = rating - (6 - y) / 1.4 end
if (w - x) <= 5 then rating = rating - (6 - (w - x)) / 1.4 end
if (h - y) <= 5 then rating = rating - (6 - (h - y)) / 1.4 end
local dist_1t = H.distance_between(x, y, target.x, target.y)
local rating = - dist_1t
if (x <= 5) then rating = rating - (6 - x) / 1.4 end
if (y <= 5) then rating = rating - (6 - y) / 1.4 end
if (width - x <= 5) then rating = rating - (6 - (width - x)) / 1.4 end
if (height - y <= 5) then rating = rating - (6 - (height - y)) / 1.4 end
-- Hexes that avoid_type units can reach get a massive negative hit
-- meaning that they will only ever be chosen if there's no way around them
if avoid:get(x, y) then rating = rating - 1000 end
-- Hexes that avoid_type units can reach get a massive penalty
if avoid_map:get(x, y) then rating = rating - 1000 end
return rating
end)
--print('wolf 1 ->', wolves[1].x, wolves[1].y, wolf1[1], wolf1[2])
--W.message { speaker = wolves[1].id, message = "Me first"}
AH.movefull_stopunit(ai, wolves[1], wolf1)
for i = 2,#wolves do
@ -89,13 +82,12 @@ function ca_wolves_move:execution(ai, cfg)
end
-- Same distance from Wolf 1 and target for all the wolves
local dst_t = H.distance_between(x, y, target.x, target.y)
local dst_1t = H.distance_between(wolf1[1], wolf1[2], target.x, target.y)
rating = rating - (dst_t - dst_1t)^2
local dist_t = H.distance_between(x, y, target.x, target.y)
local dist_1t = H.distance_between(wolf1[1], wolf1[2], target.x, target.y)
rating = rating - (dist_t - dist_1t)^2
-- Hexes that avoid_type units can reach get a massive negative hit
-- meaning that they will only ever be chosen if there's no way around them
if avoid:get(x, y) then rating = rating - 1000 end
-- Hexes that avoid_type units can reach get a massive penalty
if avoid_map:get(x, y) then rating = rating - 1000 end
return rating
end)

View file

@ -24,23 +24,20 @@ function ca_wolves_wander:execution(ai, cfg)
-- Number of wolves that can reach each hex
local reach_map = LS.create()
for i,w in ipairs(wolves) do
local r = AH.get_reachable_unocc(w)
for _,wolf in ipairs(wolves) do
local r = AH.get_reachable_unocc(wolf)
reach_map:union_merge(r, function(x, y, v1, v2) return (v1 or 0) + (v2 or 0) end)
end
-- Add a random rating; avoid avoid_type units
local avoid_units = wesnoth.get_units { type = cfg.avoid_type,
{ "filter_side", {{"enemy_of", {side = wesnoth.current.side} }} }
{ "filter_side", { { "enemy_of", { side = wesnoth.current.side } } } }
}
--print('#avoid_units', #avoid_units)
-- negative hit for hexes these units can attack
local avoid = BC.get_attack_map(avoid_units).units
local avoid_map = BC.get_attack_map(avoid_units).units
local max_rating, goal_hex = -9e99, {}
reach_map:iter( function (x, y, v)
local rating = v + math.random(99)/100.
if avoid:get(x, y) then rating = rating - 1000 end
if avoid_map:get(x, y) then rating = rating - 1000 end
if (rating > max_rating) then
max_rating, goal_hex = rating, { x, y }
@ -48,17 +45,16 @@ function ca_wolves_wander:execution(ai, cfg)
reach_map:insert(x, y, rating)
end)
--AH.put_labels(reach_map)
--W.message { speaker = 'narrator', message = "Wolves random wander"}
for i,w in ipairs(wolves) do
for _,wolf in ipairs(wolves) do
-- For each wolf, we need to check that goal hex is reachable, and out of harm's way
local best_hex = AH.find_best_move(w, function(x, y)
local best_hex = AH.find_best_move(wolf, function(x, y)
local rating = - H.distance_between(x, y, goal_hex[1], goal_hex[2])
if avoid:get(x, y) then rating = rating - 1000 end
if avoid_map:get(x, y) then rating = rating - 1000 end
return rating
end)
AH.movefull_stopunit(ai, w, best_hex)
AH.movefull_stopunit(ai, wolf, best_hex)
end
end

View file

@ -29,10 +29,10 @@ function ca_zone_guardian:execution(ai, cfg)
}
if enemies[1] then
local target, min_dist = {}, 9e99
for _,e in ipairs(enemies) do
local dist = H.distance_between(guardian.x, guardian.y, e.x, e.y)
for _,enemy in ipairs(enemies) do
local dist = H.distance_between(guardian.x, guardian.y, enemy.x, enemy.y)
if (dist < min_dist) then
target, min_dist = e, dist
target, min_dist = enemy, dist
end
end
@ -41,15 +41,15 @@ function ca_zone_guardian:execution(ai, cfg)
-- Find tiles adjacent to the target
-- Save the one with the highest defense rating that guardian can reach
local best_defense, attack_loc = -9e99, {}
for x,y in H.adjacent_tiles(target.x, target.y) do
for xa,ya in H.adjacent_tiles(target.x, target.y) do
-- Only consider unoccupied hexes
local occ_hex = wesnoth.get_units { x = x, y = y, { "not", { id = guardian.id } } }[1]
local occ_hex = wesnoth.get_units { x = xa, y = ya, { "not", { id = guardian.id } } }[1]
if not occ_hex then
local defense = 100 - wesnoth.unit_defense(guardian, wesnoth.get_terrain(x, y))
local nh = AH.next_hop(guardian, x, y)
local defense = 100 - wesnoth.unit_defense(guardian, wesnoth.get_terrain(xa, ya))
local nh = AH.next_hop(guardian, xa, ya)
if nh then
if (nh[1] == x) and (nh[2] == y) and (defense > best_defense) then
best_defense, attack_loc = defense, { x, y }
if (nh[1] == xa) and (nh[2] == ya) and (defense > best_defense) then
best_defense, attack_loc = defense, { xa, ya }
end
end
end
@ -68,13 +68,13 @@ function ca_zone_guardian:execution(ai, cfg)
-- Go through all hexes the guardian can reach, find closest to target
-- Cannot use next_hop here since target hex is occupied by enemy
local nh, min_dist = {}, 9e99
for _,r in ipairs(reach) do
for _,hex in ipairs(reach) do
-- Only consider unoccupied hexes
local occ_hex = wesnoth.get_units { x = r[1], y = r[2], { "not", { id = guardian.id } } }[1]
local occ_hex = wesnoth.get_units { x = hex[1], y = hex[2], { "not", { id = guardian.id } } }[1]
if not occ_hex then
local dist = H.distance_between(r[1], r[2], target.x, target.y)
local dist = H.distance_between(hex[1], hex[2], target.x, target.y)
if (dist < min_dist) then
min_dist, nh = dist, { r[1], r[2] }
min_dist, nh = dist, { hex[1], hex[2] }
end
end
end

View file

@ -44,8 +44,11 @@ flg_manager::flg_manager(const std::vector<const config*>& era_factions,
side_(side),
lock_settings_(lock_settings),
saved_game_(saved_game),
has_no_recruits_((side_.has_attribute("default_recruit") ?
side_["default_recruit"].empty() : side_["recruit"].empty()) &&
has_no_recruits_(
((side_.has_attribute("default_recruit") ?
side_["default_recruit"].empty() :
side_["recruit"].empty()) ||
side_["no_recruit"].to_bool()) &&
side_["previous_recruits"].empty() && side_["extra_recruit"].empty()),
color_(color),
available_factions_(),

View file

@ -203,7 +203,7 @@ public:
{
model_.clear_stuff_list();
const config& vars = resources::state_of_game
const config& vars = resources::gamedata
? resources::gamedata->get_variables()
: config();
@ -229,7 +229,7 @@ public:
}
int i = 0; ///@todo replace with precached data
const config& vars = resources::state_of_game
const config& vars = resources::gamedata
? resources::gamedata->get_variables()
: config();

View file

@ -49,6 +49,8 @@ const std::string controller_names[] = {
const std::string attributes_to_trim[] = {
"side",
"type",
"gender",
"recruit",
"extra_recruit",
"previous_recruits",
@ -919,7 +921,11 @@ config side_engine::new_config() const
// Save default "recruit" so that correct faction lists would be
// initialized by flg_manager when the new side config is sent over network.
// In case recruit list was empty, set a flag to indicate that.
res["default_recruit"] = cfg_["recruit"];
if (res["default_recruit"].empty()) {
res["no_recruit"] = true;
}
// If the user is allowed to change type, faction, leader etc,
// then import their new values in the config.

View file

@ -310,12 +310,12 @@ void wait::join_game(bool observe)
era_factions.push_back(&side);
}
const bool map_settings =
level_.child("multiplayer")["mp_use_map_settings"].to_bool();
const bool lock_settings =
level_["force_lock_settings"].to_bool();
const bool saved_game =
level_.child("multiplayer")["savegame"].to_bool();
flg_manager flg(era_factions, *side_choice, map_settings,
flg_manager flg(era_factions, *side_choice, lock_settings,
saved_game, color);
std::vector<std::string> choices;

View file

@ -53,7 +53,7 @@ controller::controller(display& disp, const vconfig& data, const std::string& sc
, segment_index_(segment_index)
, parts_()
{
ASSERT_LOG(resources::state_of_game != NULL, "Ouch: gamestate is NULL when initializing storyscreen controller");
ASSERT_LOG(resources::gamedata != NULL, "Ouch: gamedata is NULL when initializing storyscreen controller");
resolve_wml(data);
}

View file

@ -45,7 +45,7 @@ namespace
* @todo FIXME: the variable repository should be
* a class of variable.hpp, and not the game_state.
*/
#define repos (resources::state_of_game)
#define repos (resources::gamedata)
}