Merge lp:~mxsscott/widelands/carli2-ai-improvements into lp:widelands
- carli2-ai-improvements
- Merge into trunk
Proposed by
Mark Scott
Status: | Rejected |
---|---|
Rejected by: | SirVer |
Proposed branch: | lp:~mxsscott/widelands/carli2-ai-improvements |
Merge into: | lp:widelands |
Diff against target: |
752 lines (+358/-242) 5 files modified
src/ai/ai_help_structs.h (+1/-0) src/ai/defaultai.cc (+351/-242) src/ai/defaultai.h (+4/-0) src/logic/militarysite.h (+1/-0) tribes/barbarians/fernery/conf (+1/-0) |
To merge this branch: | bzr merge lp:~mxsscott/widelands/carli2-ai-improvements |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
SirVer | Needs Fixing | ||
Review via email: mp+142009@code.launchpad.net |
Commit message
Description of the change
(Branch author is carli2: https:/
- Add "demand" to wares
- missing input wares count as demand
- missing soldiers add demand to weapons
- a depth pass filter is applied to demand in order to get stable values
- enhancements are now priorized correctly
gains:
- all three tribes manage to recruit soldiers
- the AI is able to finish its enemy after 90 minutes
- great improvement for AIs economy
To post a comment you must log in.
Revision history for this message
SirVer (sirver) wrote : | # |
Setting to rejected because there was no followup - feel free to reopen or discuss more.
Unmerged revisions
- 6478. By carli <https://launchpad.net/~s3734770>
-
AI improvements
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | === modified file 'src/ai/ai_help_structs.h' |
2 | --- src/ai/ai_help_structs.h 2012-09-21 21:36:07 +0000 |
3 | +++ src/ai/ai_help_structs.h 2013-01-05 13:44:24 +0000 |
4 | @@ -274,6 +274,7 @@ |
5 | uint8_t producers; |
6 | uint8_t consumers; |
7 | uint8_t preciousness; |
8 | + float demand; |
9 | }; |
10 | |
11 | #endif |
12 | |
13 | === modified file 'src/ai/defaultai.cc' |
14 | --- src/ai/defaultai.cc 2012-09-21 21:36:07 +0000 |
15 | +++ src/ai/defaultai.cc 2013-01-05 13:44:24 +0000 |
16 | @@ -30,6 +30,7 @@ |
17 | #include "economy/economy.h" |
18 | #include "economy/flag.h" |
19 | #include "economy/road.h" |
20 | +#include "economy/wares_queue.h" |
21 | #include "logic/findimmovable.h" |
22 | #include "logic/findnode.h" |
23 | #include "log.h" |
24 | @@ -75,7 +76,8 @@ |
25 | next_attack_consideration_due(300000), |
26 | inhibit_road_building (0), |
27 | time_of_last_construction (0), |
28 | - numof_warehouses (0) |
29 | + numof_warehouses (0), |
30 | + military_demand (0.0) |
31 | {} |
32 | |
33 | DefaultAI::~DefaultAI() |
34 | @@ -136,6 +138,9 @@ |
35 | // handled by the AI itself. |
36 | update_all_not_buildable_fields(); |
37 | |
38 | + // now update the statistics of what we need (wares and military power) |
39 | + update_demand(); |
40 | + |
41 | // IF defaultAI is AGGRESSIVE - we definitely should consider to attack as |
42 | // often as possible. |
43 | if (type == AGGRESSIVE) |
44 | @@ -234,6 +239,7 @@ |
45 | wares.at(i).producers = 0; |
46 | wares.at(i).consumers = 0; |
47 | wares.at(i).preciousness = tribe->get_ware_descr(i)->preciousness(); |
48 | + wares.at(i).demand = 0; |
49 | } |
50 | |
51 | // collect information about the different buildings our tribe can construct |
52 | @@ -472,6 +478,85 @@ |
53 | } |
54 | } |
55 | |
56 | +/*** |
57 | + * updates all needs of the economy |
58 | + */ |
59 | +void DefaultAI::update_demand() |
60 | +{ |
61 | + // military buildings need soldiers: count them! |
62 | + for |
63 | + (std::list<MilitarySiteObserver>::iterator i = |
64 | + militarysites.begin(); |
65 | + i != militarysites.end(); |
66 | + ++i) |
67 | + { |
68 | + military_demand += i->site->missingSoldiers(); |
69 | + } |
70 | + military_demand += 1; // some extra points such that we always get new soldiers |
71 | + military_demand *= 0.99; |
72 | + military_demand = std::max(military_demand, (type + 2) * (float) 2000.0); // then limit it to some degree. |
73 | + // enable logging for debug purpose |
74 | + //printf("mil = %f\n", military_demand); |
75 | + |
76 | + // now we know how much military we need, so we |
77 | + // need the wares to build the soldiers |
78 | + Ware_Index const nr_workers = tribe->get_nrworkers(); |
79 | + for (Ware_Index i = Ware_Index::First(); i < nr_workers; ++i) { |
80 | + // Find all build costs for soldiers |
81 | + // is it a soldier? |
82 | + if(tribe->get_worker_descr(i)->get_worker_type() == Worker_Descr::SOLDIER) { |
83 | + Worker_Descr::Buildcost::const_iterator end = tribe->get_worker_descr(i)->buildcost().end(); |
84 | + for(Worker_Descr::Buildcost::const_iterator it = tribe->get_worker_descr(i)->buildcost().begin(); it != end; ++it) { |
85 | + if(tribe->ware_index(it->first)) |
86 | + wares.at(tribe->ware_index(it->first)).demand += it->second * military_demand / 100.0; // Add soldier-need priority |
87 | + } |
88 | + } |
89 | + } |
90 | + |
91 | + |
92 | + // production buildings need inputs |
93 | + std::list<ProductionSiteObserver>::const_iterator i = |
94 | + productionsites.begin(); |
95 | + while(1) |
96 | + { |
97 | + // iterate through both: production buildings and mines |
98 | + if(i == productionsites.end()) |
99 | + i = mines.begin(); |
100 | + if(i == mines.end()) |
101 | + break; |
102 | + // count all empty slots |
103 | + for |
104 | + (ProductionSite::Input_Queues::const_iterator j = |
105 | + i->site->warequeues().begin(); |
106 | + j != i->site->warequeues().end(); |
107 | + j++) |
108 | + { |
109 | + if((*j)->get_filled() == 0) |
110 | + // count queues that are empty |
111 | + wares.at((*j)->get_ware()).demand += 1; |
112 | + } |
113 | + i++; |
114 | + } |
115 | + |
116 | + /* TODO: Iterate over all construction sites and add material need |
117 | + // Remark: construction materials are also handled by other code, but this |
118 | + // code could do it more scalable for big empires |
119 | + |
120 | + Buildcost::const_iterator end = bld.buildcost().end(); |
121 | + for(Buildcost::const_iterator it = bld.buildcost().begin(); it != end; ++it) { |
122 | + wares.at(it->first).demand += it->second; // Add build-need priority |
123 | + }*/ |
124 | + |
125 | + // now decrease the total ammount a bit |
126 | + Ware_Index nr_wares = tribe->get_nrwares(); |
127 | + for (Ware_Index i = Ware_Index::First(); i < nr_wares; ++i) |
128 | + { |
129 | + wares.at(i).demand *= 0.99; |
130 | + // enable logging for debug purpose |
131 | + //printf("ware %s: %f\n", tribe->get_ware_descr(i)->name().c_str(), wares.at(i).demand); |
132 | + } |
133 | +} |
134 | + |
135 | |
136 | /// Updates one buildable field |
137 | void DefaultAI::update_buildable_field |
138 | @@ -860,245 +945,7 @@ |
139 | if (bo.desc->get_size() > maxsize) |
140 | continue; |
141 | |
142 | - int32_t prio = 0; |
143 | - |
144 | - if (bo.type == BuildingObserver::PRODUCTIONSITE) { |
145 | - // Don't build another building of this type, if there is already |
146 | - // one that is unoccupied at the moment |
147 | - if (bo.unoccupied) |
148 | - continue; |
149 | - if (bo.need_trees) { |
150 | - // Priority of woodcutters depend on the number of near trees |
151 | - prio += bf->trees_nearby * 3; |
152 | - prio /= 3 * (1 + bf->producers_nearby.at(bo.outputs.at(0))); |
153 | - |
154 | - // TODO improve this - it's still useless to place lumberjack huts randomly |
155 | - /*if (prio <= 0) // no, sometimes we need wood without having a forest |
156 | - continue;*/ |
157 | - |
158 | - // Check if the produced wares are needed |
159 | - Ware_Index wt(static_cast<size_t>(bo.outputs.at(0))); |
160 | - container_iterate(std::list<EconomyObserver *>, economies, l) { |
161 | - // Don't check if the economy has no warehouse. |
162 | - if ((*l.current)->economy.warehouses().empty()) |
163 | - continue; |
164 | - if ((*l.current)->economy.needs_ware(wt)) |
165 | - prio += 1 + wares.at(bo.outputs.at(0)).preciousness; |
166 | - } |
167 | - |
168 | - if (bo.total_count() < 2) { |
169 | - prio *= 6; // big bonus for the basics |
170 | - if (bo.total_count() == 0) |
171 | - prio *= 4; // even more for the absolute basics |
172 | - } |
173 | - } else if (bo.need_stones) { |
174 | - // Priority of quarries depend on the number of near stones |
175 | - prio += bf->stones_nearby * 3; |
176 | - prio /= 3 * (1 + bf->producers_nearby.at(bo.outputs.at(0))); |
177 | - if (bo.total_count() < 2) { |
178 | - prio *= 6; // big bonus for the basics |
179 | - if (bo.total_count() == 0) |
180 | - prio *= 4; // even more for the absolute basics |
181 | - } |
182 | - } else if (bo.production_hint >= 0) { |
183 | - // production hint (f.e. associate forester with trunks) |
184 | - |
185 | - // Calculate the need for this building |
186 | - int16_t inout = wares.at(bo.production_hint).consumers; |
187 | - if |
188 | - (tribe->safe_ware_index("trunk").value() |
189 | - == |
190 | - bo.production_hint) |
191 | - inout += total_constructionsites / 4; |
192 | - inout -= wares.at(bo.production_hint).producers; |
193 | - if (inout < 1) |
194 | - inout = 1; |
195 | - // the ware they're refreshing |
196 | - Ware_Index wt(static_cast<size_t>(bo.production_hint)); |
197 | - container_iterate(std::list<EconomyObserver *>, economies, l) { |
198 | - // Don't check if the economy has no warehouse. |
199 | - if ((*l.current)->economy.warehouses().empty()) |
200 | - continue; |
201 | - if ((*l.current)->economy.needs_ware(wt)) { |
202 | - prio += wares.at(bo.production_hint).preciousness * inout * 2; |
203 | - break; |
204 | - } |
205 | - } |
206 | - |
207 | - // Do not build too many of these buildings, but still care |
208 | - // to build at least two. |
209 | - // And add bonus near buildings outputting production_hint ware. |
210 | - prio += (5 * bf->producers_nearby.at(bo.production_hint)) / 2; |
211 | - prio -= bo.total_count() * 2; |
212 | - prio /= bo.total_count() + 1; |
213 | - prio += (bf->producers_nearby.at(bo.production_hint) - 1) * 5; |
214 | - if (bo.total_count() > 2) |
215 | - prio -= bo.total_count(); |
216 | - else { |
217 | - prio += wares.at(bo.production_hint).preciousness; |
218 | - prio *= 3; |
219 | - } |
220 | - if (prio < 0) |
221 | - continue; |
222 | - } else if (bo.recruitment) { |
223 | - // "recruitment centeres" like the donkey farm should be build up |
224 | - // as soon as a basic infrastructure was completed. |
225 | - // and of course the defaultAI should think of further |
226 | - // constructions of that type later in game. |
227 | - prio -= 12; // start calculation with an offset |
228 | - prio += productionsites.size() + mines.size(); |
229 | - prio -= (bo.total_count()) * 40; |
230 | - prio *= 2; |
231 | - |
232 | - // take care about borders and enemies |
233 | - prio = recalc_with_border_range(*bf, prio); |
234 | - } else { // "normal" productionsites |
235 | - |
236 | - // ToDo: prefer soldier producing things |
237 | - // Ware_Index const soldier_index = tribe().worker_index("soldier"); |
238 | - |
239 | - if (bo.is_basic && (bo.total_count() == 0)) |
240 | - prio += 100; // for very important buildings |
241 | - |
242 | - // Check if the produced wares are needed |
243 | - container_iterate(std::list<EconomyObserver *>, economies, l) { |
244 | - // Don't check if the economy has no warehouse. |
245 | - if ((*l.current)->economy.warehouses().empty()) |
246 | - continue; |
247 | - for (uint32_t m = 0; m < bo.outputs.size(); ++m) { |
248 | - Ware_Index wt(static_cast<size_t>(bo.outputs.at(m))); |
249 | - |
250 | - // if we have too much of it (avoids mass storage) |
251 | - if |
252 | - ((*l.current)->economy.stock_ware(wt) > 6 * |
253 | - (*l.current)->economy.ware_target_quantity(wt).permanent) |
254 | - prio -= 20; |
255 | - |
256 | - // if the economy needs this ware |
257 | - if ((*l.current)->economy.needs_ware(wt)) { |
258 | - prio += 1 + wares.at(bo.outputs.at(m)).preciousness; |
259 | - if (bo.total_count() == 0) |
260 | - // big bonus, this site might be elemental |
261 | - prio += 3 * wares.at(bo.outputs.at(m)).preciousness; |
262 | - } |
263 | - |
264 | - // we can enhance this building. build more |
265 | - // maybe the enhancement can produce needed ware |
266 | - if (bo.desc->enhancements().size() > 0) { |
267 | - // this code builds more metalworks |
268 | - if (bo.total_count() == 0) |
269 | - prio += 2; |
270 | - if (bo.total_count() == 1) |
271 | - prio += 8; |
272 | - } |
273 | - } |
274 | - for (uint32_t m = 0; m < bo.inputs.size(); ++m) { |
275 | - Ware_Index wt(static_cast<size_t>(bo.inputs.at(m))); |
276 | - |
277 | - // if the economies don't need it: "waste" it |
278 | - if (!(*l.current)->economy.needs_ware(wt)) { |
279 | - if (bo.total_count() == 0 && bo.prod_build_material) |
280 | - // big bonus, this site might be elemental |
281 | - prio += 3 * wares.at(bo.inputs.at(m)).preciousness; |
282 | - } |
283 | - } |
284 | - } |
285 | - |
286 | - // If the produced wares are needed |
287 | - if (prio > 0) { |
288 | - int32_t inout_prio = 0; |
289 | - for (size_t k = 0; k < bo.inputs.size(); ++k) { |
290 | - inout_prio += bf->producers_nearby.at(bo.inputs.at(k)); |
291 | - inout_prio -= bf->consumers_nearby.at(bo.inputs.at(k)) / 2; |
292 | - } |
293 | - for (size_t k = 0; k < bo.outputs.size(); ++k) |
294 | - inout_prio += bf->consumers_nearby.at(bo.outputs.at(k)); |
295 | - prio += 2 * inout_prio; |
296 | - prio = calculate_need_for_ps(bo, prio); |
297 | - } else |
298 | - continue; |
299 | - |
300 | - // take care about borders and enemies |
301 | - prio = recalc_with_border_range(*bf, prio); |
302 | - |
303 | - // do not construct more than one building, |
304 | - // if supply line is already broken. |
305 | - if (!check_supply(bo) && bo.total_count() > 0) |
306 | - prio -= 12; |
307 | - |
308 | - } |
309 | - } else if (bo.type == BuildingObserver::MILITARYSITE) { |
310 | - if (!bf->unowned_land_nearby) |
311 | - continue; |
312 | - prio = bf->unowned_land_nearby * (1 + type); |
313 | - prio -= bf->military_influence * (5 - type); |
314 | - // set to at least 1 |
315 | - prio = prio > 0 ? prio : 1; |
316 | - prio *= expand_factor; |
317 | - prio /= 2; |
318 | - |
319 | - if (bf->enemy_nearby) |
320 | - prio *= 2; |
321 | - else |
322 | - prio -= bf->military_influence * 2; |
323 | - |
324 | - if (bf->avoid_military) |
325 | - prio /= 5; |
326 | - |
327 | - prio -= militarysites.size() - productionsites.size() / (3 - type); |
328 | - |
329 | - } else if (bo.type == BuildingObserver::WAREHOUSE) { |
330 | - // Build one warehouse for ~every 35 productionsites and mines. |
331 | - // Militarysites are slightly important as well, to have a bigger |
332 | - // chance for a warehouses (containing waiting soldiers or wares |
333 | - // needed for soldier training) near the frontier. |
334 | - prio += productionsites.size() + mines.size(); |
335 | - prio += militarysites.size() / 3; |
336 | - prio -= (bo.cnt_under_construction + numof_warehouses) * 35; |
337 | - prio *= 2; |
338 | - |
339 | - // take care about borders and enemies |
340 | - prio = recalc_with_border_range(*bf, prio); |
341 | - |
342 | - } else if (bo.type == BuildingObserver::TRAININGSITE) { |
343 | - // Start building trainingsites when there are already more than 50 |
344 | - // other buildings. That should be enough for a working economy. |
345 | - // On the other hand only build more trainingsites of the same |
346 | - // type if the economy is really big. |
347 | - prio += productionsites.size() + militarysites.size(); |
348 | - prio += mines.size(); |
349 | - prio += type * 10; // +0 / +10 / +20 for DEFF/NORM/AGGR |
350 | - prio = prio / (bo.total_count() + 1); |
351 | - prio -= (bo.total_count() + 1) * 70; |
352 | - |
353 | - // take care about borders and enemies |
354 | - prio = recalc_with_border_range(*bf, prio); |
355 | - } |
356 | - |
357 | - // avoid to have too many construction sites |
358 | - // but still enable the player to build up basic productionsites |
359 | - if |
360 | - (bo.type != BuildingObserver::PRODUCTIONSITE || |
361 | - !bo.is_basic || bo.total_count() > 0) |
362 | - prio /= |
363 | - 1 + bo.cnt_under_construction * (bo.cnt_under_construction + 1); |
364 | - |
365 | - // add big penalty if water is needed, but is not near |
366 | - if (bo.need_water) { |
367 | - if (bf->water_nearby < 3) |
368 | - continue; |
369 | - int effect = bf->water_nearby - 8; |
370 | - prio += |
371 | - effect > 0 ? |
372 | - static_cast<int>(sqrt(static_cast<double>(effect))) : effect; |
373 | - // if same producers are nearby, then give some penalty |
374 | - for (size_t k = 0; k < bo.outputs.size(); ++k) |
375 | - if (bf->producers_nearby.at(bo.outputs.at(k)) > 0) |
376 | - prio -= 3; |
377 | - } |
378 | - |
379 | - // think of space consuming buildings nearby like farms or vineyards |
380 | - prio /= 1 + bf->space_consumers_nearby; |
381 | + int32_t prio = calculate_building_prio(bo, bf, expand_factor); |
382 | |
383 | // Stop here, if priority is 0 or less. |
384 | if (prio <= 0) |
385 | @@ -1199,6 +1046,7 @@ |
386 | uint32_t ioprio = 0; |
387 | for (uint32_t m = 0; m < bo.outputs.size(); ++m) { |
388 | ioprio += 5 * wares.at(bo.outputs.at(m)).preciousness; |
389 | + ioprio += round(wares.at(bo.outputs.at(m)).demand / 100.0); |
390 | } |
391 | |
392 | // tribes that have enhanceable mines should build more mines |
393 | @@ -1214,7 +1062,7 @@ |
394 | // multiply with current statistics of all other buildings of this |
395 | // type to avoid constructing buildings where already some are running |
396 | // on low resources. |
397 | - prio *= 5 + bo.current_stats; |
398 | + prio *= 45 + bo.current_stats; |
399 | prio /= 100; |
400 | |
401 | if (onlymissing) // mines aren't *that* important |
402 | @@ -1252,6 +1100,262 @@ |
403 | return true; |
404 | } |
405 | |
406 | +int32_t DefaultAI::calculate_building_prio(BuildingObserver & bo, BuildableField * const bf, uint32_t expand_factor) |
407 | +{ |
408 | + int32_t prio = 0; |
409 | + |
410 | + if (bo.type == BuildingObserver::PRODUCTIONSITE) { |
411 | + // Don't build another building of this type, if there is already |
412 | + // one that is unoccupied at the moment |
413 | + if (bo.unoccupied) |
414 | + return -1; |
415 | + if (bo.need_trees) { |
416 | + // Priority of woodcutters depend on the number of near trees |
417 | + prio += bf->trees_nearby * 3; |
418 | + prio /= 3 * (1 + bf->producers_nearby.at(bo.outputs.at(0))); |
419 | + |
420 | + // TODO improve this - it's still useless to place lumberjack huts randomly |
421 | + /*if (prio <= 0) // no, sometimes we need wood without having a forest |
422 | + return -1;*/ |
423 | + |
424 | + // Check if the produced wares are needed |
425 | + Ware_Index wt(static_cast<size_t>(bo.outputs.at(0))); |
426 | + container_iterate(std::list<EconomyObserver *>, economies, l) { |
427 | + // Don't check if the economy has no warehouse. |
428 | + if ((*l.current)->economy.warehouses().empty()) |
429 | + continue; |
430 | + if ((*l.current)->economy.needs_ware(wt)) |
431 | + prio += 1 + wares.at(bo.outputs.at(0)).preciousness; |
432 | + } |
433 | + |
434 | + if (bo.total_count() < 2) { |
435 | + prio *= 6; // big bonus for the basics |
436 | + if (bo.total_count() == 0) |
437 | + prio *= 4; // even more for the absolute basics |
438 | + } |
439 | + } else if (bo.need_stones) { |
440 | + // Priority of quarries depend on the number of near stones |
441 | + prio += bf->stones_nearby * 3; |
442 | + prio /= 3 * (1 + bf->producers_nearby.at(bo.outputs.at(0))); |
443 | + if (bo.total_count() < 2) { |
444 | + prio *= 6; // big bonus for the basics |
445 | + if (bo.total_count() == 0) |
446 | + prio *= 4; // even more for the absolute basics |
447 | + } |
448 | + } else if (bo.production_hint >= 0) { |
449 | + // production hint (f.e. associate forester with trunks) |
450 | + |
451 | + // Calculate the need for this building |
452 | + int16_t inout = wares.at(bo.production_hint).consumers; |
453 | + if |
454 | + (tribe->safe_ware_index("trunk").value() |
455 | + == |
456 | + bo.production_hint) |
457 | + inout += total_constructionsites / 4; |
458 | + inout -= wares.at(bo.production_hint).producers; |
459 | + if (inout < 1) |
460 | + inout = 1; |
461 | + // the ware they're refreshing |
462 | + Ware_Index wt(static_cast<size_t>(bo.production_hint)); |
463 | + container_iterate(std::list<EconomyObserver *>, economies, l) { |
464 | + // Don't check if the economy has no warehouse. |
465 | + if ((*l.current)->economy.warehouses().empty()) |
466 | + continue; |
467 | + if ((*l.current)->economy.needs_ware(wt)) { |
468 | + prio += wares.at(bo.production_hint).preciousness * inout * 2; |
469 | + break; |
470 | + } |
471 | + } |
472 | + |
473 | + // Do not build too many of these buildings, but still care |
474 | + // to build at least two. |
475 | + // And add bonus near buildings outputting production_hint ware. |
476 | + prio += (5 * bf->producers_nearby.at(bo.production_hint)) / 2; |
477 | + prio -= bo.total_count() * 2; |
478 | + prio /= bo.total_count() + 1; |
479 | + prio += (bf->producers_nearby.at(bo.production_hint) - 1) * 5; |
480 | + if (bo.total_count() > 2) |
481 | + prio -= bo.total_count(); |
482 | + else { |
483 | + prio += wares.at(bo.production_hint).preciousness; |
484 | + prio *= 3; |
485 | + } |
486 | + if (prio < 0) |
487 | + return -1; |
488 | + } else if (bo.recruitment) { |
489 | + // "recruitment centeres" like the donkey farm should be build up |
490 | + // as soon as a basic infrastructure was completed. |
491 | + // and of course the defaultAI should think of further |
492 | + // constructions of that type later in game. |
493 | + prio -= 12; // start calculation with an offset |
494 | + prio += productionsites.size() + mines.size(); |
495 | + prio -= (bo.total_count()) * 40; |
496 | + prio *= 2; |
497 | + |
498 | + // take care about borders and enemies |
499 | + prio = recalc_with_border_range(*bf, prio); |
500 | + } else { // "normal" productionsites |
501 | + |
502 | + if (bo.is_basic && (bo.total_count() == 0)) |
503 | + prio += 100; // for very important buildings |
504 | + |
505 | + // we can enhance this building. build more |
506 | + // maybe the enhancement can produce needed ware |
507 | + // TODO: rather plan an enhanced building from bottom up |
508 | + for (std::set<Building_Index>::const_iterator enhancement = |
509 | + bo.desc->enhancements().begin(); |
510 | + enhancement != bo.desc->enhancements().end(); |
511 | + enhancement++) { |
512 | + // when we build a, we can build b, too... |
513 | + BuildingObserver & bo2 = buildings[*enhancement]; |
514 | + // so simply add the score of the building behind it... |
515 | + uint32_t prio2 = calculate_building_prio(bo2, bf, expand_factor); |
516 | + if (prio2 * (1 + bo.total_count()) > prio * (1 + bo2.total_count())) |
517 | + prio = prio / 2 + prio2; // we want to build the enhanced building instead of this |
518 | + } |
519 | + |
520 | + |
521 | + // Check if the produced wares are needed |
522 | + container_iterate(std::list<EconomyObserver *>, economies, l) { |
523 | + // Don't check if the economy has no warehouse. |
524 | + if ((*l.current)->economy.warehouses().empty()) |
525 | + continue; |
526 | + for (uint32_t m = 0; m < bo.outputs.size(); ++m) { |
527 | + Ware_Index wt(static_cast<size_t>(bo.outputs.at(m))); |
528 | + |
529 | + // Our main instinct: what we actually need |
530 | + // for military, production and construction |
531 | + prio += round(wares.at(bo.outputs.at(m)).demand / 50.0); |
532 | + |
533 | + // if we have too much of it (avoids mass storage) |
534 | + if |
535 | + ((*l.current)->economy.stock_ware(wt) > 6 * |
536 | + (*l.current)->economy.ware_target_quantity(wt).permanent) |
537 | + prio -= 20; |
538 | + |
539 | + // if the economy needs this ware |
540 | + if ((*l.current)->economy.needs_ware(wt)) { |
541 | + prio += 1 + wares.at(bo.outputs.at(m)).preciousness; |
542 | + if (bo.total_count() == 0) |
543 | + // big bonus, this site might be elemental |
544 | + prio += 3 * wares.at(bo.outputs.at(m)).preciousness; |
545 | + } |
546 | + } |
547 | + for (uint32_t m = 0; m < bo.inputs.size(); ++m) { |
548 | + Ware_Index wt(static_cast<size_t>(bo.inputs.at(m))); |
549 | + |
550 | + // Wares that are needed should not be consumed too much |
551 | + prio -= round(wares.at(wt).demand / 100.0); |
552 | + |
553 | + // if the economies don't need it: "waste" it |
554 | + if (!(*l.current)->economy.needs_ware(wt)) { |
555 | + prio++; |
556 | + if (bo.total_count() == 0 && bo.prod_build_material) |
557 | + // big bonus, this site might be elemental |
558 | + prio += 3 * wares.at(bo.inputs.at(m)).preciousness; |
559 | + } |
560 | + } |
561 | + } |
562 | + |
563 | + // If the produced wares are needed |
564 | + if (prio > 0) { |
565 | + int32_t inout_prio = 0; |
566 | + for (size_t k = 0; k < bo.inputs.size(); ++k) { |
567 | + inout_prio += bf->producers_nearby.at(bo.inputs.at(k)); |
568 | + inout_prio -= bf->consumers_nearby.at(bo.inputs.at(k)) / 2; |
569 | + } |
570 | + for (size_t k = 0; k < bo.outputs.size(); ++k) |
571 | + inout_prio += bf->consumers_nearby.at(bo.outputs.at(k)); |
572 | + prio += 2 * inout_prio; |
573 | + prio = calculate_need_for_ps(bo, prio); |
574 | + } else |
575 | + return -1; |
576 | + |
577 | + // take care about borders and enemies |
578 | + prio = recalc_with_border_range(*bf, prio); |
579 | + |
580 | + // do not construct more than one building, |
581 | + // if supply line is already broken. |
582 | + if (!check_supply(bo) && bo.total_count() > 0) |
583 | + prio -= 12; |
584 | + |
585 | + } |
586 | + } else if (bo.type == BuildingObserver::MILITARYSITE) { |
587 | + if (!bf->unowned_land_nearby) |
588 | + return -1; |
589 | + prio = bf->unowned_land_nearby * (1 + type); |
590 | + prio -= bf->military_influence * (5 - type); |
591 | + // set to at least 1 |
592 | + prio = prio > 0 ? prio : 1; |
593 | + prio *= expand_factor; |
594 | + prio /= 2; |
595 | + |
596 | + if (bf->enemy_nearby) |
597 | + prio *= 2; |
598 | + else |
599 | + prio -= bf->military_influence * 2; |
600 | + |
601 | + if (bf->avoid_military) |
602 | + prio /= 5; |
603 | + |
604 | + prio -= militarysites.size() - productionsites.size() / (3 - type); |
605 | + |
606 | + } else if (bo.type == BuildingObserver::WAREHOUSE) { |
607 | + // Build one warehouse for ~every 35 productionsites and mines. |
608 | + // Militarysites are slightly important as well, to have a bigger |
609 | + // chance for a warehouses (containing waiting soldiers or wares |
610 | + // needed for soldier training) near the frontier. |
611 | + prio += productionsites.size() + mines.size(); |
612 | + prio += militarysites.size() / 3; |
613 | + prio -= (bo.cnt_under_construction + numof_warehouses) * 35; |
614 | + prio *= 2; |
615 | + |
616 | + // take care about borders and enemies |
617 | + prio = recalc_with_border_range(*bf, prio); |
618 | + |
619 | + } else if (bo.type == BuildingObserver::TRAININGSITE) { |
620 | + // Start building trainingsites when there are already more than 50 |
621 | + // other buildings. That should be enough for a working economy. |
622 | + // On the other hand only build more trainingsites of the same |
623 | + // type if the economy is really big. |
624 | + prio += productionsites.size() + militarysites.size(); |
625 | + prio += mines.size(); |
626 | + prio += type * 10; // +0 / +10 / +20 for DEFF/NORM/AGGR |
627 | + prio = prio / (bo.total_count() + 1); |
628 | + prio -= (bo.total_count() + 1) * 70; |
629 | + |
630 | + // take care about borders and enemies |
631 | + prio = recalc_with_border_range(*bf, prio); |
632 | + } |
633 | + |
634 | + // avoid to have too many construction sites |
635 | + // but still enable the player to build up basic productionsites |
636 | + if |
637 | + (bo.type != BuildingObserver::PRODUCTIONSITE || |
638 | + !bo.is_basic || bo.total_count() > 0) |
639 | + prio /= |
640 | + 1 + bo.cnt_under_construction * (bo.cnt_under_construction + 1); |
641 | + |
642 | + // add big penalty if water is needed, but is not near |
643 | + if (bo.need_water) { |
644 | + if (bf->water_nearby < 3) |
645 | + return -1; |
646 | + int effect = bf->water_nearby - 8; |
647 | + prio += |
648 | + effect > 0 ? |
649 | + static_cast<int>(sqrt(static_cast<double>(effect))) : effect; |
650 | + // if same producers are nearby, then give some penalty |
651 | + for (size_t k = 0; k < bo.outputs.size(); ++k) |
652 | + if (bf->producers_nearby.at(bo.outputs.at(k)) > 0) |
653 | + prio -= 3; |
654 | + } |
655 | + |
656 | + // think of space consuming buildings nearby like farms or vineyards |
657 | + prio /= 1 + bf->space_consumers_nearby; |
658 | + |
659 | + return prio; |
660 | +} |
661 | + |
662 | /** |
663 | * This function searches for places where a new road is needed to connect two |
664 | * economies. It then sends the request to build the road. |
665 | @@ -1722,7 +1826,9 @@ |
666 | if (!site.site->has_workers(*x.current, game())) |
667 | continue; |
668 | |
669 | - int32_t prio = 0; // priority for enhancement |
670 | + /*BuildableField bf(map.get_fcoords(site.site->get_position())); |
671 | + int32_t prio = calculate_building_prio(en_bo, &bf, 0); // priority for enhancement*/ |
672 | + int32_t prio = 0; |
673 | |
674 | // Find new outputs of enhanced building |
675 | std::vector<int16_t> & current_outputs = site.bo->outputs; |
676 | @@ -1742,6 +1848,7 @@ |
677 | // Check if the new wares are needed in economy of the building |
678 | for (uint32_t i = 0; i < new_outputs.size(); ++i) { |
679 | Ware_Index wt(static_cast<size_t>(new_outputs.at(i))); |
680 | + prio += round(wares.at(new_outputs.at(i)).demand / 50.0); |
681 | if (site.site->economy().needs_ware(wt)) |
682 | prio += 2 + wares.at(new_outputs.at(i)).preciousness; |
683 | } |
684 | @@ -2012,6 +2119,7 @@ |
685 | for (uint32_t k = 0; k < bo.inputs.size(); ++k) { |
686 | prio += 2 * wares.at(bo.inputs.at(k)).producers; |
687 | prio -= wares.at(bo.inputs.at(k)).consumers; |
688 | + prio -= round(wares.at(bo.inputs.at(k)).demand / 100.0); |
689 | } |
690 | if (bo.inputs.empty()) |
691 | prio += 4; |
692 | @@ -2021,6 +2129,7 @@ |
693 | WareObserver & wo = wares.at(bo.outputs.at(k)); |
694 | if (wo.consumers > 0) { |
695 | output_prio += wo.preciousness; |
696 | + output_prio += round(wo.demand / 100.0); |
697 | output_prio += wo.consumers * 2; |
698 | output_prio -= wo.producers * 2; |
699 | if (bo.total_count() == 0) |
700 | |
701 | === modified file 'src/ai/defaultai.h' |
702 | --- src/ai/defaultai.h 2012-02-20 15:54:26 +0000 |
703 | +++ src/ai/defaultai.h 2013-01-05 13:44:24 +0000 |
704 | @@ -118,6 +118,7 @@ |
705 | void update_all_buildable_fields (int32_t); |
706 | void update_all_mineable_fields (int32_t); |
707 | void update_all_not_buildable_fields (); |
708 | + void update_demand(); |
709 | |
710 | void update_buildable_field(BuildableField &, uint16_t = 6, bool = false); |
711 | void update_mineable_field (MineableField &); |
712 | @@ -138,6 +139,7 @@ |
713 | |
714 | int32_t recalc_with_border_range(const BuildableField &, int32_t); |
715 | int32_t calculate_need_for_ps(BuildingObserver &, int32_t); |
716 | + int32_t calculate_building_prio(BuildingObserver & bo, BuildableField * const bf, uint32_t expand_factor); |
717 | |
718 | void consider_productionsite_influence |
719 | (BuildableField &, Widelands::Coords, BuildingObserver const &); |
720 | @@ -193,6 +195,8 @@ |
721 | int32_t time_of_last_construction; |
722 | |
723 | uint16_t numof_warehouses; |
724 | + |
725 | + float military_demand; |
726 | }; |
727 | |
728 | #endif |
729 | |
730 | === modified file 'src/logic/militarysite.h' |
731 | --- src/logic/militarysite.h 2012-02-15 21:25:34 +0000 |
732 | +++ src/logic/militarysite.h 2013-01-05 13:44:24 +0000 |
733 | @@ -75,6 +75,7 @@ |
734 | // Begin implementation of SoldierControl |
735 | virtual std::vector<Soldier *> presentSoldiers() const; |
736 | virtual std::vector<Soldier *> stationedSoldiers() const; |
737 | + virtual uint32_t missingSoldiers() { return m_capacity - stationedSoldiers().size(); } |
738 | virtual uint32_t minSoldierCapacity() const throw (); |
739 | virtual uint32_t maxSoldierCapacity() const throw (); |
740 | virtual uint32_t soldierCapacity() const; |
741 | |
742 | === modified file 'tribes/barbarians/fernery/conf' |
743 | --- tribes/barbarians/fernery/conf 2011-09-12 17:29:32 +0000 |
744 | +++ tribes/barbarians/fernery/conf 2013-01-05 13:44:24 +0000 |
745 | @@ -3,6 +3,7 @@ |
746 | |
747 | [aihints] |
748 | space_consumer=true |
749 | +is_basic=true |
750 | |
751 | [buildcost] |
752 | trunk=5 |
see http:// wl.widelands. org/forum/ topic/648/ ?page=3# post-8562. More comments and review welcome.