-
-
Notifications
You must be signed in to change notification settings - Fork 991
/
ca_recruit_random.lua
129 lines (110 loc) · 4.61 KB
/
ca_recruit_random.lua
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
local H = wesnoth.require "helper"
local AH = wesnoth.require("ai/lua/ai_helper.lua")
local LS = wesnoth.require "location_set"
local recruit_type
local ca_recruit_random = {}
function ca_recruit_random:evaluation(cfg)
-- Random recruiting from all the units the side has
local map = wesnoth.map.get()
-- Check if leader is on keep
local leader = wesnoth.units.find_on_map { side = wesnoth.current.side, canrecruit = 'yes' }[1]
if (not leader) or (not wesnoth.get_terrain_info(map:get_terrain(leader.x, leader.y)).keep) then
return 0
end
-- Find all connected castle hexes
local castle_map = LS.of_pairs({ { leader.x, leader.y } })
local width, height, border = wesnoth.get_map_size()
local new_castle_hex_found = true
while new_castle_hex_found do
new_castle_hex_found = false
local new_hexes = {}
castle_map:iter(function(x, y)
for xa,ya in H.adjacent_tiles(x, y) do
if (not castle_map:get(xa, ya))
and (xa >= 1) and (xa <= width)
and (ya >= 1) and (ya <= height)
then
local is_castle = wesnoth.get_terrain_info(map:get_terrain(xa, ya)).castle
if is_castle then
table.insert(new_hexes, { xa, ya })
new_castle_hex_found = true
end
end
end
end)
for _,hex in ipairs(new_hexes) do
castle_map:insert(hex[1], hex[2])
end
end
-- Check if there is space left for recruiting
local no_space = true
castle_map:iter(function(x, y)
local unit = wesnoth.units.get(x, y)
if (not unit) then
no_space = false
end
end)
if no_space then return 0 end
-- Set up the probability array
local probabilities, probability_sum = {}, 0
-- Go through all the types listed in [probability] tags (which can be comma-separated lists)
for prob in wml.child_range(cfg, "probability") do
types = AH.split(prob.type, ",")
for _,typ in ipairs(types) do -- 'type' is a reserved keyword in Lua
-- If this type is in the recruit list, add it
for _,recruit in ipairs(wesnoth.sides[wesnoth.current.side].recruit) do
if (recruit == typ) then
probabilities[typ] = { value = prob.probability }
probability_sum = probability_sum + prob.probability
break
end
end
end
end
-- Now we add in all the unit types not listed in [probability] tags
for _,recruit in ipairs(wesnoth.sides[wesnoth.current.side].recruit) do
if (not probabilities[recruit]) then
probabilities[recruit] = { value = 1 }
probability_sum = probability_sum + 1
end
end
-- Now eliminate all those that are too expensive (unless cfg.skip_low_gold_recruiting is set)
if cfg.skip_low_gold_recruiting then
for typ,probability in pairs(probabilities) do -- 'type' is a reserved keyword in Lua
if (wesnoth.unit_types[typ].cost > wesnoth.sides[wesnoth.current.side].gold) then
probability_sum = probability_sum - probability.value
probabilities[typ] = nil
end
end
end
-- Now set up the cumulative probability values for each type
-- Both min and max need to be set as the order of pairs() is not guaranteed
local cum_prob = 0
for typ,probability in pairs(probabilities) do
probabilities[typ].p_i = cum_prob
cum_prob = cum_prob + probability.value
probabilities[typ].p_f = cum_prob
end
-- We always call the exec function, no matter if the selected unit is affordable
-- The point is that this will blacklist the CA if an unaffordable recruit was
-- chosen -> no cheaper recruits will be selected in subsequent calls
if (cum_prob > 0) then
local rand_prob = math.random(cum_prob)
for typ,probability in pairs(probabilities) do
if (probability.p_i < rand_prob) and (rand_prob <= probability.p_f) then
recruit_type = typ
break
end
end
else
recruit_type = wesnoth.sides[wesnoth.current.side].recruit[1]
end
return cfg.ca_score
end
function ca_recruit_random:execution(cfg)
-- Let this function blacklist itself if the chosen recruit is too expensive
if wesnoth.unit_types[recruit_type].cost <= wesnoth.sides[wesnoth.current.side].gold then
AH.checked_recruit(ai, recruit_type)
end
end
return ca_recruit_random