1 /*
2  * Copyright (C) 2004-2020 by the Widelands Development Team
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License
6  * as published by the Free Software Foundation; either version 2
7  * of the License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
17  *
18  */
19 
20 #include "ai/ai_hints.h"
21 
22 #include <memory>
23 
24 /* RST
25 AI Hints and Restrictions
26 =========================
27 
28 Every :doc:`building <autogen_toc_lua_tribes_buildings>`'s ``init.lua`` file has an ``aihints``
29 table in its ``new_<building_type>_type{table}`` function. This ``aihints`` table can contain any
30 number of entries, which will help the AI decide when and where to build or dismantle a building of
31 that type and/or how to treat it.
32 
33 All entries in ``aihints`` are optional.
34 
35 - :ref:`ai_hints_introduction`
36 - :ref:`ai_hints_common`
37 - :ref:`ai_hints_military`
38 - :ref:`ai_hints_production`
39 
40 .. _ai_hints_introduction:
41 
42 Introduction
43 ------------
44 
45 The AI has separate code paths for various building categories. Many of them are
46 categories that contain one unique building (ranger, well, port, fish breeder,
47 barracks and so on), and these cannot be combined with other types of buildings
48 and are mostly mandatory.
49 
50 The main categories where you can freely modify and add buildings are:
51 
52 - Military sites
53 - Training sites
54 - Pure production sites (they have outputs, and optionally inputs, but no production hints)
55 - Pure supporters (they have production hints, but neither inputs nor outputs)
56 - A combination of supporter and production site is possible, but suboptimal
57 
58 You can create as many building types as you want in these main categories, but
59 make sure that you don't combine any incompatible features (for example,
60 ``shipyard`` and ``mines`` don't combine).
61 
62 With the exception of the barracks and the building that produces carrier2
63 (see: :ref:`lua_tribes_<tribename>.lua`), production of workers in production sites
64 is not supported at this time.
65 
66 .. _ai_hints_common:
67 
68 Common Building Hints
69 ---------------------
70 
71 **basic_amount**
72     The amount of this building to be built while establishing a basic economy, e.g.::
73 
74         basic_amount = 1,
75 
76 **forced_after**
77     If a building of this type hasn't been built already, force that a building
78     of this type will be constructed after the given time (in seconds) has elapsed,
79     e.g.::
80 
81         forced_after = 890,
82 
83     **Note:** ``forced after`` can interfere with setting up the basic economy
84     defined by ``basic_amount``: if we don't want the building to be part of the
85     basic economy but it is forced before all the buildings for the basic economy
86     have been built, this can lead to unobvious behavior. Part of this ambiguity
87     is due to the genetic algorithm.
88 
89 **prohibited_till**
90     Do not build this building before the given time (in seconds) has elapsed, e.g.::
91 
92         prohibited_till = 1500,
93 
94     This takes precedence over ``basic_amount``, so it means it can delay achieving
95     the basic economy.
96 
97 **very_weak_ai_limit**
98     The maximum number of this building type that the very weak AI is allowed to build, e.g.::
99 
100         very_weak_ai_limit = 1,
101 
102 **weak_ai_limit_**
103     The maximum number of this building type that the weak AI is allowed to build, e.g.::
104 
105         weak_ai_limit_ = 2,
106 
107 .. _ai_hints_military:
108 
109 Military Sites
110 --------------
111 
112 **expansion**
113     The building will be used by the AI for expanding the territory, e.g.::
114 
115         expansion = true,
116 
117     **Note:** It is recommended to have at least one building has this feature.
118 
119 **fighting**
120     The building is suitable for military conflicts, e.g.::
121 
122         fighting = true,
123 
124     **Note:** It is recommended to have at least one building has this feature.
125 
126 **mountain_conqueror**
127     Prefer this type of military site near mountains, e.g.::
128 
129         mountain_conqueror = true,
130 
131     **Note:** It is recommended to have at least one building has this feature.
132 
133 .. _ai_hints_production:
134 
135 Production Sites
136 ----------------
137 
138 **collects_ware_from_map**
139     The building will generate this ware from the map, e.g. a well mining the ``water`` ware,
140     or the hunter returning from the hunt with the ``meat`` ware. The same ware needs also to be
141     listed as the first one of the building's outputs, e.g.::
142 
143         aihints = {
144             collects_ware_from_map = "meat"
145         },
146 
147         outputs = {
148             "meat",
149             "fur"
150         },
151 
152     **Note:** The AI expects exactly one such building type for each of the following wares:
153     ``fish`` (fisher), ``granite`` (quarry), ``log`` (lumberjack/woodcutter), ``meat`` (hunter),
154     ``water`` (well).
155 
156 **mines**
157     The building will mine to obtain the given ware, e.g.::
158 
159         mines = "gold",
160 
161 **mines_percent**
162     The percentage that a mine will mine of its resource before it needs enhancing, e.g.::
163 
164         mines_percent = 60,
165 
166 **needs_water**
167     The building needs to be placed near a body of water, e.g.::
168 
169         needs_water = true,
170 
171     **Note:** The AI expects exactly one such building type.
172 
173 **recruitment**
174     The building will recruit the tribe's carrier2, for example oxen or horses, e.g.::
175 
176         recruitment = true,
177 
178 **shipyard**
179     This building will construct ships, e.g.::
180 
181         shipyard = true,
182 
183     **Note:** The AI expects exactly one such building type.
184 
185 **supports_seafaring**
186     This building is needed for expedition and seafaring, e.g.::
187 
188         supports_seafaring = true,
189 
190 **space_consumer**
191     The building needs a lot of space around it, for example a farm needs space for
192     its fields, e.g.::
193 
194         space_consumer = true,
195 
196 **supports_production_of**
197     This building will support the production of the given wares without producing
198     it directly, e.g.::
199 
200         supports_production_of = { "fish" },
201 
202     For example, if a building supports the production of fish, it should be placed
203     near a building that has fish in its output.
204 
205     **Note:** The AI expects that supporters will have no inputs and no outputs. Although
206     the AI can tolerate such buildings, they will be primarily treated as normal
207     production sites when deciding on the building's location.
208 
209 **requires_supporters**
210     This building will be built only if a supporter is nearby::
211 
212         requires_supporters = true,
213 
214     For example if set for lumberjack, it will be built only if a renger is nearby.
215 
216 **trainingsites_max_percent**
217     The maximum percengate this training site will have among all training sites, e.g.::
218 
219         trainingsites_max_percent = 20,
220 
221     In this example, if an AI has built 5 training sites, it will have a maximum of
222     1 site of this type. If it has built 10 training sites, the maximum is 2.
223     For training sites that don't have this value set, their percentage will be
224     distributed evenly.
225 
226 */
227 
BuildingHints(std::unique_ptr<LuaTable> table)228 BuildingHints::BuildingHints(std::unique_ptr<LuaTable> table)
229    : mines_(table->has_key("mines") ? table->get_string("mines") : ""),
230      needs_water_(table->has_key("needs_water") ? table->get_bool("needs_water") : false),
231      space_consumer_(table->has_key("space_consumer") ? table->get_bool("space_consumer") : false),
232      expansion_(table->has_key("expansion") ? table->get_bool("expansion") : false),
233      fighting_(table->has_key("fighting") ? table->get_bool("fighting") : false),
234      mountain_conqueror_(
235         table->has_key("mountain_conqueror") ? table->get_bool("mountain_conqueror") : false),
236      shipyard_(table->has_key("shipyard") ? table->get_bool("shipyard") : false),
237      supports_seafaring_(
238         table->has_key("supports_seafaring") ? table->get_bool("supports_seafaring") : false),
239      collects_ware_from_map_(table->has_key("collects_ware_from_map") ?
240                                 table->get_string("collects_ware_from_map") :
241                                 ""),
242      prohibited_till_(table->has_key("prohibited_till") ? table->get_int("prohibited_till") : 0),
243      basic_amount_(table->has_key("basic_amount") ? table->get_int("basic_amount") : 0),
244      // 10 days default
245      forced_after_(table->has_key("forced_after") ? table->get_int("forced_after") : 864000),
246      mines_percent_(table->has_key("mines_percent") ? table->get_int("mines_percent") : 100),
247      very_weak_ai_limit_(
248         table->has_key("very_weak_ai_limit") ? table->get_int("very_weak_ai_limit") : -1),
249      weak_ai_limit_(table->has_key("weak_ai_limit") ? table->get_int("weak_ai_limit") : -1),
250      normal_ai_limit_(table->has_key("normal_ai_limit") ? table->get_int("normal_ai_limit") : -1),
251      requires_supporters_(
252         table->has_key("requires_supporters") ? table->get_bool("requires_supporters") : false),
253      trainingsites_max_percent_(table->has_key("trainingsites_max_percent") ?
254                                    table->get_int("trainingsites_max_percent") :
255                                    0) {
256 	if (table->has_key("supports_production_of")) {
257 		for (const std::string& ware_name :
258 		     table->get_table("supports_production_of")->array_entries<std::string>()) {
259 			supported_production_.insert(ware_name);
260 		}
261 	}
262 }
263 
set_trainingsites_max_percent(int percent)264 void BuildingHints::set_trainingsites_max_percent(int percent) {
265 	trainingsites_max_percent_ = percent;
266 }
267 
trainingsites_max_percent() const268 uint8_t BuildingHints::trainingsites_max_percent() const {
269 	return trainingsites_max_percent_;
270 }
271 
get_ai_limit(const Widelands::AiType ai_type) const272 int16_t BuildingHints::get_ai_limit(const Widelands::AiType ai_type) const {
273 	switch (ai_type) {
274 	case Widelands::AiType::kVeryWeak:
275 		return very_weak_ai_limit_;
276 	case Widelands::AiType::kWeak:
277 		return weak_ai_limit_;
278 	case Widelands::AiType::kNormal:
279 		return normal_ai_limit_;
280 	}
281 	NEVER_HERE();
282 }
283 
284 // TODO(GunChleoc): WareDescr has a bare "preciousness" table that should be moved below a new
285 // "aihints" table.
read_preciousness(const std::string & name,const LuaTable & table)286 void WareWorkerHints::read_preciousness(const std::string& name, const LuaTable& table) {
287 	constexpr int kMaxRecommendedPreciousness = 50;
288 	for (const std::string& key : table.keys<std::string>()) {
289 		const int value = table.get_int(key);
290 		if (value > 200) {
291 			throw wexception("Preciousness of %d is far too high for ware/worker '%s' and tribe '%s'. "
292 			                 "We recommend not going over %d.",
293 			                 value, name.c_str(), key.c_str(), kMaxRecommendedPreciousness);
294 		} else if (value > kMaxRecommendedPreciousness) {
295 			log("WARNING: Preciousness of %d is a bit high for ware/worker '%s' and tribe '%s'. We "
296 			    "recommend not going over %d.\n",
297 			    value, name.c_str(), key.c_str(), kMaxRecommendedPreciousness);
298 		}
299 
300 		preciousnesses_.insert(std::make_pair(key, value));
301 	}
302 }
303 
304 /// Returns the preciousness of the ware, or kInvalidWare if the tribe doesn't use the ware.
preciousness(const std::string & tribename) const305 int WareWorkerHints::preciousness(const std::string& tribename) const {
306 	if (preciousnesses_.count(tribename) > 0) {
307 		return preciousnesses_.at(tribename);
308 	}
309 	return Widelands::kInvalidWare;
310 }
311 
WareHints(const std::string & ware_name,const LuaTable & table)312 WareHints::WareHints(const std::string& ware_name, const LuaTable& table) : WareWorkerHints() {
313 	read_preciousness(ware_name, table);
314 }
315 
WorkerHints(const std::string & worker_name,const LuaTable & table)316 WorkerHints::WorkerHints(const std::string& worker_name, const LuaTable& table)
317    : WareWorkerHints() {
318 	read_preciousness(worker_name, *table.get_table("preciousness"));
319 }
320