1local LS = wesnoth.require "location_set" 2local AH = wesnoth.require "ai/lua/ai_helper.lua" 3 4local function get_lurker(cfg) 5 -- We simply pick the first of the lurkers, they have no strategy 6 local lurker = AH.get_units_with_moves { 7 side = wesnoth.current.side, 8 { "and", wml.get_child(cfg, "filter") } 9 }[1] 10 return lurker 11end 12 13local ca_lurkers = {} 14 15function ca_lurkers:evaluation(cfg) 16 if get_lurker(cfg) then return cfg.ca_score end 17 return 0 18end 19 20function ca_lurkers:execution(cfg) 21 local lurker = get_lurker(cfg) 22 local targets = AH.get_attackable_enemies() 23 24 -- Sort targets by hitpoints (lurkers choose lowest HP target) 25 table.sort(targets, function(a, b) return (a.hitpoints < b.hitpoints) end) 26 27 local reach = LS.of_pairs(wesnoth.find_reach(lurker.x, lurker.y)) 28 local lurk_area = wml.get_child(cfg, "filter_location") 29 local reachable_attack_terrain = 30 LS.of_pairs(wesnoth.get_locations { 31 { "and", { x = lurker.x, y = lurker.y, radius = lurker.moves } }, 32 { "and", lurk_area } 33 }) 34 reachable_attack_terrain:inter(reach) 35 36 -- Need to restrict that to reachable and not occupied by an ally (except own position) 37 local reachable_attack_terrain = reachable_attack_terrain:filter(function(x, y, v) 38 local occ_hex = AH.get_visible_units(wesnoth.current.side, { 39 x = x, y = y, 40 { "not", { x = lurker.x, y = lurker.y } } 41 })[1] 42 return not occ_hex 43 end) 44 45 -- Attack the weakest reachable enemy 46 for _,target in ipairs(targets) do 47 -- Get reachable attack terrain next to target unit 48 local reachable_attack_terrrain_adj_target = LS.of_pairs( 49 wesnoth.get_locations { x = target.x, y = target.y, radius = 1 } 50 ) 51 reachable_attack_terrrain_adj_target:inter(reachable_attack_terrain) 52 53 -- Since enemies are sorted by hitpoints, we can simply attack the first enemy found 54 if reachable_attack_terrrain_adj_target:size() > 0 then 55 local rand = math.random(1, reachable_attack_terrrain_adj_target:size()) 56 local dst = reachable_attack_terrrain_adj_target:to_stable_pairs() 57 58 AH.robust_move_and_attack(ai, lurker, dst[rand], target) 59 return 60 end 61 end 62 63 -- If we got here, unit did not attack: go to random wander terrain hex 64 if (lurker.moves > 0) and (not cfg.stationary) then 65 local reachable_wander_terrain = 66 LS.of_pairs( wesnoth.get_locations { 67 { "and", { x = lurker.x, y = lurker.y, radius = lurker.moves } }, 68 { "and", wml.get_child(cfg, "filter_location_wander") or lurk_area } 69 }) 70 reachable_wander_terrain:inter(reach) 71 72 -- Need to restrict that to reachable and not occupied by an ally (except own position) 73 local reachable_wander_terrain = reachable_wander_terrain:filter(function(x, y, v) 74 local occ_hex = AH.get_visible_units(wesnoth.current.side, { 75 x = x, y = y, 76 { "not", { x = lurker.x, y = lurker.y } } 77 })[1] 78 return not occ_hex 79 end) 80 81 if (reachable_wander_terrain:size() > 0) then 82 local dst = reachable_wander_terrain:to_stable_pairs() 83 local rand = math.random(1, reachable_wander_terrain:size()) 84 AH.movefull_stopunit(ai, lurker, dst[rand]) 85 return 86 end 87 end 88 89 -- If the unit has moves or attacks left at this point, take them away 90 AH.checked_stopunit_all(ai, lurker) 91end 92 93return ca_lurkers 94