Merge lp:~tiborb95/widelands/tiborb-ai into lp:widelands
- tiborb-ai
- Merge into trunk
Status: | Merged |
---|---|
Merged at revision: | 6978 |
Proposed branch: | lp:~tiborb95/widelands/tiborb-ai |
Merge into: | lp:widelands |
Diff against target: |
5156 lines (+2280/-1579) 17 files modified
src/ai/ai_help_structs.cc (+15/-26) src/ai/ai_help_structs.h (+214/-171) src/ai/ai_hints.cc (+18/-19) src/ai/ai_hints.h (+60/-30) src/ai/defaultai.cc (+1819/-1230) src/ai/defaultai.h (+107/-90) src/constants.h (+1/-0) src/economy/economy.cc (+2/-2) src/graphic/animation.cc (+12/-5) src/logic/cmd_queue.h (+2/-1) src/logic/productionsite.cc (+20/-5) src/logic/productionsite.h (+2/-0) tribes/atlanteans/smokery/conf (+1/-0) tribes/atlanteans/well/conf (+4/-0) tribes/barbarians/well/conf (+1/-0) tribes/empire/marblemine/conf (+1/-0) tribes/empire/well/conf (+1/-0) |
To merge this branch: | bzr merge lp:~tiborb95/widelands/tiborb-ai |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
SirVer | Approve | ||
Review via email: mp+219947@code.launchpad.net |
Commit message
Description of the change
conflicts should be resolved now
TiborB (tiborb95) wrote : | # |
No problem, I will do some housekeeping and make changes you suggested. Yesterday I did some small changes (not commited yet) but from now on there will be no functional changes...
"owned by me" was partially a joke, and meant "until merged to trunk", or in other words - I did this for widelands and only for widelands. But I will omit that comment to avoid any doubts :)
The changes are quite extensive so I understand the review will not be one-step proccess.
TiborB (tiborb95) wrote : | # |
one more comment, to this your comment:
"> + openend = oe;
while you are working on this part of the code, could you add _ to the end of member variables? openend_ . Also open_end_ reads easier."
The line cited was not written by me, and moreover defaultai.cc doesnt use this style nowhere at all. Do you want me to edit also original code?
SirVer (sirver) wrote : | # |
> The line cited was not written by me,
yes, I know. That is why I wrote 'while you are working on this part of the code'. Feel free to disregard if you do not want to mess with old cruft.
> and moreover defaultai.cc doesnt use this style nowhere at all.
defaultai.cc uses no style at all. Everything is all over the place. Moving towards a consistent Widelands style in incremental steps is good imho.
> Do you want me to edit also original code?
If you feel like it I would approve of style fixing. Do not bother if it is too much work.
TiborB (tiborb95) wrote : | # |
revision 6987 was just pushed.
I deleted some commented pieces of code, reformatted all files in src/ai/ directory with clang-format, added same comments.
Out of ai directory I had to change some conf files for buildings, mostly I added some aihints there.
Ready for review.
SirVer (sirver) wrote : | # |
Well, with the clang_formatting all through ai/ it is very difficult to see the real changes you made. However, I think this is style wise and functionality wise defintively an improvement. So I went ahead and merged it.
However, I ran into a crash when testing for the first time. I'll open a bug report and assign it to you.
TiborB (tiborb95) wrote : | # |
Glad to hear it! (I do not mean the bug :) )
SirVer (sirver) wrote : | # |
Good job with the AI stuff and the style changes.
I also added you to widelands-dev. That means:
- feel free to fix (small) stuff in trunk directly.
- Please push all your (bigger) future changes to lp:~/widelands-dev/widelands/<branch name> because other devs can then edit the branch too. That makes code reviews easier.
- NEVER EVER NEVER push your branch to trunk, i.e. do this:
$ [being on trunk] bzr merge <my branch>; bzr push lp:widelands
and NEVER do this
$ [being on <my branch>] bzr merge lp:widelands; bzr push lp:widelands
Welcome to the team :)
TiborB (tiborb95) wrote : | # |
Thanks! I am delighted!
In fact I am going to open new branch in near future as I have further
ideas in my head and there are those bugs...
I am bit scared of bzr, but I will be very carefull....
2014-06-14 23:26 GMT+02:00 SirVer <email address hidden>:
> Good job with the AI stuff and the style changes.
>
> I also added you to widelands-dev. That means:
>
> - feel free to fix (small) stuff in trunk directly.
> - Please push all your (bigger) future changes to
> lp:~/widelands-dev/widelands/<branch name> because other devs can then edit
> the branch too. That makes code reviews easier.
>
> - NEVER EVER NEVER push your branch to trunk, i.e. do this:
>
> $ [being on trunk] bzr merge <my branch>; bzr push lp:widelands
>
> and NEVER do this
>
> $ [being on <my branch>] bzr merge lp:widelands; bzr push lp:widelands
>
> Welcome to the team :)
> --
> https:/
> You are the owner of lp:~tiborb95/widelands/tiborb-ai.
>
TiborB (tiborb95) wrote : | # |
Hi,
I need explanation to this:
"- Please push all your (bigger) future changes to
lp:~/widelands-dev/widelands/<branch name> "
According to bzr primmer I would do:
bzr branch trunk tiborb-ai2
as I did before. So what exactly should I do to create new branch?
Tibor
2014-06-14 23:26 GMT+02:00 SirVer <email address hidden>:
> Good job with the AI stuff and the style changes.
>
> I also added you to widelands-dev. That means:
>
> - feel free to fix (small) stuff in trunk directly.
> - Please push all your (bigger) future changes to
> lp:~/widelands-dev/widelands/<branch name> because other devs can then edit
> the branch too. That makes code reviews easier.
>
> - NEVER EVER NEVER push your branch to trunk, i.e. do this:
>
> $ [being on trunk] bzr merge <my branch>; bzr push lp:widelands
>
> and NEVER do this
>
> $ [being on <my branch>] bzr merge lp:widelands; bzr push lp:widelands
>
> Welcome to the team :)
> --
> https:/
> You are the owner of lp:~tiborb95/widelands/tiborb-ai.
>
SirVer (sirver) wrote : | # |
The step to create the branch would not change. The only thing that changes is where you push the branch. Instead of publishing it to launchpad like this:
bzr push --remember lp:~tiborb95/widelands/<branch_name>
you push to a branch that is writable by everybody in ~widelands-dev
bzr push --remember lp:~widelands-dev/widelands/<branch_name>
Preview Diff
1 | === modified file 'src/ai/ai_help_structs.cc' |
2 | --- src/ai/ai_help_structs.cc 2013-07-26 20:19:36 +0000 |
3 | +++ src/ai/ai_help_structs.cc 2014-06-10 18:35:21 +0000 |
4 | @@ -22,59 +22,49 @@ |
5 | #include "logic/player.h" |
6 | #include "upcast.h" |
7 | |
8 | - |
9 | namespace Widelands { |
10 | |
11 | // FindNodeWithFlagOrRoad |
12 | |
13 | -bool FindNodeWithFlagOrRoad::accept (const Map &, FCoords fc) const |
14 | -{ |
15 | +bool FindNodeWithFlagOrRoad::accept(const Map&, FCoords fc) const { |
16 | if (upcast(PlayerImmovable const, pimm, fc.field->get_immovable())) |
17 | - return |
18 | - pimm->get_economy() != economy |
19 | - and |
20 | - (dynamic_cast<Flag const *>(pimm) |
21 | - or |
22 | - (dynamic_cast<Road const *>(pimm) && |
23 | - (fc.field->nodecaps() & BUILDCAPS_FLAG))); |
24 | + return pimm->get_economy() != economy and(dynamic_cast<Flag const*>(pimm) |
25 | + or(dynamic_cast<Road const*>(pimm) && |
26 | + (fc.field->nodecaps() & BUILDCAPS_FLAG))); |
27 | return false; |
28 | } |
29 | |
30 | - |
31 | // CheckStepRoadAI |
32 | |
33 | -bool CheckStepRoadAI::allowed |
34 | - (Map & map, FCoords, FCoords end, int32_t, CheckStep::StepId const id) |
35 | - const |
36 | -{ |
37 | - uint8_t endcaps = player->get_buildcaps(end); |
38 | +bool CheckStepRoadAI::allowed(Map& map, FCoords, FCoords end, int32_t, CheckStep::StepId const id) |
39 | + const { |
40 | + uint8_t endcaps = player_->get_buildcaps(end); |
41 | |
42 | // Calculate cost and passability |
43 | - if (!(endcaps & movecaps)) |
44 | + if (!(endcaps & movecaps_)) |
45 | return false; |
46 | |
47 | // Check for blocking immovables |
48 | - if (BaseImmovable const * const imm = map.get_immovable(end)) |
49 | + if (BaseImmovable const* const imm = map.get_immovable(end)) |
50 | if (imm->get_size() >= BaseImmovable::SMALL) { |
51 | - if (id != CheckStep::stepLast && !openend) |
52 | + if (id != CheckStep::stepLast && !open_end_) |
53 | return false; |
54 | |
55 | - if (dynamic_cast<Flag const *>(imm)) |
56 | + if (dynamic_cast<Flag const*>(imm)) |
57 | return true; |
58 | |
59 | - if (not dynamic_cast<Road const *>(imm) || !(endcaps & BUILDCAPS_FLAG)) |
60 | + if (not dynamic_cast<Road const*>(imm) || !(endcaps & BUILDCAPS_FLAG)) |
61 | return false; |
62 | } |
63 | |
64 | return true; |
65 | } |
66 | |
67 | -bool CheckStepRoadAI::reachabledest(Map & map, FCoords const dest) const |
68 | -{ |
69 | +bool CheckStepRoadAI::reachabledest(Map& map, FCoords const dest) const { |
70 | NodeCaps const caps = dest.field->nodecaps(); |
71 | |
72 | - if (!(caps & movecaps)) { |
73 | - if (!((movecaps & MOVECAPS_SWIM) && (caps & MOVECAPS_WALK))) |
74 | + if (!(caps & movecaps_)) { |
75 | + if (!((movecaps_ & MOVECAPS_SWIM) && (caps & MOVECAPS_WALK))) |
76 | return false; |
77 | |
78 | if (!map.can_reach_by_water(dest)) |
79 | @@ -83,5 +73,4 @@ |
80 | |
81 | return true; |
82 | } |
83 | - |
84 | } |
85 | |
86 | === modified file 'src/ai/ai_help_structs.h' |
87 | --- src/ai/ai_help_structs.h 2013-07-26 19:16:51 +0000 |
88 | +++ src/ai/ai_help_structs.h 2014-06-10 18:35:21 +0000 |
89 | @@ -36,185 +36,218 @@ |
90 | class MilitarySite; |
91 | |
92 | struct CheckStepRoadAI { |
93 | - CheckStepRoadAI(Player * const pl, uint8_t const mc, bool const oe) |
94 | - : player(pl), movecaps(mc), openend(oe) |
95 | - {} |
96 | - |
97 | - void set_openend (bool const oe) {openend = oe;} |
98 | - |
99 | - bool allowed |
100 | - (Map &, FCoords start, FCoords end, int32_t dir, CheckStep::StepId) |
101 | - const; |
102 | - bool reachabledest(Map &, FCoords dest) const; |
103 | - |
104 | - Player * player; |
105 | - uint8_t movecaps; |
106 | - bool openend; |
107 | -}; |
108 | - |
109 | + CheckStepRoadAI(Player* const pl, uint8_t const mc, bool const oe) |
110 | + : player_(pl), movecaps_(mc), open_end_(oe) { |
111 | + } |
112 | + |
113 | + void set_openend(bool const oe) { |
114 | + open_end_ = oe; |
115 | + } |
116 | + |
117 | + bool allowed(Map&, FCoords start, FCoords end, int32_t dir, CheckStep::StepId) const; |
118 | + bool reachabledest(Map&, FCoords dest) const; |
119 | + |
120 | + Player* player_; |
121 | + uint8_t movecaps_; |
122 | + bool open_end_; |
123 | +}; |
124 | + |
125 | +struct FindNodeEnemy { |
126 | + bool accept(const Map&, const FCoords& fc) const { |
127 | + // we are looking for fields we can walk on |
128 | + // and owned by hostile player. |
129 | + return (fc.field->nodecaps() & MOVECAPS_WALK) && fc.field->get_owned_by() != 0 && |
130 | + player->is_hostile(*game.get_player(fc.field->get_owned_by())); |
131 | + } |
132 | + |
133 | + Player* player; |
134 | + Game& game; |
135 | + |
136 | + FindNodeEnemy(Player* p, Game& g) : player(p), game(g) { |
137 | + } |
138 | +}; |
139 | |
140 | struct FindNodeUnowned { |
141 | - bool accept (const Map &, const FCoords & fc) const { |
142 | + bool accept(const Map&, const FCoords& fc) const { |
143 | // when looking for unowned terrain to acquire, we are actually |
144 | // only interested in fields we can walk on. |
145 | - // Fields should either be completely unowned or owned by an opposing player |
146 | - return |
147 | - (fc.field->nodecaps() & MOVECAPS_WALK) |
148 | - && |
149 | - ((fc.field->get_owned_by() == 0) |
150 | - || player->is_hostile(*game.get_player(fc.field->get_owned_by()))) |
151 | - && (!onlyenemies || (fc.field->get_owned_by() != 0)); |
152 | - } |
153 | - |
154 | - //int8_t playernum; |
155 | - Player * player; |
156 | - Game & game; |
157 | - bool onlyenemies; |
158 | - |
159 | - FindNodeUnowned(Player * p, Game & g, bool oe = false) |
160 | - : player(p), game(g), onlyenemies(oe) |
161 | - {} |
162 | -}; |
163 | - |
164 | + // Fields should either be completely unowned or owned by an opposing player_ |
165 | + return (fc.field->nodecaps() & MOVECAPS_WALK) && |
166 | + ((fc.field->get_owned_by() == 0) || |
167 | + player_->is_hostile(*game.get_player(fc.field->get_owned_by()))) && |
168 | + (!only_enemies_ || (fc.field->get_owned_by() != 0)); |
169 | + } |
170 | + |
171 | + Player* player_; |
172 | + Game& game; |
173 | + bool only_enemies_; |
174 | + |
175 | + FindNodeUnowned(Player* p, Game& g, bool oe = false) : player_(p), game(g), only_enemies_(oe) { |
176 | + } |
177 | +}; |
178 | + |
179 | +struct FindNodeUnownedMineable { |
180 | + bool accept(const Map&, const FCoords& fc) const { |
181 | + // when looking for unowned terrain to acquire, we are actually |
182 | + // only interested in fields where mines can be built. |
183 | + // Fields should be completely unowned |
184 | + return (fc.field->nodecaps() & BUILDCAPS_MINE) && (fc.field->get_owned_by() == 0); |
185 | + } |
186 | + |
187 | + Player* player_; |
188 | + Game& game; |
189 | + |
190 | + FindNodeUnownedMineable(Player* p, Game& g) : player_(p), game(g) { |
191 | + } |
192 | +}; |
193 | |
194 | struct FindNodeWater { |
195 | - bool accept(const Map & map, const FCoords & coord) const { |
196 | - return |
197 | - (map.world().terrain_descr(coord.field->terrain_d()).get_is() |
198 | - & TERRAIN_WATER) |
199 | - || |
200 | - (map.world().terrain_descr(coord.field->terrain_r()).get_is() |
201 | - & TERRAIN_WATER); |
202 | + bool accept(const Map& map, const FCoords& coord) const { |
203 | + return (map.world().terrain_descr(coord.field->terrain_d()).get_is() & TERRAIN_WATER) || |
204 | + (map.world().terrain_descr(coord.field->terrain_r()).get_is() & TERRAIN_WATER); |
205 | } |
206 | }; |
207 | |
208 | - |
209 | struct FindNodeWithFlagOrRoad { |
210 | - Economy * economy; |
211 | - bool accept(const Map &, FCoords) const; |
212 | + Economy* economy; |
213 | + bool accept(const Map&, FCoords) const; |
214 | }; |
215 | |
216 | - |
217 | struct NearFlag { |
218 | - Flag const * flag; |
219 | - int32_t cost; |
220 | - int32_t distance; |
221 | - |
222 | - NearFlag (const Flag & f, int32_t const c, int32_t const d) : |
223 | - flag(&f), cost(c), distance(d) |
224 | - {} |
225 | - |
226 | - bool operator< (const NearFlag & f) const {return cost > f.cost;} |
227 | - |
228 | - bool operator== (Flag const * const f) const {return flag == f;} |
229 | + Flag const* flag; |
230 | + int32_t cost_; |
231 | + int32_t distance_; |
232 | + |
233 | + NearFlag(const Flag& f, int32_t const c, int32_t const d) : flag(&f), cost_(c), distance_(d) { |
234 | + } |
235 | + |
236 | + bool operator<(const NearFlag& f) const { |
237 | + return cost_ > f.cost_; |
238 | + } |
239 | + |
240 | + bool operator==(Flag const* const f) const { |
241 | + return flag == f; |
242 | + } |
243 | }; |
244 | |
245 | - |
246 | struct CompareDistance { |
247 | - bool operator() (const NearFlag & a, const NearFlag & b) const { |
248 | - return a.distance < b.distance; |
249 | + bool operator()(const NearFlag& a, const NearFlag& b) const { |
250 | + return a.distance_ < b.distance_; |
251 | } |
252 | }; |
253 | |
254 | - |
255 | struct WalkableSpot { |
256 | Coords coords; |
257 | - bool hasflag; |
258 | - |
259 | - int32_t cost; |
260 | - void * eco; |
261 | - |
262 | - int16_t from; |
263 | - int16_t neighbours[6]; |
264 | + bool has_flag_; |
265 | + |
266 | + int32_t cost_; |
267 | + void* eco; |
268 | + |
269 | + int16_t from_; |
270 | + int16_t neighbours[6]; |
271 | }; |
272 | - |
273 | } |
274 | |
275 | struct BlockedField { |
276 | Widelands::FCoords coords; |
277 | - int32_t blocked_until; |
278 | + int32_t blocked_until_; |
279 | |
280 | - BlockedField(Widelands::FCoords c, int32_t until) |
281 | - : |
282 | - coords(c), |
283 | - blocked_until(until) |
284 | - {} |
285 | + BlockedField(Widelands::FCoords c, int32_t until) : coords(c), blocked_until_(until) { |
286 | + } |
287 | }; |
288 | |
289 | struct BuildableField { |
290 | Widelands::FCoords coords; |
291 | |
292 | - int32_t next_update_due; |
293 | - |
294 | - bool reachable; |
295 | - bool preferred; |
296 | - bool avoid_military; |
297 | - bool enemy_nearby; |
298 | - |
299 | - uint8_t unowned_land_nearby; |
300 | - |
301 | - uint8_t trees_nearby; |
302 | - uint8_t stones_nearby; |
303 | - uint8_t water_nearby; |
304 | - uint8_t space_consumers_nearby; |
305 | - |
306 | - int16_t military_influence; |
307 | - |
308 | - std::vector<uint8_t> consumers_nearby; |
309 | - std::vector<uint8_t> producers_nearby; |
310 | - |
311 | - BuildableField (const Widelands::FCoords & fc) |
312 | - : |
313 | - coords (fc), |
314 | - next_update_due (0), |
315 | - reachable (false), |
316 | - preferred (false), |
317 | - avoid_military(0), |
318 | - enemy_nearby(0), |
319 | - unowned_land_nearby(0), |
320 | - trees_nearby (0), |
321 | - stones_nearby (0), |
322 | - water_nearby(0), |
323 | - space_consumers_nearby(0), |
324 | - military_influence(0) |
325 | - {} |
326 | + int32_t next_update_due_; |
327 | + |
328 | + bool reachable; |
329 | + bool preferred_; |
330 | + bool enemy_nearby_; |
331 | + |
332 | + uint8_t unowned_land_nearby_; |
333 | + uint8_t unowned_mines_pots_nearby_; |
334 | + uint8_t trees_nearby_; |
335 | + uint8_t stones_nearby_; |
336 | + int8_t water_nearby_; |
337 | + int8_t ground_water_; // used by wells |
338 | + uint8_t space_consumers_nearby_; |
339 | + // to manage the military better following variables exists: |
340 | + // capacity of nearby buildings: |
341 | + int16_t military_capacity_; |
342 | + // distance to near buldings: |
343 | + int16_t military_loneliness_; |
344 | + // count of military buildings in construction |
345 | + // when making decision on new mulitary buildings it considers also |
346 | + // unowned fields and mines, but this information is not quite correct as there |
347 | + // are construction sites that will change this once they are built |
348 | + int16_t military_in_constr_nearby_; |
349 | + // actual count of soldiers in nearby buldings |
350 | + int16_t military_presence_; |
351 | + // stationed (manned) military buildings nearby |
352 | + int16_t military_stationed_; |
353 | + |
354 | + std::vector<uint8_t> consumers_nearby_; |
355 | + std::vector<uint8_t> producers_nearby_; |
356 | + |
357 | + BuildableField(const Widelands::FCoords& fc) |
358 | + : coords(fc), |
359 | + next_update_due_(0), |
360 | + reachable(false), |
361 | + preferred_(false), |
362 | + enemy_nearby_(0), |
363 | + unowned_land_nearby_(0), |
364 | + trees_nearby_(0), |
365 | + // explanation of starting values |
366 | + // this is done to save some work for AI (CPU utilization) |
367 | + // base rules are: |
368 | + // count of stones can only decrease, so amount of stones |
369 | + // is recalculated only when previous count is positive |
370 | + // count of water fields are stable, so if the current count is |
371 | + // non-negative, water is not recaldulated |
372 | + stones_nearby_(1), |
373 | + water_nearby_(-1), |
374 | + ground_water_(1), |
375 | + space_consumers_nearby_(0), |
376 | + military_capacity_(0), |
377 | + military_loneliness_(1000), |
378 | + military_in_constr_nearby_(0), |
379 | + military_presence_(0), |
380 | + military_stationed_(0) { |
381 | + } |
382 | }; |
383 | |
384 | struct MineableField { |
385 | Widelands::FCoords coords; |
386 | |
387 | - int32_t next_update_due; |
388 | - |
389 | - bool reachable; |
390 | - bool preferred; |
391 | - |
392 | - int32_t mines_nearby; |
393 | - |
394 | - MineableField (const Widelands::FCoords & fc) : |
395 | - coords (fc), |
396 | - next_update_due(0), |
397 | - reachable (false), |
398 | - preferred (false), |
399 | - mines_nearby(0) |
400 | - {} |
401 | + int32_t next_update_due_; |
402 | + |
403 | + bool reachable; |
404 | + bool preferred_; |
405 | + |
406 | + int32_t mines_nearby_; |
407 | + |
408 | + MineableField(const Widelands::FCoords& fc) |
409 | + : coords(fc), next_update_due_(0), reachable(false), preferred_(false), mines_nearby_(0) { |
410 | + } |
411 | }; |
412 | |
413 | struct EconomyObserver { |
414 | - Widelands::Economy & economy; |
415 | - std::list<Widelands::Flag const *> flags; |
416 | - int32_t next_connection_try; |
417 | - uint32_t failed_connection_tries; |
418 | + Widelands::Economy& economy; |
419 | + std::list<Widelands::Flag const*> flags; |
420 | + int32_t next_connection_try; |
421 | + uint32_t failed_connection_tries; |
422 | |
423 | - EconomyObserver (Widelands::Economy & e) : economy(e) { |
424 | + EconomyObserver(Widelands::Economy& e) : economy(e) { |
425 | next_connection_try = 0; |
426 | failed_connection_tries = 0; |
427 | } |
428 | }; |
429 | |
430 | struct BuildingObserver { |
431 | - char const * name; |
432 | - Widelands::Building_Index id; |
433 | - Widelands::Building_Descr const * desc; |
434 | + char const* name; |
435 | + Widelands::Building_Index id; |
436 | + Widelands::Building_Descr const* desc; |
437 | |
438 | enum { |
439 | BORING, |
440 | @@ -224,56 +257,66 @@ |
441 | WAREHOUSE, |
442 | TRAININGSITE, |
443 | MINE |
444 | - } type; |
445 | - |
446 | - bool is_basic; // is a "must" to have for the ai |
447 | - bool prod_build_material; |
448 | - bool recruitment; // is "producing" workers? |
449 | - |
450 | - bool is_buildable; |
451 | - |
452 | - bool need_trees; // lumberjack = true |
453 | - bool need_stones; // quarry = true |
454 | - bool need_water; // fisher, fish_breeder = true |
455 | - bool space_consumer; // farm, vineyard... = true |
456 | - |
457 | - bool unoccupied; // >= 1 building unoccupied ? |
458 | - |
459 | - int32_t mines; // type of resource it mines |
460 | - uint16_t mines_percent; // % of res it can mine |
461 | - |
462 | - uint32_t current_stats; |
463 | - |
464 | - std::vector<int16_t> inputs; |
465 | - std::vector<int16_t> outputs; |
466 | - int16_t production_hint; |
467 | - |
468 | - int32_t cnt_built; |
469 | - int32_t cnt_under_construction; |
470 | - |
471 | - int32_t total_count() const {return cnt_built + cnt_under_construction;} |
472 | - bool buildable(Widelands::Player & player) { |
473 | - return is_buildable && player.is_building_type_allowed(id); |
474 | + } type; |
475 | + |
476 | + bool is_basic_; // is a "must" to have for the ai |
477 | + bool prod_build_material_; |
478 | + bool plants_trees_; |
479 | + bool recruitment_; // is "producing" workers? |
480 | + bool is_buildable_; |
481 | + bool need_trees_; // lumberjack = true |
482 | + bool need_stones_; // quarry = true |
483 | + bool mines_marble_; // need to distinquish mines_ that produce marbles |
484 | + bool mines_water_; // wells |
485 | + bool need_water_; // fisher, fish_breeder = true |
486 | + bool space_consumer_; // farm, vineyard... = true |
487 | + |
488 | + bool unoccupied_; // |
489 | + |
490 | + int32_t mines_; // type of resource it mines_ |
491 | + uint16_t mines_percent_; // % of res it can mine |
492 | + |
493 | + uint32_t current_stats_; |
494 | + |
495 | + std::vector<int16_t> inputs_; |
496 | + std::vector<int16_t> outputs_; |
497 | + int16_t production_hint_; |
498 | + |
499 | + int32_t cnt_built_; |
500 | + int32_t cnt_under_construction_; |
501 | + int32_t cnt_target_; // number of buildings as target |
502 | + |
503 | + // used to track amount of wares produced by building |
504 | + uint32_t stocklevel_; |
505 | + int32_t stocklevel_time; // time when stocklevel_ was last time recalculated |
506 | + int32_t last_dismantle_time_; |
507 | + int32_t construction_decision_time_; |
508 | + |
509 | + int32_t total_count() const { |
510 | + return cnt_built_ + cnt_under_construction_; |
511 | + } |
512 | + bool buildable(Widelands::Player& player_) { |
513 | + return is_buildable_ && player_.is_building_type_allowed(id); |
514 | } |
515 | }; |
516 | |
517 | struct ProductionSiteObserver { |
518 | - Widelands::ProductionSite * site; |
519 | - int32_t builttime; |
520 | - uint8_t statszero; |
521 | - BuildingObserver * bo; |
522 | + Widelands::ProductionSite* site; |
523 | + int32_t built_time_; |
524 | + uint8_t stats_zero_; |
525 | + BuildingObserver* bo; |
526 | }; |
527 | |
528 | struct MilitarySiteObserver { |
529 | - Widelands::MilitarySite * site; |
530 | - BuildingObserver * bo; |
531 | + Widelands::MilitarySite* site; |
532 | + BuildingObserver* bo; |
533 | uint8_t checks; |
534 | }; |
535 | |
536 | struct WareObserver { |
537 | - uint8_t producers; |
538 | - uint8_t consumers; |
539 | - uint8_t preciousness; |
540 | + uint8_t producers_; |
541 | + uint8_t consumers_; |
542 | + uint8_t preciousness_; |
543 | }; |
544 | |
545 | #endif |
546 | |
547 | === modified file 'src/ai/ai_hints.cc' |
548 | --- src/ai/ai_hints.cc 2014-03-15 11:29:32 +0000 |
549 | +++ src/ai/ai_hints.cc 2014-06-10 18:35:21 +0000 |
550 | @@ -23,29 +23,28 @@ |
551 | |
552 | #include "profile/profile.h" |
553 | |
554 | - |
555 | -BuildingHints::~BuildingHints () |
556 | -{ |
557 | +BuildingHints::~BuildingHints() { |
558 | free(renews_map_resource); |
559 | - free(mines); |
560 | + free(mines_); |
561 | } |
562 | |
563 | -BuildingHints::BuildingHints (Section * const section) : |
564 | - renews_map_resource(nullptr), |
565 | - mines (nullptr), |
566 | - basic (section ? section->get_bool("is_basic") : false), |
567 | - build_material (section ? section->get_bool("build_material") : true), |
568 | - logproducer (section ? section->get_bool("logproducer") : false), |
569 | - stoneproducer (section ? section->get_bool("stoneproducer") : false), |
570 | - needs_water (section ? section->get_bool("needs_water") : false), |
571 | - recruitment (section ? section->get_bool("recruitment") : false), |
572 | - space_consumer (section ? section->get_bool("space_consumer") : false), |
573 | - mines_percent (section ? section->get_int ("mines_percent", 100) : 0) |
574 | -{ |
575 | +BuildingHints::BuildingHints(Section* const section) |
576 | + : renews_map_resource(nullptr), |
577 | + mines_(nullptr), |
578 | + basic_(section ? section->get_bool("is_basic") : false), |
579 | + build_material_(section ? section->get_bool("build_material") : true), |
580 | + log_producer_(section ? section->get_bool("logproducer") : false), |
581 | + stone_producer_(section ? section->get_bool("stoneproducer") : false), |
582 | + marble_producer_(section ? section->get_bool("marbleproducer") : false), |
583 | + needs_water_(section ? section->get_bool("needs_water") : false), |
584 | + mines_water_(section ? section->get_bool("mines_water") : false), |
585 | + recruitment_(section ? section->get_bool("recruitment") : false), |
586 | + space_consumer_(section ? section->get_bool("space_consumer") : false), |
587 | + mines_percent_(section ? section->get_int("mines_percent", 100) : 0) { |
588 | if (section) { |
589 | - if (char const * const s = section->get_string("renews_map_resource")) |
590 | + if (char const* const s = section->get_string("renews_map_resource")) |
591 | renews_map_resource = strdup(s); |
592 | - if (char const * const s = section->get_string("mines")) |
593 | - mines = strdup(s); |
594 | + if (char const* const s = section->get_string("mines")) |
595 | + mines_ = strdup(s); |
596 | } |
597 | } |
598 | |
599 | === modified file 'src/ai/ai_hints.h' |
600 | --- src/ai/ai_hints.h 2014-03-15 11:29:32 +0000 |
601 | +++ src/ai/ai_hints.h 2014-06-10 18:35:21 +0000 |
602 | @@ -29,40 +29,70 @@ |
603 | /// buildings conf file. It is used to tell the computer player about the |
604 | /// special properties of a building. |
605 | struct BuildingHints : boost::noncopyable { |
606 | - BuildingHints (Section *); |
607 | + BuildingHints(Section*); |
608 | ~BuildingHints(); |
609 | |
610 | - char const * get_renews_map_resource() const {return renews_map_resource;} |
611 | - |
612 | - char const * get_mines () const {return mines;} |
613 | - |
614 | - bool is_basic () const {return basic;} |
615 | - |
616 | - bool prod_build_material () const {return build_material;} |
617 | - |
618 | - bool is_logproducer () const {return logproducer;} |
619 | - |
620 | - bool is_stoneproducer () const {return stoneproducer;} |
621 | - |
622 | - bool get_needs_water () const {return needs_water;} |
623 | - |
624 | - bool for_recruitment () const {return recruitment;} |
625 | - |
626 | - bool is_space_consumer () const {return space_consumer;} |
627 | - |
628 | - uint8_t get_mines_percent () const {return mines_percent;} |
629 | + char const* get_renews_map_resource() const { |
630 | + return renews_map_resource; |
631 | + } |
632 | + |
633 | + char const* get_mines() const { |
634 | + return mines_; |
635 | + } |
636 | + |
637 | + bool is_basic() const { |
638 | + return basic_; |
639 | + } |
640 | + |
641 | + bool prod_build_material() const { |
642 | + return build_material_; |
643 | + } |
644 | + |
645 | + bool is_logproducer() const { |
646 | + return log_producer_; |
647 | + } |
648 | + |
649 | + bool is_stoneproducer() const { |
650 | + return stone_producer_; |
651 | + } |
652 | + |
653 | + bool is_marbleproducer() const { |
654 | + return marble_producer_; |
655 | + } |
656 | + |
657 | + bool mines_water() const { |
658 | + return mines_water_; |
659 | + } |
660 | + |
661 | + bool get_needs_water() const { |
662 | + return needs_water_; |
663 | + } |
664 | + |
665 | + bool for_recruitment() const { |
666 | + return recruitment_; |
667 | + } |
668 | + |
669 | + bool is_space_consumer() const { |
670 | + return space_consumer_; |
671 | + } |
672 | + |
673 | + uint8_t get_mines_percent() const { |
674 | + return mines_percent_; |
675 | + } |
676 | |
677 | private: |
678 | - char * renews_map_resource; |
679 | - char * mines; |
680 | - bool basic; |
681 | - bool build_material; // whether the building produces build material |
682 | - bool logproducer; |
683 | - bool stoneproducer; |
684 | - bool needs_water; |
685 | - bool recruitment; // whether building recruits special workers |
686 | - bool space_consumer; |
687 | - uint8_t mines_percent; |
688 | + char* renews_map_resource; |
689 | + char* mines_; |
690 | + bool basic_; |
691 | + bool build_material_; // whether the building produces build material |
692 | + bool log_producer_; |
693 | + bool stone_producer_; |
694 | + bool marble_producer_; |
695 | + bool needs_water_; |
696 | + bool mines_water_; |
697 | + bool recruitment_; // whether building recruits special workers |
698 | + bool space_consumer_; |
699 | + uint8_t mines_percent_; |
700 | }; |
701 | |
702 | #endif |
703 | |
704 | === modified file 'src/ai/defaultai.cc' |
705 | --- src/ai/defaultai.cc 2014-04-29 18:39:52 +0000 |
706 | +++ src/ai/defaultai.cc 2014-06-10 18:35:21 +0000 |
707 | @@ -46,7 +46,30 @@ |
708 | #include "profile/profile.h" |
709 | #include "upcast.h" |
710 | |
711 | -#define FIELD_UPDATE_INTERVAL 1000 |
712 | +constexpr int kFieldUpdateInterval = 1000; |
713 | +constexpr int kIdleMineUpdateInterval = 22000; |
714 | +constexpr int kBusyMineUpdateInterval = 2000; |
715 | +constexpr int kBuildingMinInterval = |
716 | + 25 * 1000; // building of the same building can be started after 25s at earliest |
717 | +constexpr bool kMilitaryDebug = false; |
718 | +constexpr bool kMilDismDebug = false; |
719 | +constexpr bool kMilitScoreDebug = false; |
720 | +constexpr bool kQuarryDismDebug = false; |
721 | +constexpr bool kProductionDebug = false; |
722 | +constexpr bool kHintDebug = false; |
723 | +constexpr bool kWinnerDebug = false; |
724 | +constexpr bool kNewBuildingDebug = false; |
725 | +constexpr bool kStandbyDebug = false; |
726 | +constexpr bool kMinesDebug = false; |
727 | +constexpr bool kUpgradeDebug = false; |
728 | +constexpr bool kStockDebug = false; |
729 | +constexpr bool kMinesUpdateDebug = false; |
730 | +constexpr bool kWoodDebug = false; |
731 | +constexpr bool kSpaceDebug = false; |
732 | +constexpr bool kStatDebug = false; |
733 | +constexpr bool kIdleDismantle = false; |
734 | +constexpr bool kWellDebug = false; |
735 | +constexpr int kBaseInfrastructureTime = 20 * 60 * 1000; |
736 | |
737 | using namespace Widelands; |
738 | |
739 | @@ -55,52 +78,59 @@ |
740 | DefaultAI::DefensiveImpl DefaultAI::defensiveImpl; |
741 | |
742 | /// Constructor of DefaultAI |
743 | -DefaultAI::DefaultAI(Game & ggame, Player_Number const pid, uint8_t const t) : |
744 | - Computer_Player (ggame, pid), |
745 | - type (t), |
746 | - m_buildable_changed (true), |
747 | - m_mineable_changed (true), |
748 | - player (nullptr), |
749 | - tribe (nullptr), |
750 | - total_constructionsites (0), |
751 | - next_road_due (2000), |
752 | - next_stats_update_due (30000), |
753 | - next_construction_due (1000), |
754 | - next_productionsite_check_due(0), |
755 | - next_mine_check_due (0), |
756 | - next_militarysite_check_due (0), |
757 | - next_attack_consideration_due(300000), |
758 | - inhibit_road_building (0), |
759 | - time_of_last_construction (0), |
760 | - numof_warehouses (0) |
761 | -{} |
762 | +DefaultAI::DefaultAI(Game& ggame, Player_Number const pid, uint8_t const t) |
763 | + : Computer_Player(ggame, pid), |
764 | + type(t), |
765 | + m_buildable_changed(true), |
766 | + m_mineable_changed(true), |
767 | + player(nullptr), |
768 | + tribe(nullptr), |
769 | + total_constructionsites(0), |
770 | + next_road_due_(2000), |
771 | + next_stats_update_due_(30000), |
772 | + next_construction_due_(1000), |
773 | + next_mine_construction_due_(0), |
774 | + next_productionsite_check_due_(0), |
775 | + next_mine_check_due_(0), |
776 | + next_militarysite_check_due_(0), |
777 | + next_attack_consideration_due_(300000), |
778 | + next_helpersites_check_due_(180000), |
779 | + inhibit_road_building_(0), |
780 | + time_of_last_construction_(0), |
781 | + numof_warehouses_(0), |
782 | + new_buildings_stop_(false), |
783 | + unstationed_milit_buildings_(0), |
784 | + military_under_constr_(0), |
785 | + military_last_dismantle_(0), |
786 | + military_last_build_(0) { |
787 | +} |
788 | |
789 | -DefaultAI::~DefaultAI() |
790 | -{ |
791 | +DefaultAI::~DefaultAI() { |
792 | while (not buildable_fields.empty()) { |
793 | delete buildable_fields.back(); |
794 | buildable_fields.pop_back(); |
795 | } |
796 | + |
797 | while (not mineable_fields.empty()) { |
798 | delete mineable_fields.back(); |
799 | mineable_fields.pop_back(); |
800 | } |
801 | + |
802 | while (not economies.empty()) { |
803 | delete economies.back(); |
804 | economies.pop_back(); |
805 | } |
806 | } |
807 | |
808 | - |
809 | /** |
810 | - * Main loop of computer player "defaultAI" |
811 | + * Main loop of computer player_ "defaultAI" |
812 | * |
813 | * General behaviour is defined here. |
814 | */ |
815 | -void DefaultAI::think () |
816 | -{ |
817 | +void DefaultAI::think() { |
818 | + |
819 | if (tribe == nullptr) |
820 | - late_initialization (); |
821 | + late_initialization(); |
822 | |
823 | const int32_t gametime = game().get_gametime(); |
824 | |
825 | @@ -108,19 +138,16 @@ |
826 | // update statistics about buildable fields |
827 | update_all_buildable_fields(gametime); |
828 | } |
829 | - if (m_mineable_changed) { |
830 | - // do the same for mineable fields |
831 | - update_all_mineable_fields(gametime); |
832 | - } |
833 | + |
834 | m_buildable_changed = false; |
835 | - m_mineable_changed = false; |
836 | |
837 | // if there are more than one economy try to connect them with a road. |
838 | - if (next_road_due <= gametime) { |
839 | - next_road_due = gametime + 1000; |
840 | - if (construct_roads (gametime)) { |
841 | + if (next_road_due_ <= gametime) { |
842 | + next_road_due_ = gametime + 1000; |
843 | + |
844 | + if (construct_roads(gametime)) { |
845 | m_buildable_changed = true; |
846 | - m_mineable_changed = true; |
847 | + // m_mineable_changed = true; |
848 | return; |
849 | } |
850 | } else |
851 | @@ -129,9 +156,8 @@ |
852 | |
853 | // NOTE Because of the check above, the following parts of think() are used |
854 | // NOTE only once every second at maximum. This increases performance and as |
855 | - // NOTE human players can not even react that fast, it should not be a |
856 | + // NOTE human player_s can not even react that fast, it should not be a |
857 | // NOTE disadvantage for the defaultAI. |
858 | - |
859 | // This must be checked every time as changes of bobs in AI area aren't |
860 | // handled by the AI itself. |
861 | update_all_not_buildable_fields(); |
862 | @@ -139,7 +165,7 @@ |
863 | // IF defaultAI is AGGRESSIVE - we definitely should consider to attack as |
864 | // often as possible. |
865 | if (type == AGGRESSIVE) |
866 | - if (next_attack_consideration_due <= gametime) |
867 | + if (next_attack_consideration_due_ <= gametime) |
868 | consider_attack(gametime); |
869 | |
870 | // check if anything in the economies changed. |
871 | @@ -150,14 +176,15 @@ |
872 | |
873 | // Before thinking about a new construction, update current stats, to have |
874 | // a better view on current economy. |
875 | - if (next_stats_update_due <= gametime) |
876 | + if (next_stats_update_due_ <= gametime) |
877 | update_productionsite_stats(gametime); |
878 | |
879 | // Now try to build something if possible |
880 | - if (next_construction_due <= gametime) { |
881 | - next_construction_due = gametime + 2000; |
882 | + if (next_construction_due_ <= gametime) { |
883 | + next_construction_due_ = gametime + 2000; |
884 | + |
885 | if (construct_building(gametime)) { |
886 | - time_of_last_construction = gametime; |
887 | + time_of_last_construction_ = gametime; |
888 | return; |
889 | } |
890 | } |
891 | @@ -167,7 +194,7 @@ |
892 | return; |
893 | |
894 | // Check the mines and consider upgrading or destroying one |
895 | - if (check_mines(gametime)) |
896 | + if (check_mines_(gametime)) |
897 | return; |
898 | |
899 | // consider whether a change of the soldier capacity of some militarysites |
900 | @@ -178,7 +205,7 @@ |
901 | // Finally consider military actions if defaultAI type is Aggressive or |
902 | // Normal. |
903 | if (!(type == DEFENSIVE)) |
904 | - if (next_attack_consideration_due <= gametime) |
905 | + if (next_attack_consideration_due_ <= gametime) |
906 | consider_attack(gametime); |
907 | |
908 | // improve existing roads! |
909 | @@ -191,14 +218,13 @@ |
910 | if (improve_roads(gametime)) { |
911 | m_buildable_changed = true; |
912 | m_mineable_changed = true; |
913 | - inhibit_road_building = gametime + 2500; |
914 | + inhibit_road_building_ = gametime + 2500; |
915 | return; |
916 | } |
917 | } |
918 | |
919 | /// called by Widelands game engine when an immovable changed |
920 | -void DefaultAI::receive(const NoteImmovable & note) |
921 | -{ |
922 | +void DefaultAI::receive(const NoteImmovable& note) { |
923 | if (note.lg == LOSE) |
924 | lose_immovable(*note.pi); |
925 | else |
926 | @@ -206,95 +232,104 @@ |
927 | } |
928 | |
929 | /// called by Widelands game engine when a field changed |
930 | -void DefaultAI::receive(const NoteFieldPossession & note) |
931 | -{ |
932 | +void DefaultAI::receive(const NoteFieldPossession& note) { |
933 | if (note.lg == GAIN) |
934 | unusable_fields.push_back(note.fc); |
935 | } |
936 | |
937 | - |
938 | /** |
939 | * Cares for all variables not initialised during construction |
940 | * |
941 | * When DefaultAI is constructed, some information is not yet available (e.g. |
942 | * world), so this is done after complete loading of the map. |
943 | */ |
944 | -void DefaultAI::late_initialization () |
945 | -{ |
946 | +void DefaultAI::late_initialization() { |
947 | player = game().get_player(player_number()); |
948 | NoteReceiver<NoteImmovable>::connect(*player); |
949 | NoteReceiver<NoteFieldPossession>::connect(*player); |
950 | tribe = &player->tribe(); |
951 | - |
952 | - log ("ComputerPlayer(%d): initializing (%u)\n", player_number(), type); |
953 | - |
954 | + log("ComputerPlayer(%d): initializing (%u)\n", player_number(), type); |
955 | Ware_Index const nr_wares = tribe->get_nrwares(); |
956 | wares.resize(nr_wares); |
957 | + |
958 | for (Ware_Index i = 0; i < nr_wares; ++i) { |
959 | - wares.at(i).producers = 0; |
960 | - wares.at(i).consumers = 0; |
961 | - wares.at(i).preciousness = tribe->get_ware_descr(i)->preciousness(); |
962 | + wares.at(i).producers_ = 0; |
963 | + wares.at(i).consumers_ = 0; |
964 | + wares.at(i).preciousness_ = tribe->get_ware_descr(i)->preciousness(); |
965 | } |
966 | |
967 | // collect information about the different buildings our tribe can construct |
968 | Building_Index const nr_buildings = tribe->get_nrbuildings(); |
969 | - const World & world = game().map().world(); |
970 | + const World& world = game().map().world(); |
971 | + |
972 | for (Building_Index i = 0; i < nr_buildings; ++i) { |
973 | - const Building_Descr & bld = *tribe->get_building_descr(i); |
974 | - const std::string & building_name = bld.name(); |
975 | - const BuildingHints & bh = bld.hints(); |
976 | - |
977 | - buildings.resize (buildings.size() + 1); |
978 | - |
979 | - BuildingObserver & bo = buildings.back(); |
980 | - bo.name = building_name.c_str(); |
981 | - bo.id = i; |
982 | - bo.desc = &bld; |
983 | - bo.type = BuildingObserver::BORING; |
984 | - bo.cnt_built = 0; |
985 | - bo.cnt_under_construction = 0; |
986 | - bo.production_hint = -1; |
987 | - bo.current_stats = 100; |
988 | - bo.unoccupied = false; |
989 | - |
990 | - bo.is_basic = false; |
991 | - |
992 | - bo.is_buildable = bld.is_buildable(); |
993 | - |
994 | - bo.need_trees = bh.is_logproducer(); |
995 | - bo.need_stones = bh.is_stoneproducer(); |
996 | - bo.need_water = bh.get_needs_water(); |
997 | - bo.recruitment = bh.for_recruitment(); |
998 | - bo.space_consumer = bh.is_space_consumer(); |
999 | - |
1000 | - if (char const * const s = bh.get_renews_map_resource()) |
1001 | - bo.production_hint = tribe->safe_ware_index(s); |
1002 | + const Building_Descr& bld = *tribe->get_building_descr(i); |
1003 | + const std::string& building_name = bld.name(); |
1004 | + const BuildingHints& bh = bld.hints(); |
1005 | + buildings.resize(buildings.size() + 1); |
1006 | + BuildingObserver& bo = buildings.back(); |
1007 | + bo.name = building_name.c_str(); |
1008 | + bo.id = i; |
1009 | + bo.desc = &bld; |
1010 | + bo.type = BuildingObserver::BORING; |
1011 | + bo.cnt_built_ = 0; |
1012 | + bo.cnt_under_construction_ = 0; |
1013 | + bo.cnt_target_ = 0; |
1014 | + bo.stocklevel_ = 0; |
1015 | + bo.stocklevel_time = 0; |
1016 | + bo.last_dismantle_time_ = 0; |
1017 | + // this is set to negative number, otherwise the AI would wait 25 sec |
1018 | + // after game start not building anything |
1019 | + bo.construction_decision_time_ = -60 * 60 * 1000; |
1020 | + bo.production_hint_ = -1; |
1021 | + bo.current_stats_ = 0; |
1022 | + bo.unoccupied_ = false; |
1023 | + bo.is_basic_ = false; |
1024 | + bo.is_buildable_ = bld.is_buildable(); |
1025 | + bo.need_trees_ = bh.is_logproducer(); |
1026 | + bo.need_stones_ = bh.is_stoneproducer(); |
1027 | + bo.mines_marble_ = bh.is_marbleproducer(); |
1028 | + bo.need_water_ = bh.get_needs_water(); |
1029 | + bo.mines_water_ = bh.mines_water(); |
1030 | + bo.recruitment_ = bh.for_recruitment(); |
1031 | + bo.space_consumer_ = bh.is_space_consumer(); |
1032 | + |
1033 | + if (char const* const s = bh.get_renews_map_resource()) { |
1034 | + bo.production_hint_ = tribe->safe_ware_index(s); |
1035 | + |
1036 | + if (kHintDebug) |
1037 | + printf(" TDEBUG: %-20s get production hint: %d\n", bo.name, bo.production_hint_); |
1038 | + } |
1039 | + |
1040 | + // I just presume cut wood is named "log" in the game |
1041 | + if (tribe->safe_ware_index("log") == bo.production_hint_) |
1042 | + bo.plants_trees_ = true; |
1043 | + else |
1044 | + bo.plants_trees_ = false; |
1045 | + |
1046 | + if (kHintDebug) |
1047 | + printf(" building %-15s: plants trees: %s\n", bo.name, bo.plants_trees_ ? "Y" : "N"); |
1048 | |
1049 | // Read all interesting data from ware producing buildings |
1050 | if (typeid(bld) == typeid(ProductionSite_Descr)) { |
1051 | - const ProductionSite_Descr & prod = |
1052 | - ref_cast<ProductionSite_Descr const, Building_Descr const>(bld); |
1053 | - |
1054 | - bo.type = |
1055 | - bld.get_ismine() ? BuildingObserver::MINE : |
1056 | - BuildingObserver::PRODUCTIONSITE; |
1057 | - |
1058 | + const ProductionSite_Descr& prod = |
1059 | + ref_cast<ProductionSite_Descr const, Building_Descr const>(bld); |
1060 | + bo.type = bld.get_ismine() ? BuildingObserver::MINE : BuildingObserver::PRODUCTIONSITE; |
1061 | container_iterate_const(BillOfMaterials, prod.inputs(), j) |
1062 | - bo.inputs.push_back(j.current->first); |
1063 | - |
1064 | - container_iterate_const |
1065 | - (ProductionSite_Descr::Output, prod.output_ware_types(), j) |
1066 | - bo.outputs.push_back(*j.current); |
1067 | + bo.inputs_.push_back(j.current->first); |
1068 | + container_iterate_const(ProductionSite_Descr::Output, prod.output_ware_types(), j) |
1069 | + bo.outputs_.push_back(*j.current); |
1070 | |
1071 | if (bo.type == BuildingObserver::MINE) { |
1072 | // get the resource needed by the mine |
1073 | - if (char const * const s = bh.get_mines()) |
1074 | - bo.mines = world.get_resource(s); |
1075 | - bo.mines_percent = bh.get_mines_percent(); |
1076 | + if (char const* const s = bh.get_mines()) |
1077 | + bo.mines_ = world.get_resource(s); |
1078 | + |
1079 | + bo.mines_percent_ = bh.get_mines_percent(); |
1080 | } |
1081 | |
1082 | - bo.is_basic = bh.is_basic(); |
1083 | - bo.prod_build_material = bh.prod_build_material(); |
1084 | + bo.is_basic_ = bh.is_basic(); |
1085 | + bo.prod_build_material_ = bh.prod_build_material(); |
1086 | |
1087 | continue; |
1088 | } |
1089 | @@ -320,15 +355,14 @@ |
1090 | } |
1091 | } |
1092 | |
1093 | - total_constructionsites = 0; |
1094 | - next_construction_due = 0; |
1095 | - next_road_due = 1000; |
1096 | - next_productionsite_check_due = 0; |
1097 | - inhibit_road_building = 0; |
1098 | - |
1099 | + total_constructionsites = 0; |
1100 | + next_construction_due_ = 0; |
1101 | + next_road_due_ = 1000; |
1102 | + next_productionsite_check_due_ = 0; |
1103 | + inhibit_road_building_ = 0; |
1104 | // Add all fields that we own |
1105 | - Map & map = game().map(); |
1106 | - std::set<OPtr<PlayerImmovable> > found_immovables; |
1107 | + Map& map = game().map(); |
1108 | + std::set<OPtr<PlayerImmovable>> found_immovables; |
1109 | |
1110 | for (Y_Coordinate y = 0; y < map.get_height(); ++y) { |
1111 | for (X_Coordinate x = 0; x < map.get_width(); ++x) { |
1112 | @@ -337,9 +371,10 @@ |
1113 | if (f.field->get_owned_by() != player_number()) |
1114 | continue; |
1115 | |
1116 | - unusable_fields.push_back (f); |
1117 | + unusable_fields.push_back(f); |
1118 | |
1119 | if (upcast(PlayerImmovable, imm, f.field->get_immovable())) |
1120 | + |
1121 | // Guard by a set - immovables might be on several nodes at once. |
1122 | if (&imm->owner() == player and not found_immovables.count(imm)) { |
1123 | found_immovables.insert(imm); |
1124 | @@ -349,21 +384,15 @@ |
1125 | } |
1126 | } |
1127 | |
1128 | - |
1129 | /** |
1130 | * Checks ALL available buildable fields. |
1131 | * |
1132 | * this shouldn't be used often, as it might hang the game for some 100 |
1133 | * milliseconds if the area the computer owns is big. |
1134 | */ |
1135 | -void DefaultAI::update_all_buildable_fields(const int32_t gametime) |
1136 | -{ |
1137 | - while |
1138 | - (not buildable_fields.empty() |
1139 | - and |
1140 | - buildable_fields.front()->next_update_due <= gametime) |
1141 | - { |
1142 | - BuildableField & bf = *buildable_fields.front(); |
1143 | +void DefaultAI::update_all_buildable_fields(const int32_t gametime) { |
1144 | + while (not buildable_fields.empty() and buildable_fields.front()->next_update_due_ <= gametime) { |
1145 | + BuildableField& bf = *buildable_fields.front(); |
1146 | |
1147 | // check whether we lost ownership of the node |
1148 | if (bf.coords.field->get_owned_by() != player_number()) { |
1149 | @@ -374,17 +403,16 @@ |
1150 | |
1151 | // check whether we can still construct regular buildings on the node |
1152 | if ((player->get_buildcaps(bf.coords) & BUILDCAPS_SIZEMASK) == 0) { |
1153 | - unusable_fields.push_back (bf.coords); |
1154 | + unusable_fields.push_back(bf.coords); |
1155 | delete &bf; |
1156 | buildable_fields.pop_front(); |
1157 | continue; |
1158 | } |
1159 | |
1160 | - update_buildable_field (bf); |
1161 | - bf.next_update_due = gametime + FIELD_UPDATE_INTERVAL; |
1162 | - |
1163 | - buildable_fields.push_back (&bf); |
1164 | - buildable_fields.pop_front (); |
1165 | + update_buildable_field(bf); |
1166 | + bf.next_update_due_ = gametime + kFieldUpdateInterval; |
1167 | + buildable_fields.push_back(&bf); |
1168 | + buildable_fields.pop_front(); |
1169 | } |
1170 | } |
1171 | |
1172 | @@ -394,14 +422,9 @@ |
1173 | * this shouldn't be used often, as it might hang the game for some 100 |
1174 | * milliseconds if the area the computer owns is big. |
1175 | */ |
1176 | -void DefaultAI::update_all_mineable_fields(const int32_t gametime) |
1177 | -{ |
1178 | - while |
1179 | - (not mineable_fields.empty() |
1180 | - and |
1181 | - mineable_fields.front()->next_update_due <= gametime) |
1182 | - { |
1183 | - MineableField * mf = mineable_fields.front(); |
1184 | +void DefaultAI::update_all_mineable_fields(const int32_t gametime) { |
1185 | + while (not mineable_fields.empty() and mineable_fields.front()->next_update_due_ <= gametime) { |
1186 | + MineableField* mf = mineable_fields.front(); |
1187 | |
1188 | // check whether we lost ownership of the node |
1189 | if (mf->coords.field->get_owned_by() != player_number()) { |
1190 | @@ -412,18 +435,16 @@ |
1191 | |
1192 | // check whether we can still construct regular buildings on the node |
1193 | if ((player->get_buildcaps(mf->coords) & BUILDCAPS_MINE) == 0) { |
1194 | - unusable_fields.push_back (mf->coords); |
1195 | + unusable_fields.push_back(mf->coords); |
1196 | delete mf; |
1197 | - |
1198 | mineable_fields.pop_front(); |
1199 | continue; |
1200 | } |
1201 | |
1202 | - update_mineable_field (*mf); |
1203 | - mf->next_update_due = gametime + FIELD_UPDATE_INTERVAL; |
1204 | - |
1205 | - mineable_fields.push_back (mf); |
1206 | - mineable_fields.pop_front (); |
1207 | + update_mineable_field(*mf); |
1208 | + mf->next_update_due_ = gametime + kFieldUpdateInterval; // in fact this has very small effect |
1209 | + mineable_fields.push_back(mf); |
1210 | + mineable_fields.pop_front(); |
1211 | } |
1212 | } |
1213 | |
1214 | @@ -432,10 +453,10 @@ |
1215 | * |
1216 | * milliseconds if the area the computer owns is big. |
1217 | */ |
1218 | -void DefaultAI::update_all_not_buildable_fields() |
1219 | -{ |
1220 | +void DefaultAI::update_all_not_buildable_fields() { |
1221 | int32_t const pn = player_number(); |
1222 | uint32_t maxchecks = unusable_fields.size(); |
1223 | + |
1224 | if (maxchecks > 50) |
1225 | maxchecks = 50; |
1226 | |
1227 | @@ -447,24 +468,17 @@ |
1228 | } |
1229 | |
1230 | // check whether building capabilities have improved |
1231 | - if (player->get_buildcaps(unusable_fields.front()) & BUILDCAPS_SIZEMASK) |
1232 | - { |
1233 | - |
1234 | - buildable_fields.push_back |
1235 | - (new BuildableField(unusable_fields.front())); |
1236 | + if (player->get_buildcaps(unusable_fields.front()) & BUILDCAPS_SIZEMASK) { |
1237 | + buildable_fields.push_back(new BuildableField(unusable_fields.front())); |
1238 | unusable_fields.pop_front(); |
1239 | - |
1240 | - update_buildable_field (*buildable_fields.back()); |
1241 | + update_buildable_field(*buildable_fields.back()); |
1242 | continue; |
1243 | } |
1244 | |
1245 | if (player->get_buildcaps(unusable_fields.front()) & BUILDCAPS_MINE) { |
1246 | - |
1247 | - mineable_fields.push_back |
1248 | - (new MineableField(unusable_fields.front())); |
1249 | + mineable_fields.push_back(new MineableField(unusable_fields.front())); |
1250 | unusable_fields.pop_front(); |
1251 | - |
1252 | - update_mineable_field (*mineable_fields.back()); |
1253 | + update_mineable_field(*mineable_fields.back()); |
1254 | continue; |
1255 | } |
1256 | |
1257 | @@ -473,763 +487,1116 @@ |
1258 | } |
1259 | } |
1260 | |
1261 | - |
1262 | /// Updates one buildable field |
1263 | -void DefaultAI::update_buildable_field |
1264 | - (BuildableField & field, uint16_t range, bool military) |
1265 | -{ |
1266 | +void DefaultAI::update_buildable_field(BuildableField& field, uint16_t range, bool military) { |
1267 | // look if there is any unowned land nearby |
1268 | - Map & map = game().map(); |
1269 | + Map& map = game().map(); |
1270 | FindNodeUnowned find_unowned(player, game()); |
1271 | + FindNodeUnownedMineable find_unowned_mines_pots(player, game()); |
1272 | Player_Number const pn = player->player_number(); |
1273 | + field.unowned_land_nearby_ = |
1274 | + map.find_fields(Area<FCoords>(field.coords, range), nullptr, find_unowned); |
1275 | |
1276 | - field.unowned_land_nearby = |
1277 | - map.find_fields(Area<FCoords>(field.coords, range), nullptr, find_unowned); |
1278 | + if (field.unowned_land_nearby_ > 2) // 2 is 'reasonably low' number here |
1279 | + field.unowned_mines_pots_nearby_ = map.find_fields( |
1280 | + Area<FCoords>(field.coords, range + 2), |
1281 | + nullptr, |
1282 | + find_unowned_mines_pots); //+2: a mine can mine raw materials from some range |
1283 | + else |
1284 | + field.unowned_mines_pots_nearby_ = 0; |
1285 | |
1286 | // collect information about resources in the area |
1287 | std::vector<ImmovableFound> immovables; |
1288 | - |
1289 | // Search in a radius of range |
1290 | - map.find_immovables (Area<FCoords>(field.coords, range), &immovables); |
1291 | + map.find_immovables(Area<FCoords>(field.coords, range), &immovables); |
1292 | |
1293 | // Is this a general update or just for military consideration |
1294 | // (second is used in check_militarysites) |
1295 | if (!military) { |
1296 | - int32_t const tree_attr = Map_Object_Descr::get_attribute_id("tree"); |
1297 | - int32_t const stone_attr = Map_Object_Descr::get_attribute_id("stone"); |
1298 | - |
1299 | - field.reachable = false; |
1300 | - field.preferred = false; |
1301 | - field.avoid_military = false; |
1302 | - field.enemy_nearby = false; |
1303 | - |
1304 | - field.military_influence = 0; |
1305 | - field.trees_nearby = 0; |
1306 | - field.stones_nearby = 0; |
1307 | - field.space_consumers_nearby = 0; |
1308 | - field.producers_nearby.clear(); |
1309 | - field.producers_nearby.resize(wares.size()); |
1310 | - field.consumers_nearby.clear(); |
1311 | - field.consumers_nearby.resize(wares.size()); |
1312 | + int32_t const tree_attr = Map_Object_Descr::get_attribute_id("tree"); |
1313 | + field.reachable = false; |
1314 | + field.preferred_ = false; |
1315 | + field.enemy_nearby_ = false; |
1316 | + field.military_capacity_ = 0; |
1317 | + field.military_loneliness_ = 1000; // instead of floats(v- |
1318 | + field.military_presence_ = 0; |
1319 | + field.military_stationed_ = 0; |
1320 | + field.trees_nearby_ = 0; |
1321 | + field.space_consumers_nearby_ = 0; |
1322 | + field.producers_nearby_.clear(); |
1323 | + field.producers_nearby_.resize(wares.size()); |
1324 | + field.consumers_nearby_.clear(); |
1325 | + field.consumers_nearby_.resize(wares.size()); |
1326 | std::vector<Coords> water_list; |
1327 | - FindNodeWater find_water; |
1328 | - map.find_fields(Area<FCoords>(field.coords, 4), &water_list, find_water); |
1329 | - field.water_nearby = water_list.size(); |
1330 | + |
1331 | + if (field.water_nearby_ == -1) { //-1 means "value has never been calculated" |
1332 | + FindNodeWater find_water; |
1333 | + map.find_fields(Area<FCoords>(field.coords, 4), &water_list, find_water); |
1334 | + field.water_nearby_ = water_list.size(); |
1335 | + } |
1336 | |
1337 | FCoords fse; |
1338 | - map.get_neighbour (field.coords, WALK_SE, &fse); |
1339 | + map.get_neighbour(field.coords, WALK_SE, &fse); |
1340 | |
1341 | - if (BaseImmovable const * const imm = fse.field->get_immovable()) |
1342 | - if |
1343 | - (dynamic_cast<Flag const *>(imm) |
1344 | - or |
1345 | - (dynamic_cast<Road const *>(imm) |
1346 | - && |
1347 | - (fse.field->nodecaps() & BUILDCAPS_FLAG))) |
1348 | - field.preferred = true; |
1349 | + if (BaseImmovable const* const imm = fse.field->get_immovable()) |
1350 | + if (dynamic_cast<Flag const*>(imm) |
1351 | + or(dynamic_cast<Road const*>(imm) && (fse.field->nodecaps() & BUILDCAPS_FLAG))) |
1352 | + field.preferred_ = true; |
1353 | |
1354 | for (uint32_t i = 0; i < immovables.size(); ++i) { |
1355 | - const BaseImmovable & base_immovable = *immovables.at(i).object; |
1356 | - if (dynamic_cast<const Flag *>(&base_immovable)) |
1357 | + const BaseImmovable& base_immovable = *immovables.at(i).object; |
1358 | + |
1359 | + if (dynamic_cast<const Flag*>(&base_immovable)) |
1360 | field.reachable = true; |
1361 | + |
1362 | if (upcast(PlayerImmovable const, player_immovable, &base_immovable)) |
1363 | - // TODO Only continue; if this is an opposing site |
1364 | - // TODO allied sites should be counted for military influence |
1365 | + |
1366 | + //// TODO Only continue; if this is an opposing site |
1367 | + //// TODO allied sites should be counted for military influence |
1368 | if (player_immovable->owner().player_number() != pn) { |
1369 | if (player->is_hostile(player_immovable->owner())) |
1370 | - field.enemy_nearby = true; |
1371 | + field.enemy_nearby_ = true; |
1372 | + |
1373 | continue; |
1374 | } |
1375 | |
1376 | if (upcast(Building const, building, &base_immovable)) { |
1377 | - |
1378 | if (upcast(ConstructionSite const, constructionsite, building)) { |
1379 | - const Building_Descr & target_descr = |
1380 | - constructionsite->building(); |
1381 | - |
1382 | - if |
1383 | - (upcast |
1384 | - (MilitarySite_Descr const, target_ms_d, &target_descr)) |
1385 | - { |
1386 | - const int32_t v = |
1387 | - target_ms_d->get_conquers() |
1388 | - - |
1389 | - map.calc_distance(field.coords, immovables.at(i).coords); |
1390 | - |
1391 | - if (0 < v) { |
1392 | - field.military_influence += v * (v + 2) * 6; |
1393 | - field.avoid_military = true; |
1394 | - } |
1395 | - } |
1396 | - |
1397 | - if (dynamic_cast<ProductionSite_Descr const *>(&target_descr)) |
1398 | - consider_productionsite_influence |
1399 | - (field, |
1400 | - immovables.at(i).coords, |
1401 | - get_building_observer(constructionsite->name().c_str())); |
1402 | - } |
1403 | - |
1404 | - if (upcast(MilitarySite const, militarysite, building)) { |
1405 | - const int32_t v = |
1406 | - militarysite->get_conquers() |
1407 | - - |
1408 | - map.calc_distance(field.coords, immovables.at(i).coords); |
1409 | - |
1410 | - if (v > 0) |
1411 | - field.military_influence += |
1412 | - v * v * militarysite->soldierCapacity(); |
1413 | - } |
1414 | - |
1415 | - if (dynamic_cast<const ProductionSite *>(building)) |
1416 | - consider_productionsite_influence |
1417 | - (field, |
1418 | - immovables.at(i).coords, |
1419 | - get_building_observer(building->name().c_str())); |
1420 | - |
1421 | - continue; |
1422 | + const Building_Descr& target_descr = constructionsite->building(); |
1423 | + |
1424 | + if (dynamic_cast<ProductionSite_Descr const*>(&target_descr)) |
1425 | + consider_productionsite_influence( |
1426 | + field, |
1427 | + immovables.at(i).coords, |
1428 | + get_building_observer(constructionsite->name().c_str())); |
1429 | + } |
1430 | + |
1431 | + if (dynamic_cast<const ProductionSite*>(building)) |
1432 | + consider_productionsite_influence( |
1433 | + field, immovables.at(i).coords, get_building_observer(building->name().c_str())); |
1434 | } |
1435 | |
1436 | if (immovables.at(i).object->has_attribute(tree_attr)) |
1437 | - ++field.trees_nearby; |
1438 | - |
1439 | - if (immovables.at(i).object->has_attribute(stone_attr)) |
1440 | - ++field.stones_nearby; |
1441 | - } |
1442 | - } else { // the small update just for military consideration |
1443 | - for (uint32_t i = 0; i < immovables.size(); ++i) { |
1444 | - const BaseImmovable & base_immovable = *immovables.at(i).object; |
1445 | - if (upcast(Building const, building, &base_immovable)) { |
1446 | - if (upcast(ConstructionSite const, constructionsite, building)) { |
1447 | - const Building_Descr & target_descr = |
1448 | - constructionsite->building(); |
1449 | - |
1450 | - if |
1451 | - (upcast |
1452 | - (MilitarySite_Descr const, target_ms_d, &target_descr)) |
1453 | - { |
1454 | - const int32_t v = |
1455 | - target_ms_d->get_conquers() |
1456 | - - |
1457 | - map.calc_distance(field.coords, immovables.at(i).coords); |
1458 | - |
1459 | - if (0 < v) { |
1460 | - field.military_influence += v * (v + 2) * 6; |
1461 | - field.avoid_military = true; |
1462 | - } |
1463 | + ++field.trees_nearby_; |
1464 | + } |
1465 | + |
1466 | + // stones are not renewable, we will count them only if previous state si nonzero |
1467 | + if (field.stones_nearby_ > 0) { |
1468 | + |
1469 | + int32_t const stone_attr = Map_Object_Descr::get_attribute_id("stone"); |
1470 | + field.stones_nearby_ = 0; |
1471 | + |
1472 | + for (uint32_t j = 0; j < immovables.size(); ++j) { |
1473 | + // const BaseImmovable & base_immovable = *immovables.at(i).object; |
1474 | + if (immovables.at(j).object->has_attribute(stone_attr)) |
1475 | + ++field.stones_nearby_; |
1476 | + } |
1477 | + } |
1478 | + |
1479 | + //// ground water is not renewable and its amount can only fall, we will count them only if |
1480 | + /// previous state si nonzero |
1481 | + if (field.ground_water_ > 0) { |
1482 | + field.ground_water_ = |
1483 | + field.coords.field->get_resources_amount(); // field->get_resources(); |
1484 | + |
1485 | + // printf(" RESOURCE DEBUG: %2d",field.get_resources()); |
1486 | + } |
1487 | + } |
1488 | + |
1489 | + // folowing is done allways (regardless of military or not) |
1490 | + |
1491 | + if (kMilitScoreDebug) |
1492 | + printf(" FIELD SCORE: central building: %3dx%3d\n", field.coords.x, field.coords.y); |
1493 | + |
1494 | + field.military_stationed_ = 0; |
1495 | + |
1496 | + for (uint32_t i = 0; i < immovables.size(); ++i) { |
1497 | + const BaseImmovable& base_immovable = *immovables.at(i).object; |
1498 | + |
1499 | + // testing if it is enemy-owned field |
1500 | + // TODO count such fields... |
1501 | + if (upcast(PlayerImmovable const, player_immovable, &base_immovable)) |
1502 | + |
1503 | + // TODO Only continue; if this is an opposing site |
1504 | + // TODO allied sites should be counted for military influence |
1505 | + if (player_immovable->owner().player_number() != pn) { |
1506 | + if (player->is_hostile(player_immovable->owner())) |
1507 | + field.enemy_nearby_ = true; |
1508 | + |
1509 | + continue; |
1510 | + } |
1511 | + |
1512 | + if (upcast(Building const, building, &base_immovable)) { |
1513 | + if (upcast(ConstructionSite const, constructionsite, building)) { |
1514 | + const Building_Descr& target_descr = constructionsite->building(); |
1515 | + |
1516 | + if (upcast(MilitarySite_Descr const, target_ms_d, &target_descr)) { |
1517 | + const int32_t dist = map.calc_distance(field.coords, immovables.at(i).coords); |
1518 | + const int32_t radius = target_ms_d->get_conquers() + 4; |
1519 | + const int32_t v = radius - dist; |
1520 | + |
1521 | + if (v > 0) { |
1522 | + if (kMilitScoreDebug) |
1523 | + printf(" FIELD SCORE: testing near military construction site at %3dx%3d, " |
1524 | + "presumed capacity: %d, loneliness:%4f (%2d:%2d)\n", |
1525 | + immovables.at(i).coords.x, |
1526 | + immovables.at(i).coords.y, |
1527 | + 2, |
1528 | + static_cast<double>(dist) / radius, |
1529 | + dist, |
1530 | + radius); |
1531 | + |
1532 | + field.military_capacity_ += 2; |
1533 | + field.military_loneliness_ *= static_cast<double_t>(dist) / radius; |
1534 | + field.military_in_constr_nearby_ += 1; |
1535 | } |
1536 | } |
1537 | - if (upcast(MilitarySite const, militarysite, building)) { |
1538 | - const int32_t v = |
1539 | - militarysite->get_conquers() |
1540 | - - |
1541 | - map.calc_distance(field.coords, immovables.at(i).coords); |
1542 | - |
1543 | - if (v > 0) |
1544 | - field.military_influence += |
1545 | - v * v * militarysite->soldierCapacity(); |
1546 | + } |
1547 | + |
1548 | + if (upcast(MilitarySite const, militarysite, building)) { |
1549 | + const int32_t dist = map.calc_distance(field.coords, immovables.at(i).coords); |
1550 | + const int32_t radius = militarysite->get_conquers() + 4; |
1551 | + const int32_t v = radius - dist; |
1552 | + |
1553 | + if (v > 0 and dist > 0) { |
1554 | + if (kMilitScoreDebug) |
1555 | + printf(" FIELD SCORE: testing near military building at %3dx%3d, capacity: %d, " |
1556 | + "loneliness:%3f (%2d:%2d), stationed: %1d\n", |
1557 | + immovables.at(i).coords.x, |
1558 | + immovables.at(i).coords.y, |
1559 | + militarysite->maxSoldierCapacity(), |
1560 | + static_cast<double>(dist) / radius, |
1561 | + dist, |
1562 | + radius, |
1563 | + militarysite->stationedSoldiers().size()); |
1564 | + |
1565 | + field.military_capacity_ += militarysite->maxSoldierCapacity(); |
1566 | + field.military_presence_ += militarysite->stationedSoldiers().size(); |
1567 | + |
1568 | + if (militarysite->stationedSoldiers().size() > 0) |
1569 | + field.military_stationed_ += 1; |
1570 | + |
1571 | + field.military_loneliness_ *= static_cast<double_t>(dist) / radius; |
1572 | } |
1573 | } |
1574 | } |
1575 | } |
1576 | + |
1577 | + if (kMilitScoreDebug) |
1578 | + printf( |
1579 | + " FIELD SCORE: results: capacity: %d, presence: %d, loneliness: %4d, stationed: %1d\n", |
1580 | + field.military_capacity_, |
1581 | + field.military_presence_, |
1582 | + field.military_loneliness_, |
1583 | + field.military_stationed_); |
1584 | + |
1585 | + //} |
1586 | } |
1587 | |
1588 | /// Updates one mineable field |
1589 | -void DefaultAI::update_mineable_field (MineableField & field) |
1590 | -{ |
1591 | +void DefaultAI::update_mineable_field(MineableField& field) { |
1592 | // collect information about resources in the area |
1593 | std::vector<ImmovableFound> immovables; |
1594 | - Map & map = game().map(); |
1595 | - |
1596 | - map.find_immovables (Area<FCoords>(field.coords, 6), &immovables); |
1597 | - |
1598 | - field.reachable = false; |
1599 | - field.preferred = false; |
1600 | - field.mines_nearby = 1; |
1601 | - |
1602 | + Map& map = game().map(); |
1603 | + map.find_immovables(Area<FCoords>(field.coords, 5), &immovables); |
1604 | + field.reachable = false; |
1605 | + field.preferred_ = false; |
1606 | + field.mines_nearby_ = 1; |
1607 | FCoords fse; |
1608 | map.get_brn(field.coords, &fse); |
1609 | |
1610 | - if (BaseImmovable const * const imm = fse.field->get_immovable()) |
1611 | - if |
1612 | - (dynamic_cast<Flag const *>(imm) |
1613 | - or |
1614 | - (dynamic_cast<Road const *>(imm) |
1615 | - && |
1616 | - (fse.field->nodecaps() & BUILDCAPS_FLAG))) |
1617 | - field.preferred = true; |
1618 | + if (BaseImmovable const* const imm = fse.field->get_immovable()) |
1619 | + if (dynamic_cast<Flag const*>(imm) |
1620 | + or(dynamic_cast<Road const*>(imm) && (fse.field->nodecaps() & BUILDCAPS_FLAG))) |
1621 | + field.preferred_ = true; |
1622 | |
1623 | container_iterate_const(std::vector<ImmovableFound>, immovables, i) { |
1624 | - if (dynamic_cast<Flag const *>(i.current->object)) |
1625 | + if (dynamic_cast<Flag const*>(i.current->object)) |
1626 | field.reachable = true; |
1627 | else if (upcast(Building const, bld, i.current->object)) { |
1628 | if (bld->descr().get_ismine()) { |
1629 | - ++field.mines_nearby; |
1630 | + ++field.mines_nearby_; |
1631 | } else if (upcast(ConstructionSite const, cs, bld)) { |
1632 | if (cs->building().get_ismine()) |
1633 | - ++field.mines_nearby; |
1634 | + ++field.mines_nearby_; |
1635 | } |
1636 | } |
1637 | } |
1638 | } |
1639 | |
1640 | - |
1641 | -/// Updates the productionsites statistics needed for construction decision. |
1642 | +/// Updates the production and MINE sites statistics needed for construction decision. |
1643 | void DefaultAI::update_productionsite_stats(int32_t const gametime) { |
1644 | - // Updating the stats every 20 seconds should be enough |
1645 | - next_stats_update_due = gametime + 20000; |
1646 | + // Updating the stats every 10 seconds should be enough |
1647 | + next_stats_update_due_ = gametime + 10000; |
1648 | |
1649 | // Reset statistics for all buildings |
1650 | for (uint32_t i = 0; i < buildings.size(); ++i) { |
1651 | - if (buildings.at(i).cnt_built > 0) |
1652 | - buildings.at(i).current_stats = 0; |
1653 | - // If there are no buildings of that type set the current_stats to 100 |
1654 | + if (buildings.at(i).cnt_built_ > 0) |
1655 | + buildings.at(i).current_stats_ = 0; |
1656 | + // If there are no buildings of that type set the current_stats_ to 100 |
1657 | else |
1658 | - buildings.at(i).current_stats = 100; |
1659 | - buildings.at(i).unoccupied = false; |
1660 | + buildings.at(i).current_stats_ = 0; // there was 100, this confuses algorithm |
1661 | + |
1662 | + buildings.at(i).unoccupied_ = false; |
1663 | } |
1664 | |
1665 | // Check all available productionsites |
1666 | for (uint32_t i = 0; i < productionsites.size(); ++i) { |
1667 | - assert(productionsites.front().bo->cnt_built > 0); |
1668 | - |
1669 | + assert(productionsites.front().bo->cnt_built_ > 0); |
1670 | // Add statistics value |
1671 | - productionsites.front().bo->current_stats += |
1672 | - productionsites.front().site->get_statistics_percent(); |
1673 | - |
1674 | + productionsites.front().bo->current_stats_ += |
1675 | + productionsites.front().site->get_crude_statistics(); |
1676 | + if (kStatDebug and abs(productionsites.front().site->get_crude_statistics() - |
1677 | + productionsites.front().site->get_statistics_percent()) > 50) |
1678 | + printf(" STAT DEBUG: %15s (%3dx%3d): crude statistic: %3d vs official statistics: %3d\n", |
1679 | + productionsites.front().site->name().c_str(), |
1680 | + productionsites.front().site->get_position().x, |
1681 | + productionsites.front().site->get_position().y, |
1682 | + productionsites.front().site->get_crude_statistics(), |
1683 | + productionsites.front().site->get_statistics_percent()); |
1684 | // Check whether this building is completely occupied |
1685 | - productionsites.front().bo->unoccupied |= |
1686 | - !productionsites.front().site->can_start_working(); |
1687 | - |
1688 | + productionsites.front().bo->unoccupied_ |= !productionsites.front().site->can_start_working(); |
1689 | // Now reorder the buildings |
1690 | productionsites.push_back(productionsites.front()); |
1691 | productionsites.pop_front(); |
1692 | } |
1693 | |
1694 | + // for mines_ also |
1695 | + // Check all available productionsites |
1696 | + for (uint32_t i = 0; i < mines_.size(); ++i) { |
1697 | + assert(mines_.front().bo->cnt_built_ > 0); |
1698 | + // Add statistics value |
1699 | + mines_.front().bo->current_stats_ += mines_.front().site->get_statistics_percent(); |
1700 | + // Check whether this building is completely occupied |
1701 | + mines_.front().bo->unoccupied_ |= !mines_.front().site->can_start_working(); |
1702 | + // Now reorder the buildings |
1703 | + mines_.push_back(mines_.front()); |
1704 | + mines_.pop_front(); |
1705 | + } |
1706 | + |
1707 | // Scale statistics down |
1708 | for (uint32_t i = 0; i < buildings.size(); ++i) { |
1709 | - if (buildings.at(i).cnt_built > 0) |
1710 | - buildings.at(i).current_stats /= buildings.at(i).cnt_built; |
1711 | + if (buildings.at(i).cnt_built_ > 0) |
1712 | + buildings.at(i).current_stats_ /= buildings.at(i).cnt_built_; |
1713 | } |
1714 | } |
1715 | |
1716 | - |
1717 | -/** |
1718 | - * constructs the most needed building |
1719 | - * |
1720 | - * The need for a productionsite or a mine is calculated by the need for |
1721 | - * their produced wares. The need for logproducers (like lumberjack's huts), |
1722 | - * stoneproducers (like quarries) and resource refreshing buildings (like |
1723 | - * forester's houses, gamekeeper's huts or fishbreeder houses) are calculated |
1724 | - * separately as these buildings should have another priority (on one hand they |
1725 | - * are important for the basic infrastructure, but there is no need for a lot |
1726 | - * of these buildings. |
1727 | - * Militarysites, warehouses and trainingsites have a different calculation, |
1728 | - * that (should) depend on the initialisation type (Aggressive, Normal, |
1729 | - * Defensive) |
1730 | - */ |
1731 | -bool DefaultAI::construct_building (int32_t) // (int32_t gametime) |
1732 | -{ |
1733 | - // TODO make this smarter, easier and yet more effective |
1734 | - |
1735 | - // TODO implement handling of seafaring |
1736 | - |
1737 | - // Do not have too many constructionsites |
1738 | - uint32_t producers = mines.size() + productionsites.size(); |
1739 | - bool onlymissing = false; |
1740 | - if (total_constructionsites >= (2 + (producers / 10))) |
1741 | - onlymissing = true; |
1742 | - |
1743 | +// * Constructs the most needed building |
1744 | +// algorithm goes over all available spots and all allowed buildings, |
1745 | +// scores every combination and one with highest and positive score |
1746 | +// is built. |
1747 | +// * Buildings are split into categories |
1748 | +// * The logic is complex but aproximatelly: |
1749 | +// - buildings producing building material are preffered |
1750 | +// - buildings identified as basic are preffered |
1751 | +// - first bulding of a type is preffered |
1752 | +// - if a bulding is upgradeable, second building is also preffered |
1753 | +// (there should be no upgrade when there are not two buildings of the same type) |
1754 | +// - algorigthm is trying to take into account actual utlization of buildings |
1755 | +// (the one shown in GUI/game is not reliable, it calculates own statistics) |
1756 | +// * military buildings have own strategy, split into two situations: |
1757 | +// - there is no enemy |
1758 | +// - there is an enemy |
1759 | +// Currently more military buildings are built then needed |
1760 | +// and "optimalization" (dismantling not needed buildings) is done afterwards |
1761 | +bool DefaultAI::construct_building(int32_t gametime) { // (int32_t gametime) |
1762 | // Just used for easy checking whether a mine or something else was built. |
1763 | bool mine = false; |
1764 | - |
1765 | + bool field_blocked = false; |
1766 | + int32_t spots = 0; |
1767 | + uint32_t consumers_nearby_count = 0; |
1768 | + // this is to increase score so also building near borders can be built |
1769 | + int32_t bulgarian_constant = 12; |
1770 | std::vector<int32_t> spots_avail; |
1771 | spots_avail.resize(4); |
1772 | |
1773 | for (int32_t i = 0; i < 4; ++i) |
1774 | spots_avail.at(i) = 0; |
1775 | |
1776 | - for |
1777 | - (std::list<BuildableField *>::iterator i = buildable_fields.begin(); |
1778 | - i != buildable_fields.end(); |
1779 | - ++i) |
1780 | + for (std::list<BuildableField*>::iterator i = buildable_fields.begin(); |
1781 | + i != buildable_fields.end(); |
1782 | + ++i) |
1783 | ++spots_avail.at((*i)->coords.field->nodecaps() & BUILDCAPS_SIZEMASK); |
1784 | |
1785 | + // calculating expand factor |
1786 | int32_t expand_factor = 0; |
1787 | |
1788 | if (type != DEFENSIVE) { |
1789 | ++expand_factor; |
1790 | + |
1791 | // check space and set the need for expansion |
1792 | - if |
1793 | - (spots_avail.at(BUILDCAPS_BIG) |
1794 | - < |
1795 | - static_cast<uint16_t>(2 + (productionsites.size() / 50))) |
1796 | + if (spots_avail.at(BUILDCAPS_BIG) < static_cast<uint16_t>(2 + (productionsites.size() / 50))) |
1797 | expand_factor += 2; |
1798 | - if |
1799 | - (spots_avail.at(BUILDCAPS_MEDIUM) + spots_avail.at(BUILDCAPS_BIG) |
1800 | - < |
1801 | - static_cast<uint16_t>(4 + (productionsites.size() / 50))) |
1802 | + |
1803 | + if (spots_avail.at(BUILDCAPS_MEDIUM) + spots_avail.at(BUILDCAPS_BIG) < |
1804 | + static_cast<uint16_t>(4 + (productionsites.size() / 50))) |
1805 | expand_factor += type; |
1806 | |
1807 | - uint32_t spots = spots_avail.at(BUILDCAPS_SMALL); |
1808 | + spots = spots_avail.at(BUILDCAPS_SMALL); |
1809 | spots += spots_avail.at(BUILDCAPS_MEDIUM); |
1810 | spots += spots_avail.at(BUILDCAPS_BIG); |
1811 | + |
1812 | if (type == AGGRESSIVE) |
1813 | spots -= militarysites.size() / 20; |
1814 | + |
1815 | if (spots < 16) |
1816 | expand_factor *= 2; |
1817 | + |
1818 | if ((type == AGGRESSIVE) && spots < 32) |
1819 | expand_factor *= 2; |
1820 | } else { |
1821 | // check space and set the need for expansion |
1822 | if (spots_avail.at(BUILDCAPS_BIG) < 7) |
1823 | ++expand_factor; |
1824 | + |
1825 | if (spots_avail.at(BUILDCAPS_MEDIUM) + spots_avail.at(BUILDCAPS_BIG) < 12) |
1826 | ++expand_factor; |
1827 | - if |
1828 | - (spots_avail.at(BUILDCAPS_SMALL) + |
1829 | - spots_avail.at(BUILDCAPS_MEDIUM) + |
1830 | - spots_avail.at(BUILDCAPS_BIG) |
1831 | - < |
1832 | - 16) |
1833 | + |
1834 | + if (spots_avail.at(BUILDCAPS_SMALL) + spots_avail.at(BUILDCAPS_MEDIUM) + |
1835 | + spots_avail.at(BUILDCAPS_BIG) < |
1836 | + 16) |
1837 | expand_factor *= 3; |
1838 | } |
1839 | |
1840 | - // don't expand when we have unoccupied military buildings |
1841 | - //if (TODO) expand_factor = 0; |
1842 | + // checking amount of free spots, if needed setting new building stop flag |
1843 | + new_buildings_stop_ = false; |
1844 | + |
1845 | + if (militarysites.size() * 2 + 20 < productionsites.size() or spots < |
1846 | + (7 + static_cast<int32_t>(productionsites.size()) / 5)) { |
1847 | + new_buildings_stop_ = true; |
1848 | + } |
1849 | + |
1850 | + if (kNewBuildingDebug) |
1851 | + printf(" TDEBUG new buildings stop: %s; milit: %3d vs prod: %3d buildings, spots: %4d\n", |
1852 | + new_buildings_stop_ ? "Y" : "N", |
1853 | + militarysites.size(), |
1854 | + productionsites.size(), |
1855 | + spots); |
1856 | + |
1857 | + // sometimes there is to many military buildings in construction, so we must |
1858 | + // prevent initialization of further buildings start |
1859 | + bool new_military_buildings_stop = false; |
1860 | + // in areas close to enemies, above limit is not effective, so we have second one |
1861 | + // more benevolent limit |
1862 | + bool near_enemy_b_buildings_stop = false; |
1863 | + // in some situation expansion just halts because there are not good spots to expand |
1864 | + // so this is a boost to increase a score and allow building a military building on a spot |
1865 | + // that is normally not suitable for building |
1866 | + int32_t military_boost = 1; |
1867 | + |
1868 | + int32_t treshold = (militarysites.size() + productionsites.size()) / 100 + 1; |
1869 | + |
1870 | + if (unstationed_milit_buildings_ + military_under_constr_ / 3 > treshold) { |
1871 | + new_military_buildings_stop = true; |
1872 | + |
1873 | + if (kMilitaryDebug) |
1874 | + printf(" TDEBUG new military buildings stop ON, %d %d \n", |
1875 | + unstationed_milit_buildings_, |
1876 | + military_under_constr_); |
1877 | + } else if (kMilitaryDebug) |
1878 | + printf(" TDEBUG new military buildings stop OFF, %d %d\n", |
1879 | + unstationed_milit_buildings_, |
1880 | + military_under_constr_); |
1881 | + |
1882 | + if (unstationed_milit_buildings_ + military_under_constr_ / 3 > 2 * treshold) { |
1883 | + near_enemy_b_buildings_stop = true; |
1884 | + |
1885 | + if (kMilitaryDebug) |
1886 | + printf(" TDEBUG new military near-enemy buildings stop ON, %d %d \n", |
1887 | + unstationed_milit_buildings_, |
1888 | + military_under_constr_); |
1889 | + } |
1890 | + |
1891 | + // here we deal with situation when for some time no new military building was built |
1892 | + // in fact this is a last time when there were any military buildings in construction |
1893 | + if ((unstationed_milit_buildings_ + military_under_constr_) > 0) |
1894 | + military_last_build_ = game().get_gametime(); |
1895 | + |
1896 | + if (military_last_build_ + 1 * 60 * 1000 < game().get_gametime()) { |
1897 | + if (kMilitaryDebug) |
1898 | + printf(" TDEBUG: Boosting military building\n"); |
1899 | + |
1900 | + military_boost = 200; |
1901 | + } |
1902 | |
1903 | // Defensive AIs also attack sometimes (when they want to expand) |
1904 | if (type == DEFENSIVE && expand_factor > 1) |
1905 | - if (next_attack_consideration_due <= game().get_gametime()) |
1906 | + if (next_attack_consideration_due_ <= game().get_gametime()) |
1907 | consider_attack(game().get_gametime()); |
1908 | |
1909 | - |
1910 | - Building_Index proposed_building = INVALID_INDEX; |
1911 | + // Building_Index proposed_building = INVALID_INDEX; // I need BuildingObserver not index |
1912 | + BuildingObserver* best_building = nullptr; |
1913 | int32_t proposed_priority = 0; |
1914 | Coords proposed_coords; |
1915 | |
1916 | // Remove outdated fields from blocker list |
1917 | - for |
1918 | - (std::list<BlockedField>::iterator i = blocked_fields.begin(); |
1919 | - i != blocked_fields.end();) |
1920 | - if (i->blocked_until < game().get_gametime()) { |
1921 | + for (std::list<BlockedField>::iterator i = blocked_fields.begin(); i != blocked_fields.end();) |
1922 | + if (i->blocked_until_ < game().get_gametime()) { |
1923 | i = blocked_fields.erase(i); |
1924 | - } |
1925 | - else ++i; |
1926 | + } else |
1927 | + ++i; |
1928 | + |
1929 | + // these are 3 helping variables |
1930 | + bool output_is_needed = false; |
1931 | + int16_t max_preciousness = 0; // preciousness_ of most precious output |
1932 | + int16_t max_needed_preciousness = 0; // preciousness_ of most precious NEEDED output |
1933 | |
1934 | // first scan all buildable fields for regular buildings |
1935 | - for |
1936 | - (std::list<BuildableField *>::iterator i = buildable_fields.begin(); |
1937 | - i != buildable_fields.end(); |
1938 | - ++i) |
1939 | - { |
1940 | - BuildableField * const bf = *i; |
1941 | + for (std::list<BuildableField*>::iterator i = buildable_fields.begin(); |
1942 | + i != buildable_fields.end(); |
1943 | + ++i) { |
1944 | + BuildableField* const bf = *i; |
1945 | |
1946 | if (!bf->reachable) |
1947 | continue; |
1948 | |
1949 | + if (time(nullptr) % 5 == 0) |
1950 | + continue; // add randomnes and ease AI |
1951 | + |
1952 | // Continue if field is blocked at the moment |
1953 | - for |
1954 | - (std::list<BlockedField>::iterator j = blocked_fields.begin(); |
1955 | - j != blocked_fields.end(); |
1956 | - ++j) |
1957 | + field_blocked = false; |
1958 | + |
1959 | + for (std::list<BlockedField>::iterator j = blocked_fields.begin(); j != blocked_fields.end(); |
1960 | + ++j) |
1961 | if (j->coords == bf->coords) |
1962 | - continue; |
1963 | + field_blocked = true; |
1964 | + |
1965 | + // continue; |
1966 | + if (field_blocked) |
1967 | + continue; |
1968 | |
1969 | assert(player); |
1970 | - int32_t const maxsize = |
1971 | - player->get_buildcaps(bf->coords) & BUILDCAPS_SIZEMASK; |
1972 | + int32_t const maxsize = player->get_buildcaps(bf->coords) & BUILDCAPS_SIZEMASK; |
1973 | |
1974 | - // Check all buildable buildings |
1975 | + // For every field test all buildings |
1976 | for (uint32_t j = 0; j < buildings.size(); ++j) { |
1977 | - BuildingObserver & bo = buildings.at(j); |
1978 | + BuildingObserver& bo = buildings.at(j); |
1979 | |
1980 | if (!bo.buildable(*player)) |
1981 | continue; |
1982 | |
1983 | + if (time(nullptr) % 3 == 0) |
1984 | + continue; // add randomnes and ease AI |
1985 | + |
1986 | if (bo.type == BuildingObserver::MINE) |
1987 | continue; |
1988 | |
1989 | - // If there are already a lot of constructionsites, only missing |
1990 | - // productionsites that produce build material are allowed |
1991 | - // (perhaps they are needed to finish the other constructionsites?) |
1992 | - if (onlymissing) { |
1993 | - if (!(bo.type == BuildingObserver::PRODUCTIONSITE)) |
1994 | - continue; |
1995 | - if ((bo.total_count() > 0) || !bo.prod_build_material) |
1996 | - continue; |
1997 | + if (gametime - bo.construction_decision_time_ < kBuildingMinInterval) |
1998 | + continue; |
1999 | + |
2000 | + if (bo.unoccupied_) |
2001 | + continue; |
2002 | + |
2003 | + if (not bo.type == BuildingObserver::MILITARYSITE and bo.cnt_under_construction_ >= 2) |
2004 | + continue; |
2005 | + |
2006 | + // so we are going to seriously evaluate this building on this field, |
2007 | + // first some base info |
2008 | + // if at least on of outputs is needed |
2009 | + output_is_needed = false; |
2010 | + // max presiousness of outputs |
2011 | + max_preciousness = 0; |
2012 | + // max preciousness of most needed output |
2013 | + max_needed_preciousness = 0; |
2014 | + |
2015 | + // Check if the produced wares are needed (if it is producing anything) |
2016 | + if (bo.outputs_.size() > 0) { |
2017 | + container_iterate(std::list<EconomyObserver*>, economies, l) { |
2018 | + // Don't check if the economy has no warehouse. |
2019 | + if ((*l.current)->economy.warehouses().empty()) |
2020 | + continue; |
2021 | + |
2022 | + for (uint32_t m = 0; m < bo.outputs_.size(); ++m) { |
2023 | + Ware_Index wt(static_cast<size_t>(bo.outputs_.at(m))); |
2024 | + |
2025 | + if ((*l.current)->economy.needs_ware(wt)) { |
2026 | + output_is_needed = true; |
2027 | + |
2028 | + if (wares.at(bo.outputs_.at(m)).preciousness_ > max_needed_preciousness) |
2029 | + max_needed_preciousness = wares.at(bo.outputs_.at(m)).preciousness_; |
2030 | + |
2031 | + max_preciousness = wares.at(bo.outputs_.at(m)).preciousness_; |
2032 | + } else { |
2033 | + if (wares.at(bo.outputs_.at(m)).preciousness_ > max_preciousness) |
2034 | + max_preciousness = wares.at(bo.outputs_.at(m)).preciousness_; |
2035 | + } |
2036 | + } |
2037 | + } |
2038 | } |
2039 | |
2040 | + // if current field is not big enough |
2041 | if (bo.desc->get_size() > maxsize) |
2042 | continue; |
2043 | |
2044 | - int32_t prio = 0; |
2045 | + int32_t prio = 0; // score of a bulding on a field |
2046 | |
2047 | if (bo.type == BuildingObserver::PRODUCTIONSITE) { |
2048 | - // Don't build another building of this type, if there is already |
2049 | - // one that is unoccupied at the moment |
2050 | - if (bo.unoccupied) |
2051 | - continue; |
2052 | - if (bo.need_trees) { |
2053 | - // Priority of woodcutters depend on the number of near trees |
2054 | - prio += bf->trees_nearby * 3; |
2055 | - prio /= 3 * (1 + bf->producers_nearby.at(bo.outputs.at(0))); |
2056 | - |
2057 | - // TODO improve this - it's still useless to place lumberjack huts randomly |
2058 | - /*if (prio <= 0) // no, sometimes we need wood without having a forest |
2059 | - continue;*/ |
2060 | - |
2061 | - // Check if the produced wares are needed |
2062 | - Ware_Index wt(static_cast<size_t>(bo.outputs.at(0))); |
2063 | - container_iterate(std::list<EconomyObserver *>, economies, l) { |
2064 | - // Don't check if the economy has no warehouse. |
2065 | - if ((*l.current)->economy.warehouses().empty()) |
2066 | - continue; |
2067 | - if ((*l.current)->economy.needs_ware(wt)) |
2068 | - prio += 1 + wares.at(bo.outputs.at(0)).preciousness; |
2069 | - } |
2070 | - |
2071 | - if (bo.total_count() < 2) { |
2072 | - prio *= 6; // big bonus for the basics |
2073 | - if (bo.total_count() == 0) |
2074 | - prio *= 4; // even more for the absolute basics |
2075 | - } |
2076 | - } else if (bo.need_stones) { |
2077 | - // Priority of quarries depend on the number of near stones |
2078 | - prio += bf->stones_nearby * 3; |
2079 | - prio /= 3 * (1 + bf->producers_nearby.at(bo.outputs.at(0))); |
2080 | - if (bo.total_count() < 2) { |
2081 | - prio *= 6; // big bonus for the basics |
2082 | - if (bo.total_count() == 0) |
2083 | - prio *= 4; // even more for the absolute basics |
2084 | - } |
2085 | - } else if (bo.production_hint >= 0) { |
2086 | + |
2087 | + // this can be only a well (as by now) |
2088 | + if (bo.mines_water_) { |
2089 | + if (bf->ground_water_ < 2) |
2090 | + continue; |
2091 | + |
2092 | + if (bo.cnt_under_construction_ + bo.unoccupied_ > 0) |
2093 | + continue; |
2094 | + if ((bo.cnt_built_ + bo.unoccupied_) > 0 and gametime < kBaseInfrastructureTime) |
2095 | + continue; |
2096 | + if (new_buildings_stop_) |
2097 | + continue; |
2098 | + bo.cnt_target_ = |
2099 | + 2 + static_cast<int32_t>(mines_.size() + productionsites.size()) / 20; |
2100 | + if ((bo.cnt_built_ + bo.cnt_under_construction_ + bo.unoccupied_) > bo.cnt_target_) |
2101 | + continue; |
2102 | + |
2103 | + if (bo.stocklevel_time < game().get_gametime() - 30 * 1000) { |
2104 | + bo.stocklevel_ = get_stocklevel(bo); |
2105 | + bo.stocklevel_time = game().get_gametime(); |
2106 | + } |
2107 | + if (bo.stocklevel_ > 50) |
2108 | + continue; |
2109 | + if (kWellDebug) |
2110 | + printf(" kWellDebug: %-15s has %2d resources, stocklevel: %3d\n", |
2111 | + bo.name, |
2112 | + bf->ground_water_, |
2113 | + bo.stocklevel_); |
2114 | + prio = bf->ground_water_ - 2; |
2115 | + prio = recalc_with_border_range(*bf, prio); |
2116 | + |
2117 | + } else if (bo.need_trees_) { // LUMBERJACS |
2118 | + |
2119 | + if (kWoodDebug) |
2120 | + printf(" TDEBUG: %1d: buildings count:%2d-%2d-%2d, trees nearby: %3d, " |
2121 | + "build.stop: %s\n", |
2122 | + player_number(), |
2123 | + bo.cnt_built_, |
2124 | + bo.cnt_under_construction_, |
2125 | + bo.unoccupied_, |
2126 | + bf->trees_nearby_ * 2, |
2127 | + (new_buildings_stop_) ? "Y" : "N"); |
2128 | + |
2129 | + if (bo.cnt_built_ + bo.cnt_under_construction_ + bo.unoccupied_ <= 2) |
2130 | + prio = bulgarian_constant + 200 + bf->trees_nearby_; |
2131 | + else if (bo.cnt_under_construction_ + bo.unoccupied_ <= 1) { |
2132 | + prio = |
2133 | + bf->trees_nearby_ - 5 - |
2134 | + new_buildings_stop_ * 40; //+ bf->producers_nearby_.at(bo.outputs_.at(0))*5; |
2135 | + } |
2136 | + |
2137 | + if (kWoodDebug and prio > 0) |
2138 | + printf(" TDEBUG: %1d: suggesting woodcutter with prio: %2d, total: %2d\n", |
2139 | + player_number(), |
2140 | + prio, |
2141 | + bo.cnt_built_ + bo.cnt_under_construction_ + bo.unoccupied_); |
2142 | + } else if (bo.need_stones_) { |
2143 | + |
2144 | + // quaries are generally to be built everywhere where stones are |
2145 | + // no matter the need for stones, as stones are considered an obstacle |
2146 | + // to expansion |
2147 | + if (bo.cnt_under_construction_ > 0) |
2148 | + continue; |
2149 | + prio = bf->stones_nearby_; |
2150 | + |
2151 | + if (bo.stocklevel_time < game().get_gametime() - 5 * 1000) { |
2152 | + bo.stocklevel_ = get_stocklevel_by_hint(static_cast<size_t>(bo.production_hint_)); |
2153 | + bo.stocklevel_time = game().get_gametime(); |
2154 | + } |
2155 | + |
2156 | + if (bo.stocklevel_ < 20) |
2157 | + prio = prio * 2; |
2158 | + |
2159 | + if (bo.total_count() == 0) |
2160 | + prio = prio * 2; |
2161 | + |
2162 | + // to prevent to many quaries on one spot |
2163 | + prio = prio - 30 * bf->producers_nearby_.at(bo.outputs_.at(0)); |
2164 | + |
2165 | + } else if (bo.production_hint_ >= 0) { |
2166 | + // first setting targets (needed also for dismantling) |
2167 | + if (bo.plants_trees_) |
2168 | + bo.cnt_target_ = |
2169 | + 2 + static_cast<int32_t>(mines_.size() + productionsites.size()) / 15; |
2170 | + else |
2171 | + bo.cnt_target_ = |
2172 | + 1 + static_cast<int32_t>(mines_.size() + productionsites.size()) / 20; |
2173 | + |
2174 | + if ((bo.cnt_under_construction_ + bo.unoccupied_) > 0) |
2175 | + continue; |
2176 | + |
2177 | // production hint (f.e. associate forester with logs) |
2178 | |
2179 | - // Calculate the need for this building |
2180 | - int16_t inout = wares.at(bo.production_hint).consumers; |
2181 | - if |
2182 | - (tribe->safe_ware_index("log") |
2183 | - == |
2184 | - bo.production_hint) |
2185 | - inout += total_constructionsites / 4; |
2186 | - inout -= wares.at(bo.production_hint).producers; |
2187 | - if (inout < 1) |
2188 | - inout = 1; |
2189 | - // the ware they're refreshing |
2190 | - Ware_Index wt(static_cast<size_t>(bo.production_hint)); |
2191 | - container_iterate(std::list<EconomyObserver *>, economies, l) { |
2192 | - // Don't check if the economy has no warehouse. |
2193 | - if ((*l.current)->economy.warehouses().empty()) |
2194 | - continue; |
2195 | - if ((*l.current)->economy.needs_ware(wt)) { |
2196 | - prio += wares.at(bo.production_hint).preciousness * inout * 2; |
2197 | - break; |
2198 | - } |
2199 | - } |
2200 | - |
2201 | - // Do not build too many of these buildings, but still care |
2202 | - // to build at least two. |
2203 | - // And add bonus near buildings outputting production_hint ware. |
2204 | - prio += (5 * bf->producers_nearby.at(bo.production_hint)) / 2; |
2205 | - prio -= bo.total_count() * 2; |
2206 | - prio /= bo.total_count() + 1; |
2207 | - prio += (bf->producers_nearby.at(bo.production_hint) - 1) * 5; |
2208 | - if (bo.total_count() > 2) |
2209 | - prio -= bo.total_count(); |
2210 | - else { |
2211 | - prio += wares.at(bo.production_hint).preciousness; |
2212 | - prio *= 3; |
2213 | - } |
2214 | - if (prio < 0) |
2215 | - continue; |
2216 | - } else if (bo.recruitment) { |
2217 | - // "recruitment centeres" like the donkey farm should be build up |
2218 | - // as soon as a basic infrastructure was completed. |
2219 | - // and of course the defaultAI should think of further |
2220 | - // constructions of that type later in game. |
2221 | - prio -= 12; // start calculation with an offset |
2222 | - prio += productionsites.size() + mines.size(); |
2223 | - prio -= (bo.total_count()) * 40; |
2224 | - prio *= 2; |
2225 | - |
2226 | - // take care about borders and enemies |
2227 | - prio = recalc_with_border_range(*bf, prio); |
2228 | - } else { // "normal" productionsites |
2229 | - |
2230 | - // ToDo: prefer soldier producing things |
2231 | - // Ware_Index const soldier_index = tribe().worker_index("soldier"); |
2232 | - |
2233 | - if (bo.is_basic && (bo.total_count() == 0)) |
2234 | - prio += 100; // for very important buildings |
2235 | - |
2236 | - // Check if the produced wares are needed |
2237 | - container_iterate(std::list<EconomyObserver *>, economies, l) { |
2238 | - // Don't check if the economy has no warehouse. |
2239 | - if ((*l.current)->economy.warehouses().empty()) |
2240 | - continue; |
2241 | - for (uint32_t m = 0; m < bo.outputs.size(); ++m) { |
2242 | - Ware_Index wt(static_cast<size_t>(bo.outputs.at(m))); |
2243 | - |
2244 | - // if we have too much of it (avoids mass storage) |
2245 | - if |
2246 | - ((*l.current)->economy.stock_ware(wt) > 6 * |
2247 | - (*l.current)->economy.ware_target_quantity(wt).permanent) |
2248 | - prio -= 20; |
2249 | - |
2250 | - // if the economy needs this ware |
2251 | - if ((*l.current)->economy.needs_ware(wt)) { |
2252 | - prio += 1 + wares.at(bo.outputs.at(m)).preciousness; |
2253 | - if (bo.total_count() == 0) |
2254 | - // big bonus, this site might be elemental |
2255 | - prio += 3 * wares.at(bo.outputs.at(m)).preciousness; |
2256 | - } |
2257 | - |
2258 | - // we can enhance this building. build more |
2259 | - // maybe the enhancement can produce needed ware |
2260 | - if (bo.desc->enhancements().size() > 0) { |
2261 | - // this code builds more metalworks |
2262 | - if (bo.total_count() == 0) |
2263 | - prio += 2; |
2264 | - if (bo.total_count() == 1) |
2265 | - prio += 8; |
2266 | - } |
2267 | - } |
2268 | - for (uint32_t m = 0; m < bo.inputs.size(); ++m) { |
2269 | - Ware_Index wt(static_cast<size_t>(bo.inputs.at(m))); |
2270 | - |
2271 | - // if the economies don't need it: "waste" it |
2272 | - if (!(*l.current)->economy.needs_ware(wt)) { |
2273 | - if (bo.total_count() == 0 && bo.prod_build_material) |
2274 | - // big bonus, this site might be elemental |
2275 | - prio += 3 * wares.at(bo.inputs.at(m)).preciousness; |
2276 | - } |
2277 | - } |
2278 | - } |
2279 | - |
2280 | - // If the produced wares are needed |
2281 | - if (prio > 0) { |
2282 | - int32_t inout_prio = 0; |
2283 | - for (size_t k = 0; k < bo.inputs.size(); ++k) { |
2284 | - inout_prio += bf->producers_nearby.at(bo.inputs.at(k)); |
2285 | - inout_prio -= bf->consumers_nearby.at(bo.inputs.at(k)) / 2; |
2286 | - } |
2287 | - for (size_t k = 0; k < bo.outputs.size(); ++k) |
2288 | - inout_prio += bf->consumers_nearby.at(bo.outputs.at(k)); |
2289 | - prio += 2 * inout_prio; |
2290 | - prio = calculate_need_for_ps(bo, prio); |
2291 | - } else |
2292 | - continue; |
2293 | - |
2294 | - // take care about borders and enemies |
2295 | - prio = recalc_with_border_range(*bf, prio); |
2296 | - |
2297 | - // do not construct more than one building, |
2298 | - // if supply line is already broken. |
2299 | - if (!check_supply(bo) && bo.total_count() > 0) |
2300 | - prio -= 12; |
2301 | - |
2302 | - } |
2303 | - } else if (bo.type == BuildingObserver::MILITARYSITE) { |
2304 | - if (!bf->unowned_land_nearby) |
2305 | - continue; |
2306 | - prio = bf->unowned_land_nearby * (1 + type); |
2307 | - prio -= bf->military_influence * (5 - type); |
2308 | - // set to at least 1 |
2309 | - prio = prio > 0 ? prio : 1; |
2310 | - prio *= expand_factor; |
2311 | - prio /= 2; |
2312 | - |
2313 | - if (bf->enemy_nearby) |
2314 | - prio *= 2; |
2315 | - else |
2316 | - prio -= bf->military_influence * 2; |
2317 | - |
2318 | - if (bf->avoid_military) |
2319 | - prio /= 5; |
2320 | - |
2321 | - prio -= militarysites.size() - productionsites.size() / (3 - type); |
2322 | - |
2323 | + if (bo.need_water_ and bf->water_nearby_ < 3) // probably some of them needs water |
2324 | + continue; |
2325 | + |
2326 | + if (bo.plants_trees_) { // RANGERS |
2327 | + if (bo.total_count() < bo.cnt_target_) |
2328 | + prio = 70; |
2329 | + else { // even when we are above goal we need to consider level of stock |
2330 | + if (bo.stocklevel_time < game().get_gametime() - 5 * 1000) { |
2331 | + bo.stocklevel_ = |
2332 | + get_stocklevel_by_hint(static_cast<size_t>(bo.production_hint_)); |
2333 | + bo.stocklevel_time = game().get_gametime(); |
2334 | + } |
2335 | + |
2336 | + if (bo.stocklevel_ < 5 and new_buildings_stop_) |
2337 | + prio = bf->producers_nearby_.at(bo.production_hint_) * 5 - 5 - |
2338 | + bf->trees_nearby_ * 2; |
2339 | + else if (bo.stocklevel_ < 50) |
2340 | + prio = 50 + bf->producers_nearby_.at(bo.production_hint_) * 5 - |
2341 | + bf->trees_nearby_ * 2; |
2342 | + else |
2343 | + continue; // we are above tresh |
2344 | + } |
2345 | + } else if (gametime > kBaseInfrastructureTime and not |
2346 | + new_buildings_stop_) { // gamekeepers or so |
2347 | + if (bo.stocklevel_time < game().get_gametime() - 5 * 1000) { |
2348 | + bo.stocklevel_ = |
2349 | + get_stocklevel_by_hint(static_cast<size_t>(bo.production_hint_)); |
2350 | + bo.stocklevel_time = game().get_gametime(); |
2351 | + } |
2352 | + |
2353 | + if (bo.total_count() < bo.cnt_target_) { |
2354 | + prio = bf->producers_nearby_.at(bo.production_hint_) * 10; |
2355 | + prio = recalc_with_border_range(*bf, prio); |
2356 | + |
2357 | + } else if (bo.stocklevel_ < 50 and not new_buildings_stop_) { |
2358 | + prio = bf->producers_nearby_.at(bo.production_hint_) * 5; |
2359 | + prio = recalc_with_border_range(*bf, prio); // only for not wood producers_ |
2360 | + } else |
2361 | + continue; |
2362 | + } |
2363 | + |
2364 | + if (kHintDebug or(kWoodDebug and bo.plants_trees_)) |
2365 | + printf(" TDEBUG: %1d: suggesting new %16s at %3dx%3d, current count: %2d, goal: " |
2366 | + "%2d, stocklevel_:%3d, new build. stop: %s, prio: %d\n", |
2367 | + player_number(), |
2368 | + bo.name, |
2369 | + bf->coords.x, |
2370 | + bf->coords.y, |
2371 | + bo.total_count(), |
2372 | + bo.cnt_target_, |
2373 | + bo.stocklevel_, |
2374 | + new_buildings_stop_ ? "Y" : "N", |
2375 | + prio); |
2376 | + |
2377 | + if (prio <= 0) |
2378 | + continue; |
2379 | + } else if (bo.recruitment_ and gametime > |
2380 | + kBaseInfrastructureTime and not new_buildings_stop_) { |
2381 | + // this will depend on number of mines_ and productionsites |
2382 | + if (static_cast<int32_t>((productionsites.size() + mines_.size()) / 30) > |
2383 | + bo.total_count() and bo.cnt_under_construction_ == |
2384 | + 0) |
2385 | + prio = 4 + bulgarian_constant; |
2386 | + } else { // finally normal productionsites |
2387 | + if (bo.production_hint_ >= 0) |
2388 | + continue; |
2389 | + |
2390 | + if ((bo.cnt_under_construction_ + bo.unoccupied_) > 0) |
2391 | + continue; |
2392 | + |
2393 | + // first eliminate buildings needing water if there is short supplies |
2394 | + if (bo.need_water_ and bf->water_nearby_ < 3) |
2395 | + continue; |
2396 | + |
2397 | + if ((bo.is_basic_ or bo.prod_build_material_)and bo.total_count() == 0) |
2398 | + prio = 150 + max_preciousness; |
2399 | + else if (game().get_gametime() < |
2400 | + kBaseInfrastructureTime or |
2401 | + new_buildings_stop_) // leave 15 minutes for basic infrastructure only |
2402 | + continue; |
2403 | + else if (((bo.is_basic_ or bo.prod_build_material_)and bo.total_count() <= |
2404 | + 1)or(output_is_needed and bo.total_count() == 0)) |
2405 | + prio = 80 + max_preciousness; |
2406 | + else if (bo.inputs_.size() == 0) { |
2407 | + bo.cnt_target_ = |
2408 | + 1 + static_cast<int32_t>(mines_.size() + productionsites.size()) / 8; |
2409 | + |
2410 | + if (bo.cnt_built_ > |
2411 | + bo.cnt_target_ and not |
2412 | + bo.space_consumer_) // spaceconsumers_ can be built more then target |
2413 | + continue; |
2414 | + |
2415 | + if (bo.stocklevel_time < game().get_gametime() - 5 * 1000) { |
2416 | + bo.stocklevel_ = get_stocklevel(bo); |
2417 | + bo.stocklevel_time = game().get_gametime(); |
2418 | + } |
2419 | + if (kSpaceDebug and bo.space_consumer_) |
2420 | + printf(" TDEBUG: %1d: considering %-15s, stock: %3d\n", |
2421 | + player_number(), |
2422 | + bo.name, |
2423 | + bo.stocklevel_); |
2424 | + |
2425 | + if (bo.stocklevel_ < 50) { |
2426 | + prio = max_preciousness + bulgarian_constant; |
2427 | + |
2428 | + if (bo.space_consumer_) |
2429 | + prio += 5; |
2430 | + |
2431 | + if (not bo.space_consumer_) |
2432 | + prio -= bf->producers_nearby_.at(bo.outputs_.at(0)) * |
2433 | + 20; // leave some free space between them |
2434 | + |
2435 | + if (bo.cnt_built_ < 2) |
2436 | + prio += 5; |
2437 | + |
2438 | + prio = recalc_with_border_range(*bf, prio); |
2439 | + |
2440 | + if (kProductionDebug or(kSpaceDebug and bo.space_consumer_)) |
2441 | + printf(" TDEBUG: %1d: proposing %-15s , on stock: %3d(<50), stat: %3d, " |
2442 | + "count: %2d/T:%2d, setting priority: %2d, on %3d %3d\n", |
2443 | + player_number(), |
2444 | + bo.name, |
2445 | + bo.stocklevel_, |
2446 | + bo.current_stats_, |
2447 | + bo.total_count(), |
2448 | + bo.cnt_target_, |
2449 | + prio, |
2450 | + bf->coords.x, |
2451 | + bf->coords.y); |
2452 | + } |
2453 | + } else if (bo.inputs_.size() > 0) { |
2454 | + // to have two buildings from everything (intended for upgradeable buildings) |
2455 | + // but I do not know how to identify such buildings |
2456 | + if (bo.cnt_built_ == 1 and game().get_gametime() > |
2457 | + 60 * 60 * 1000 and bo.desc->enhancements().size() > |
2458 | + 0 and mines_.size() > 0) { |
2459 | + prio = max_preciousness + bulgarian_constant; |
2460 | + } |
2461 | + // if output is needed and there are no idle buildings |
2462 | + else if (output_is_needed) { |
2463 | + if (bo.cnt_built_ > 0 and bo.current_stats_ > 80) { |
2464 | + prio = max_preciousness + bulgarian_constant + 30; |
2465 | + |
2466 | + if (kProductionDebug) |
2467 | + printf(" TDEBUG: %2d/%-15s with inputs_: stats: %3d>90, setting " |
2468 | + "priority: %2d, on %3d %3d\n", |
2469 | + bo.id, |
2470 | + bo.name, |
2471 | + bo.current_stats_, |
2472 | + prio, |
2473 | + bf->coords.x, |
2474 | + bf->coords.y); |
2475 | + } else if (bo.cnt_built_ > 0 and bo.current_stats_ > 55) { |
2476 | + prio = max_preciousness + bulgarian_constant; |
2477 | + |
2478 | + if (kProductionDebug) |
2479 | + printf(" TDEBUG: %2d/%-15s with inputs_: stats: %3d>60, setting " |
2480 | + "priority: %2d, on %3d %3d\n", |
2481 | + bo.id, |
2482 | + bo.name, |
2483 | + bo.current_stats_, |
2484 | + prio, |
2485 | + bf->coords.x, |
2486 | + bf->coords.y); |
2487 | + } |
2488 | + } |
2489 | + } |
2490 | + |
2491 | + if (prio <= 0) |
2492 | + continue; |
2493 | + |
2494 | + // then we consider borders and enemies nearby (if any) |
2495 | + prio = recalc_with_border_range(*bf, prio); |
2496 | + |
2497 | + //+1 if any consumers_ are nearby |
2498 | + consumers_nearby_count = 0; |
2499 | + |
2500 | + for (size_t k = 0; k < bo.outputs_.size(); ++k) |
2501 | + consumers_nearby_count += bf->consumers_nearby_.at(bo.outputs_.at(k)); |
2502 | + |
2503 | + if (consumers_nearby_count > 0) |
2504 | + prio += 1; |
2505 | + } |
2506 | + } // production sites done |
2507 | + else if (bo.type == BuildingObserver::MILITARYSITE) { |
2508 | + if (military_boost > 1 and kMilitaryDebug) |
2509 | + printf(" TDEBUG: boosting: unowned land %d \n", bf->unowned_land_nearby_); |
2510 | + |
2511 | + if (new_military_buildings_stop and not bf->enemy_nearby_) |
2512 | + continue; |
2513 | + |
2514 | + if (near_enemy_b_buildings_stop and bf->enemy_nearby_) |
2515 | + continue; |
2516 | + |
2517 | + if (bo.desc->get_size() == |
2518 | + 3 and game().get_gametime() < |
2519 | + 15 * 60 * 1000) // do not built fortresses in first half of hour of game |
2520 | + continue; |
2521 | + |
2522 | + if (!bf->unowned_land_nearby_) |
2523 | + continue; |
2524 | + |
2525 | + // not to build so many military buildings nearby |
2526 | + if (!bf->enemy_nearby_ and bf->military_in_constr_nearby_ > 1) |
2527 | + continue; |
2528 | + |
2529 | + // here is to consider unowned potential mines |
2530 | + int32_t mines_spots_score = 0; |
2531 | + mines_spots_score = bf->unowned_mines_pots_nearby_; |
2532 | + |
2533 | + if (mines_spots_score > 0) { |
2534 | + mines_spots_score *= 4; |
2535 | + mines_spots_score += 8; |
2536 | + } |
2537 | + |
2538 | + prio = (bf->unowned_land_nearby_ - 4 + mines_spots_score + bf->stones_nearby_ / 2 + |
2539 | + bf->military_loneliness_ / 5 - 100 + military_boost); // * (1 + type); |
2540 | + |
2541 | + if (kMilitaryDebug) |
2542 | + printf(" NEW MILITARY: %3dx%3d: unowned: %3d(%3d), mines_: %3d, lonel.: %4d (%4d), " |
2543 | + "stones: %2d, boost: %3d,result: %3d, enemy:% 2d, cur stat: %2d/%2d/%2d, " |
2544 | + "stops:%s %s\n", |
2545 | + bf->coords.x, |
2546 | + bf->coords.y, |
2547 | + bf->unowned_land_nearby_ - 4, |
2548 | + mines_spots_score, |
2549 | + bf->unowned_mines_pots_nearby_, |
2550 | + bf->military_loneliness_ / 5 - 100, |
2551 | + bf->military_loneliness_, |
2552 | + bf->stones_nearby_ / 2, |
2553 | + military_boost, |
2554 | + prio, |
2555 | + bf->enemy_nearby_, |
2556 | + bo.cnt_built_, |
2557 | + unstationed_milit_buildings_, |
2558 | + bo.cnt_under_construction_, |
2559 | + new_military_buildings_stop ? "Y" : "N", |
2560 | + near_enemy_b_buildings_stop ? "Y" : "N"); |
2561 | + |
2562 | + if (bo.desc->get_size() < maxsize) |
2563 | + prio = prio - 5; // penalty |
2564 | + |
2565 | + if (bf->enemy_nearby_ and bf->military_capacity_ < 12) { |
2566 | + if (kMilitaryDebug) |
2567 | + printf(" NEW MILITARY: Military capacity: %2d, boosting priority by 100d\n", |
2568 | + bf->military_capacity_); |
2569 | + |
2570 | + prio += 100; |
2571 | + } |
2572 | + |
2573 | + if (kMilitaryDebug and prio > 0) |
2574 | + printf(" NEW MILITARY: candidate's final priority: %d \n", prio); |
2575 | } else if (bo.type == BuildingObserver::WAREHOUSE) { |
2576 | - // Build one warehouse for ~every 35 productionsites and mines. |
2577 | + // Build one warehouse for ~every 35 productionsites and mines_. |
2578 | // Militarysites are slightly important as well, to have a bigger |
2579 | // chance for a warehouses (containing waiting soldiers or wares |
2580 | // needed for soldier training) near the frontier. |
2581 | - prio += productionsites.size() + mines.size(); |
2582 | - prio += militarysites.size() / 3; |
2583 | - prio -= (bo.cnt_under_construction + numof_warehouses) * 35; |
2584 | - prio *= 2; |
2585 | + if ((static_cast<int32_t>(productionsites.size() + mines_.size())) / 35 > |
2586 | + static_cast<int32_t>(numof_warehouses_) and bo.cnt_under_construction_ == |
2587 | + 0) |
2588 | + prio = 13; |
2589 | |
2590 | // take care about borders and enemies |
2591 | prio = recalc_with_border_range(*bf, prio); |
2592 | |
2593 | + // TODO: |
2594 | + // introduce check that there is no warehouse nearby to prevent to close placing |
2595 | + |
2596 | } else if (bo.type == BuildingObserver::TRAININGSITE) { |
2597 | - // Start building trainingsites when there are already more than 50 |
2598 | - // other buildings. That should be enough for a working economy. |
2599 | - // On the other hand only build more trainingsites of the same |
2600 | - // type if the economy is really big. |
2601 | - prio += productionsites.size() + militarysites.size(); |
2602 | - prio += mines.size(); |
2603 | - prio += type * 10; // +0 / +10 / +20 for DEFF/NORM/AGGR |
2604 | - prio = prio / (bo.total_count() + 1); |
2605 | - prio -= (bo.total_count() + 1) * 70; |
2606 | + // build after 20 production sites and then after each 50 production site |
2607 | + if (static_cast<int32_t>((productionsites.size() + 30) / 50) > |
2608 | + bo.total_count() and bo.cnt_under_construction_ == |
2609 | + 0) |
2610 | + prio = 4; |
2611 | |
2612 | // take care about borders and enemies |
2613 | prio = recalc_with_border_range(*bf, prio); |
2614 | } |
2615 | |
2616 | - // avoid to have too many construction sites |
2617 | - // but still enable the player to build up basic productionsites |
2618 | - if |
2619 | - (bo.type != BuildingObserver::PRODUCTIONSITE || |
2620 | - !bo.is_basic || bo.total_count() > 0) |
2621 | - prio /= |
2622 | - 1 + bo.cnt_under_construction * (bo.cnt_under_construction + 1); |
2623 | - |
2624 | - // add big penalty if water is needed, but is not near |
2625 | - if (bo.need_water) { |
2626 | - if (bf->water_nearby < 3) |
2627 | - continue; |
2628 | - int effect = bf->water_nearby - 8; |
2629 | - prio += |
2630 | - effect > 0 ? |
2631 | - static_cast<int>(sqrt(static_cast<double>(effect))) : effect; |
2632 | - // if same producers are nearby, then give some penalty |
2633 | - for (size_t k = 0; k < bo.outputs.size(); ++k) |
2634 | - if (bf->producers_nearby.at(bo.outputs.at(k)) > 0) |
2635 | - prio -= 3; |
2636 | - } |
2637 | - |
2638 | // think of space consuming buildings nearby like farms or vineyards |
2639 | - prio /= 1 + bf->space_consumers_nearby; |
2640 | + prio -= bf->space_consumers_nearby_ * 10; |
2641 | |
2642 | // Stop here, if priority is 0 or less. |
2643 | if (prio <= 0) |
2644 | continue; |
2645 | |
2646 | // Prefer road side fields |
2647 | - prio += bf->preferred ? 1 : 0; |
2648 | - |
2649 | + prio += bf->preferred_ ? 1 : 0; |
2650 | // don't waste good land for small huts |
2651 | - prio -= (maxsize - bo.desc->get_size()) * 3; |
2652 | - if (prio > proposed_priority) { |
2653 | - proposed_building = bo.id; |
2654 | - proposed_priority = prio; |
2655 | - proposed_coords = bf->coords; |
2656 | - } |
2657 | - } |
2658 | - } |
2659 | - |
2660 | - // then try all mines - as soon as basic economy is build up. |
2661 | - for |
2662 | - (uint32_t i = 0; i < buildings.size() && productionsites.size() > 8; ++i) |
2663 | - { |
2664 | - BuildingObserver & bo = buildings.at(i); |
2665 | - |
2666 | - if (!bo.buildable(*player) || bo.type != BuildingObserver::MINE) |
2667 | - continue; |
2668 | - |
2669 | - // Don't build another building of this type, if there is already |
2670 | - // one that is unoccupied at the moment |
2671 | - if (bo.unoccupied) |
2672 | - continue; |
2673 | - |
2674 | - |
2675 | - // Only have 2 mines of a type under construction |
2676 | - if (bo.cnt_under_construction > 2) |
2677 | - continue; |
2678 | - |
2679 | - if (onlymissing) |
2680 | - // Do not build mines twice, as long as other buildings might be more needed |
2681 | - if (bo.total_count() > 0) |
2682 | - continue; |
2683 | - |
2684 | - |
2685 | - for |
2686 | - (std::list<MineableField *>::iterator j = mineable_fields.begin(); |
2687 | - j != mineable_fields.end(); |
2688 | - ++j) |
2689 | - { |
2690 | - int32_t prio = 0; |
2691 | - |
2692 | - if ((*j)->coords.field->get_resources() != bo.mines) |
2693 | - continue; |
2694 | - else |
2695 | - prio += (*j)->coords.field->get_resources_amount() * 4 / 3; |
2696 | - |
2697 | - // Only build mines on locations where some material can be mined |
2698 | - if (prio < 2) |
2699 | - continue; |
2700 | - |
2701 | - // Continue if field is blocked at the moment |
2702 | - bool blocked = false; |
2703 | - for |
2704 | - (std::list<BlockedField>::iterator k = blocked_fields.begin(); |
2705 | - k != blocked_fields.end(); |
2706 | - ++k) |
2707 | - if ((*j)->coords == k->coords) { |
2708 | - blocked = true; |
2709 | - break; |
2710 | - } |
2711 | - if (blocked) continue; |
2712 | - |
2713 | - // Check if current economy can supply enough food for production. |
2714 | - for (uint32_t k = 0; k < bo.inputs.size(); ++k) { |
2715 | - prio += wares.at(bo.inputs.at(k)).producers; |
2716 | - prio -= wares.at(bo.inputs.at(k)).consumers / 2; |
2717 | - } |
2718 | - |
2719 | - // our wares are needed? gimme more |
2720 | - uint32_t ioprio = 0; |
2721 | - for (uint32_t m = 0; m < bo.outputs.size(); ++m) { |
2722 | - ioprio += 5 * wares.at(bo.outputs.at(m)).preciousness; |
2723 | - } |
2724 | - |
2725 | - // tribes that have enhanceable mines should build more mines |
2726 | - prio *= 1 + 100 / bo.mines_percent; |
2727 | - |
2728 | - // No plus for mines with multiple output |
2729 | - ioprio /= bo.outputs.size(); |
2730 | - prio += ioprio; |
2731 | - |
2732 | - prio -= 3 * (*j)->mines_nearby * (*j)->mines_nearby; |
2733 | - //prio /= 1 + bo.cnt_built * 2; |
2734 | - |
2735 | - // multiply with current statistics of all other buildings of this |
2736 | - // type to avoid constructing buildings where already some are running |
2737 | - // on low resources. |
2738 | - prio *= 5 + bo.current_stats; |
2739 | - prio /= 100; |
2740 | - |
2741 | - if (onlymissing) // mines aren't *that* important |
2742 | - prio /= 3; |
2743 | - if (prio > proposed_priority) { |
2744 | - |
2745 | - proposed_building = bo.id; |
2746 | - proposed_priority = prio; |
2747 | - proposed_coords = (*j)->coords; |
2748 | - mine = true; |
2749 | - } |
2750 | - } |
2751 | - } |
2752 | - |
2753 | - if (proposed_building == INVALID_INDEX) |
2754 | - return false; |
2755 | - |
2756 | - // do not have too many construction sites |
2757 | - if |
2758 | - (proposed_priority < static_cast<int32_t>(total_constructionsites) |
2759 | - and not |
2760 | - onlymissing) // only return here, if we do NOT try to build a missing bld |
2761 | - return false; |
2762 | + prio -= (maxsize - bo.desc->get_size()) * 5; |
2763 | + |
2764 | + if (prio > proposed_priority) { |
2765 | + best_building = &bo; |
2766 | + proposed_priority = prio; |
2767 | + proposed_coords = bf->coords; |
2768 | + } |
2769 | + } // ending loop over buildings |
2770 | + } // ending loop over fields |
2771 | + |
2772 | + // then try all mines_ - as soon as basic economy is build up. |
2773 | + if (gametime > next_mine_construction_due_) { |
2774 | + |
2775 | + update_all_mineable_fields(gametime); |
2776 | + next_mine_construction_due_ = gametime + kIdleMineUpdateInterval; |
2777 | + |
2778 | + if (mineable_fields.size() > 0) { |
2779 | + |
2780 | + for (uint32_t i = 0; i < buildings.size() && productionsites.size() > 8; ++i) { |
2781 | + BuildingObserver& bo = buildings.at(i); |
2782 | + |
2783 | + if (not bo.mines_marble_ and gametime < |
2784 | + kBaseInfrastructureTime) // allow only stone mines_ in early stages of game |
2785 | + continue; |
2786 | + |
2787 | + if (!bo.buildable(*player) || bo.type != BuildingObserver::MINE) |
2788 | + continue; |
2789 | + |
2790 | + if (gametime - bo.construction_decision_time_ < kBuildingMinInterval) |
2791 | + continue; |
2792 | + |
2793 | + // Don't build another building of this type, if there is already |
2794 | + // one that is unoccupied_ at the moment |
2795 | + // or under construction |
2796 | + if ((bo.cnt_under_construction_ + bo.unoccupied_) > 0) |
2797 | + continue; |
2798 | + |
2799 | + // calculating actual amount of mined raw materials |
2800 | + if (bo.stocklevel_time < game().get_gametime() - 5 * 1000) { |
2801 | + bo.stocklevel_ = get_stocklevel(bo); |
2802 | + bo.stocklevel_time = game().get_gametime(); |
2803 | + } |
2804 | + |
2805 | + if (kMinesDebug) |
2806 | + printf( |
2807 | + " TDEBUG: %1d considering %12s/%1d: stat: %3d(<20), stocklevel_: %2d, count %2d " |
2808 | + "/ %2d / %2d\n", |
2809 | + player_number(), |
2810 | + bo.name, |
2811 | + bo.mines_, |
2812 | + bo.current_stats_, |
2813 | + bo.stocklevel_, |
2814 | + bo.total_count(), |
2815 | + bo.unoccupied_, |
2816 | + bo.cnt_under_construction_); |
2817 | + |
2818 | + // Only try to build mines_ that produce needed wares. |
2819 | + if (((bo.cnt_built_ - bo.unoccupied_) > 0 and bo.current_stats_ < 20)or bo.stocklevel_ > |
2820 | + 40 + static_cast<uint32_t>(bo.mines_marble_) * 30) { |
2821 | + if (kMinesDebug) |
2822 | + printf(" No need to seek for this mine type: stat: %2d, stock :%2d/%2d\n", |
2823 | + bo.current_stats_, |
2824 | + bo.stocklevel_, |
2825 | + 40 + bo.mines_marble_ * 30); |
2826 | + continue; |
2827 | + } |
2828 | + |
2829 | + // this is penalty if there are existing mines too close |
2830 | + // it is treated as multiplicator for count of near mines |
2831 | + uint32_t nearness_penalty = 0; |
2832 | + if ((bo.cnt_built_ + bo.cnt_under_construction_) == 0) |
2833 | + nearness_penalty = 0; |
2834 | + else if (bo.mines_marble_) |
2835 | + nearness_penalty = 7; |
2836 | + else |
2837 | + nearness_penalty = 10; |
2838 | + |
2839 | + // iterating over fields |
2840 | + for (std::list<MineableField*>::iterator j = mineable_fields.begin(); |
2841 | + j != mineable_fields.end(); |
2842 | + ++j) { |
2843 | + |
2844 | + if ((*j)->coords.field->get_resources() != bo.mines_) |
2845 | + continue; |
2846 | + |
2847 | + int32_t prio = (*j)->coords.field->get_resources_amount(); |
2848 | + |
2849 | + // applying nearnes penalty |
2850 | + prio = prio - (*j)->mines_nearby_ * nearness_penalty; |
2851 | + |
2852 | + if (kMinesDebug) |
2853 | + printf(" TDEBUG: priority of spot at %3d x %3d: %3d (%2d - %2d*%2d) , current " |
2854 | + "best: %2d \n", |
2855 | + (*j)->coords.x, |
2856 | + (*j)->coords.y, |
2857 | + prio, |
2858 | + (*j)->coords.field->get_resources_amount(), |
2859 | + (*j)->mines_nearby_, |
2860 | + nearness_penalty, |
2861 | + proposed_priority); |
2862 | + |
2863 | + // Only build mines_ on locations where some material can be mined |
2864 | + if (prio < 2) |
2865 | + continue; |
2866 | + |
2867 | + // Continue if field is blocked at the moment |
2868 | + bool blocked = false; |
2869 | + |
2870 | + for (std::list<BlockedField>::iterator k = blocked_fields.begin(); |
2871 | + k != blocked_fields.end(); |
2872 | + ++k) |
2873 | + if ((*j)->coords == k->coords) { |
2874 | + blocked = true; |
2875 | + break; |
2876 | + } |
2877 | + |
2878 | + if (blocked) { |
2879 | + if (kMinesDebug) |
2880 | + printf(" spot blocked!\n"); |
2881 | + continue; |
2882 | + } |
2883 | + |
2884 | + if (prio > proposed_priority) { |
2885 | + // proposed_building = bo.id; |
2886 | + best_building = &bo; |
2887 | + proposed_priority = prio; |
2888 | + proposed_coords = (*j)->coords; |
2889 | + mine = true; |
2890 | + |
2891 | + if (kMinesDebug) |
2892 | + printf(" TDEBUG: using %-12s as a candidate\n", bo.name); |
2893 | + } |
2894 | + } // end of evaluation of field |
2895 | + } |
2896 | + |
2897 | + } // section if mine size >0 |
2898 | + } // end of mines_ section |
2899 | + |
2900 | + // if there is no winner: |
2901 | + // if (proposed_building == INVALID_INDEX) { |
2902 | + if (best_building == nullptr) { |
2903 | + if (kWinnerDebug) |
2904 | + printf(" TDEBUG: no building picked up\n"); |
2905 | + |
2906 | + mine = false; |
2907 | + return false; |
2908 | + } |
2909 | |
2910 | // send the command to construct a new building |
2911 | - game().send_player_build |
2912 | - (player_number(), proposed_coords, proposed_building); |
2913 | + game().send_player_build(player_number(), proposed_coords, best_building->id); |
2914 | + BlockedField blocked( |
2915 | + game().map().get_fcoords(proposed_coords), game().get_gametime() + 120000); // two minutes |
2916 | + blocked_fields.push_back(blocked); |
2917 | + |
2918 | + if (not best_building->type == BuildingObserver::MILITARYSITE) |
2919 | + best_building->construction_decision_time_ = gametime; |
2920 | + else // very ugly hack here |
2921 | + best_building->construction_decision_time_ = gametime - kBuildingMinInterval / 2; |
2922 | + |
2923 | + if (kWinnerDebug) |
2924 | + printf(" TDEBUG: winning priority %4d, building %2d, coords: %3d x %3d, M: %s\n", |
2925 | + proposed_priority, |
2926 | + best_building->id, |
2927 | + proposed_coords.x, |
2928 | + proposed_coords.y, |
2929 | + mine ? "Y" : "N"); |
2930 | |
2931 | // set the type of update that is needed |
2932 | - if (mine) |
2933 | - m_mineable_changed = true; |
2934 | - else |
2935 | + if (mine) { |
2936 | + next_mine_construction_due_ = gametime + kBusyMineUpdateInterval; |
2937 | + |
2938 | + if (kMinesUpdateDebug) |
2939 | + printf(" TDEBUG expanding mine update by: %d,building %2d, coords: %3d x %3d \n", |
2940 | + kBusyMineUpdateInterval, |
2941 | + best_building->id, |
2942 | + proposed_coords.x, |
2943 | + proposed_coords.y); |
2944 | + |
2945 | + if (kMinesUpdateDebug) |
2946 | + printf(" new next_mine_construction_due_=%10d\n", next_mine_construction_due_); |
2947 | + |
2948 | + // m_mineable_changed = true; |
2949 | + } else |
2950 | + // last_mine_constr_time=gametime; |
2951 | m_buildable_changed = true; |
2952 | |
2953 | return true; |
2954 | @@ -1239,25 +1606,25 @@ |
2955 | * This function searches for places where a new road is needed to connect two |
2956 | * economies. It then sends the request to build the road. |
2957 | */ |
2958 | -bool DefaultAI::construct_roads (int32_t gametime) |
2959 | -{ |
2960 | +bool DefaultAI::construct_roads(int32_t gametime) { |
2961 | if (economies.size() < 2) { |
2962 | // only one economy, no need for new roads |
2963 | return false; |
2964 | } |
2965 | |
2966 | uint32_t economies_to_connect = 0; |
2967 | - EconomyObserver * eo_to_connect = economies.front(); // dummy initialisation |
2968 | + EconomyObserver* eo_to_connect = economies.front(); // dummy initialisation |
2969 | |
2970 | // fetch first two economies that might be connectable |
2971 | - for |
2972 | - (std::list<EconomyObserver *>::iterator i = economies.begin(); |
2973 | - economies_to_connect < 2 && i != economies.end(); |
2974 | - ++i) |
2975 | + for (std::list<EconomyObserver*>::iterator i = economies.begin(); |
2976 | + economies_to_connect < 2 && i != economies.end(); |
2977 | + ++i) |
2978 | + |
2979 | // Do not try to connect economies that already failed in last time. |
2980 | if ((*i)->next_connection_try <= gametime) { |
2981 | if (economies_to_connect == 1) |
2982 | eo_to_connect = *i; |
2983 | + |
2984 | ++economies_to_connect; |
2985 | } |
2986 | |
2987 | @@ -1287,22 +1654,19 @@ |
2988 | |
2989 | // If the economy consists of just one constructionsite, and the defaultAI |
2990 | // failed more than 4 times to connect, we remove the constructionsite |
2991 | - if |
2992 | - (eo_to_connect->failed_connection_tries > 3 |
2993 | - and |
2994 | - eo_to_connect->flags.size() == 1) |
2995 | - { |
2996 | - Building * bld = eo_to_connect->flags.front()->get_building(); |
2997 | + if (eo_to_connect->failed_connection_tries > 3 and eo_to_connect->flags.size() == 1) { |
2998 | + Building* bld = eo_to_connect->flags.front()->get_building(); |
2999 | + |
3000 | if (bld) { |
3001 | - BuildingObserver & bo = get_building_observer(bld->name().c_str()); |
3002 | + BuildingObserver& bo = get_building_observer(bld->name().c_str()); |
3003 | + |
3004 | if (bo.type == BuildingObserver::CONSTRUCTIONSITE) { |
3005 | - game().send_player_bulldoze(*const_cast<Flag *>(eo_to_connect->flags.front())); |
3006 | + game().send_player_bulldoze(*const_cast<Flag*>(eo_to_connect->flags.front())); |
3007 | eo_to_connect->flags.pop_front(); |
3008 | // Block the field at constructionsites coords for 5 minutes |
3009 | // against new construction tries. |
3010 | - BlockedField blocked |
3011 | - (game().map().get_fcoords(bld->get_position()), |
3012 | - game().get_gametime() + 300000); |
3013 | + BlockedField blocked( |
3014 | + game().map().get_fcoords(bld->get_position()), game().get_gametime() + 300000); |
3015 | blocked_fields.push_back(blocked); |
3016 | } |
3017 | } |
3018 | @@ -1315,58 +1679,62 @@ |
3019 | } |
3020 | |
3021 | /// improves current road system |
3022 | -bool DefaultAI::improve_roads (int32_t gametime) |
3023 | -{ |
3024 | +bool DefaultAI::improve_roads(int32_t gametime) { |
3025 | // Remove flags of dead end roads, as long as no more wares are stored on them |
3026 | - container_iterate(std::list<EconomyObserver *>, economies, i) |
3027 | - container_iterate(std::list<Flag const *>, (*i.current)->flags, j) |
3028 | - if ((*j.current)->is_dead_end() && (*j.current)->current_wares() == 0) { |
3029 | - game().send_player_bulldoze(*const_cast<Flag *>((*j.current))); |
3030 | - j.current = (*i.current)->flags.erase(j.current); |
3031 | - return true; |
3032 | - } |
3033 | + container_iterate(std::list<EconomyObserver*>, economies, i) |
3034 | + container_iterate(std::list<Flag const*>, (*i.current)->flags, j) |
3035 | + |
3036 | + if ((*j.current)->is_dead_end() && (*j.current)->current_wares() == 0) { |
3037 | + game().send_player_bulldoze(*const_cast<Flag*>((*j.current))); |
3038 | + j.current = (*i.current)->flags.erase(j.current); |
3039 | + return true; |
3040 | + } |
3041 | |
3042 | // force a split on roads that are longer than 3 parts |
3043 | // actually we do not care for loss of building capabilities - normal maps |
3044 | // should have enough space and the computer can expand it's territory. |
3045 | if (!roads.empty()) { |
3046 | - const Path & path = roads.front()->get_path(); |
3047 | + const Path& path = roads.front()->get_path(); |
3048 | |
3049 | if (path.get_nsteps() > 3) { |
3050 | - const Map & map = game().map(); |
3051 | + const Map& map = game().map(); |
3052 | CoordPath cp(map, path); |
3053 | - |
3054 | // try to split after two steps |
3055 | CoordPath::Step_Vector::size_type i = cp.get_nsteps() - 1, j = 1; |
3056 | + |
3057 | for (; i >= j; --i, ++j) { |
3058 | { |
3059 | const Coords c = cp.get_coords().at(i); |
3060 | + |
3061 | if (map[c].nodecaps() & BUILDCAPS_FLAG) { |
3062 | - game().send_player_build_flag (player_number(), c); |
3063 | + game().send_player_build_flag(player_number(), c); |
3064 | return true; |
3065 | } |
3066 | } |
3067 | { |
3068 | const Coords c = cp.get_coords().at(j); |
3069 | + |
3070 | if (map[c].nodecaps() & BUILDCAPS_FLAG) { |
3071 | - game().send_player_build_flag (player_number(), c); |
3072 | + game().send_player_build_flag(player_number(), c); |
3073 | return true; |
3074 | } |
3075 | } |
3076 | } |
3077 | + |
3078 | // Unable to set a flag - perhaps the road was build stupid |
3079 | - game().send_player_bulldoze(*const_cast<Road *>(roads.front())); |
3080 | + game().send_player_bulldoze(*const_cast<Road*>(roads.front())); |
3081 | } |
3082 | |
3083 | - roads.push_back (roads.front()); |
3084 | - roads.pop_front (); |
3085 | + roads.push_back(roads.front()); |
3086 | + roads.pop_front(); |
3087 | } |
3088 | |
3089 | - if (!economies.empty() && inhibit_road_building <= gametime) { |
3090 | - EconomyObserver * eco = economies.front(); |
3091 | + if (!economies.empty() && inhibit_road_building_ <= gametime) { |
3092 | + EconomyObserver* eco = economies.front(); |
3093 | + |
3094 | if (!eco->flags.empty()) { |
3095 | bool finish = false; |
3096 | - const Flag & flag = *eco->flags.front(); |
3097 | + const Flag& flag = *eco->flags.front(); |
3098 | |
3099 | // try to connect to another economy |
3100 | if (economies.size() > 1) |
3101 | @@ -1376,17 +1744,15 @@ |
3102 | // TODO do this only on useful places - the attempt below |
3103 | // TODO unfortunatey did not work as it should... |
3104 | // if the flag is full of wares or if it is not yet a fork. |
3105 | - if (!finish) //&& (!flag.has_capacity() || flag.nr_of_roads() < 3)) |
3106 | + if (!finish) //&& (!flag.has_capacity() || flag.nr_of_roads() < 3)) |
3107 | finish = improve_transportation_ways(flag); |
3108 | |
3109 | // cycle through flags one at a time |
3110 | eco->flags.push_back(eco->flags.front()); |
3111 | eco->flags.pop_front(); |
3112 | - |
3113 | // and cycle through economies |
3114 | economies.push_back(eco); |
3115 | economies.pop_front(); |
3116 | - |
3117 | return finish; |
3118 | } else |
3119 | // If the economy has no flag, the observers need to be updated. |
3120 | @@ -1396,32 +1762,28 @@ |
3121 | return false; |
3122 | } |
3123 | |
3124 | - |
3125 | // connects a specific flag to another economy |
3126 | -bool DefaultAI::connect_flag_to_another_economy (const Flag & flag) |
3127 | -{ |
3128 | +bool DefaultAI::connect_flag_to_another_economy(const Flag& flag) { |
3129 | FindNodeWithFlagOrRoad functor; |
3130 | CheckStepRoadAI check(player, MOVECAPS_WALK, true); |
3131 | std::vector<Coords> reachable; |
3132 | // first look for possible destinations |
3133 | functor.economy = flag.get_economy(); |
3134 | - Map & map = game().map(); |
3135 | - map.find_reachable_fields |
3136 | - (Area<FCoords>(map.get_fcoords(flag.get_position()), 16), |
3137 | - &reachable, |
3138 | - check, |
3139 | - functor); |
3140 | + Map& map = game().map(); |
3141 | + map.find_reachable_fields( |
3142 | + Area<FCoords>(map.get_fcoords(flag.get_position()), 16), &reachable, check, functor); |
3143 | |
3144 | if (reachable.empty()) |
3145 | return false; |
3146 | |
3147 | // then choose the one with the shortest path |
3148 | - Path * path = new Path(); |
3149 | + Path* path = new Path(); |
3150 | bool found = false; |
3151 | check.set_openend(false); |
3152 | Coords closest; |
3153 | container_iterate_const(std::vector<Coords>, reachable, i) { |
3154 | - Path * path2 = new Path(); |
3155 | + Path* path2 = new Path(); |
3156 | + |
3157 | if (map.findpath(flag.get_position(), *i.current, 0, *path2, check) >= 0) { |
3158 | if (!found || path->get_nsteps() > path2->get_nsteps()) { |
3159 | delete path; |
3160 | @@ -1431,12 +1793,13 @@ |
3161 | found = true; |
3162 | } |
3163 | } |
3164 | + |
3165 | delete path2; |
3166 | } |
3167 | |
3168 | if (found) { |
3169 | // if we join a road and there is no flag yet, build one |
3170 | - if (dynamic_cast<const Road *>(map[closest].get_immovable())) |
3171 | + if (dynamic_cast<const Road*>(map[closest].get_immovable())) |
3172 | game().send_player_build_flag(player_number(), closest); |
3173 | |
3174 | // and finally build the road |
3175 | @@ -1449,12 +1812,12 @@ |
3176 | } |
3177 | |
3178 | /// adds alternative ways to already existing ones |
3179 | -bool DefaultAI::improve_transportation_ways (const Flag & flag) |
3180 | -{ |
3181 | +bool DefaultAI::improve_transportation_ways(const Flag& flag) { |
3182 | // First of all try to remove old building flags to clean up the road web if possible |
3183 | container_iterate(std::list<Widelands::Coords>, flags_to_be_removed, i) { |
3184 | // Maybe the flag was already removed? |
3185 | FCoords f = game().map().get_fcoords(*(i.current)); |
3186 | + |
3187 | if (upcast(Flag, other_flag, f.field->get_immovable())) { |
3188 | // Check if building is dismantled, but don't waste precious wares |
3189 | if (!other_flag->get_building() && other_flag->current_wares() == 0) { |
3190 | @@ -1467,15 +1830,15 @@ |
3191 | break; |
3192 | } |
3193 | } |
3194 | - |
3195 | std::priority_queue<NearFlag> queue; |
3196 | std::vector<NearFlag> nearflags; |
3197 | - |
3198 | - queue.push (NearFlag(flag, 0, 0)); |
3199 | - Map & map = game().map(); |
3200 | + queue.push(NearFlag(flag, 0, 0)); |
3201 | + Map& map = game().map(); |
3202 | |
3203 | while (!queue.empty()) { |
3204 | - std::vector<NearFlag>::iterator f = find(nearflags.begin(), nearflags.end(), queue.top().flag); |
3205 | + std::vector<NearFlag>::iterator f = |
3206 | + find(nearflags.begin(), nearflags.end(), queue.top().flag); |
3207 | + |
3208 | if (f != nearflags.end()) { |
3209 | queue.pop(); |
3210 | continue; |
3211 | @@ -1483,46 +1846,40 @@ |
3212 | |
3213 | nearflags.push_back(queue.top()); |
3214 | queue.pop(); |
3215 | - |
3216 | - NearFlag & nf = nearflags.back(); |
3217 | + NearFlag& nf = nearflags.back(); |
3218 | |
3219 | for (uint8_t i = 1; i <= 6; ++i) { |
3220 | - Road * const road = nf.flag->get_road(i); |
3221 | + Road* const road = nf.flag->get_road(i); |
3222 | |
3223 | if (!road) |
3224 | continue; |
3225 | |
3226 | - Flag * endflag = &road->get_flag(Road::FlagStart); |
3227 | + Flag* endflag = &road->get_flag(Road::FlagStart); |
3228 | + |
3229 | if (endflag == nf.flag) |
3230 | endflag = &road->get_flag(Road::FlagEnd); |
3231 | |
3232 | int32_t dist = map.calc_distance(flag.get_position(), endflag->get_position()); |
3233 | - if (dist > 12) // out of range |
3234 | + |
3235 | + if (dist > 12) // out of range |
3236 | continue; |
3237 | |
3238 | - queue.push(NearFlag(*endflag, nf.cost + road->get_path().get_nsteps(), dist)); |
3239 | + queue.push(NearFlag(*endflag, nf.cost_ + road->get_path().get_nsteps(), dist)); |
3240 | } |
3241 | } |
3242 | |
3243 | - std::sort (nearflags.begin(), nearflags.end(), CompareDistance()); |
3244 | - |
3245 | + std::sort(nearflags.begin(), nearflags.end(), CompareDistance()); |
3246 | CheckStepRoadAI check(player, MOVECAPS_WALK, false); |
3247 | |
3248 | for (uint32_t i = 1; i < nearflags.size(); ++i) { |
3249 | - NearFlag & nf = nearflags.at(i); |
3250 | - |
3251 | - if (2 * nf.distance + 2 < nf.cost) { |
3252 | - |
3253 | - Path & path = *new Path(); |
3254 | - if |
3255 | - (map.findpath |
3256 | - (flag.get_position(), nf.flag->get_position(), 0, path, check) |
3257 | - >= |
3258 | - 0 |
3259 | - and |
3260 | - static_cast<int32_t>(2 * path.get_nsteps() + 2) < nf.cost) |
3261 | - { |
3262 | - game().send_player_build_road (player_number(), path); |
3263 | + NearFlag& nf = nearflags.at(i); |
3264 | + |
3265 | + if (2 * nf.distance_ + 2 < nf.cost_) { |
3266 | + Path& path = *new Path(); |
3267 | + |
3268 | + if (map.findpath(flag.get_position(), nf.flag->get_position(), 0, path, check) >= |
3269 | + 0 and static_cast<int32_t>(2 * path.get_nsteps() + 2) < nf.cost_) { |
3270 | + game().send_player_build_road(player_number(), path); |
3271 | return true; |
3272 | } |
3273 | |
3274 | @@ -1533,25 +1890,24 @@ |
3275 | return false; |
3276 | } |
3277 | |
3278 | - |
3279 | /** |
3280 | * Checks if anything in one of the economies changed and takes care for these |
3281 | * changes. |
3282 | * |
3283 | * \returns true, if something was changed. |
3284 | */ |
3285 | -bool DefaultAI::check_economies () |
3286 | -{ |
3287 | +bool DefaultAI::check_economies() { |
3288 | while (!new_flags.empty()) { |
3289 | - const Flag & flag = *new_flags.front(); |
3290 | + const Flag& flag = *new_flags.front(); |
3291 | new_flags.pop_front(); |
3292 | - get_economy_observer(flag.economy())->flags.push_back (&flag); |
3293 | + get_economy_observer(flag.economy())->flags.push_back(&flag); |
3294 | } |
3295 | |
3296 | - container_iterate(std::list<EconomyObserver *>, economies, i) { |
3297 | + container_iterate(std::list<EconomyObserver*>, economies, i) { |
3298 | // check if any flag has changed its economy |
3299 | - std::list<Flag const *> &fl = (*i.current)->flags; |
3300 | - for (std::list<Flag const *>::iterator j = fl.begin(); j != fl.end();) { |
3301 | + std::list<Flag const*>& fl = (*i.current)->flags; |
3302 | + |
3303 | + for (std::list<Flag const*>::iterator j = fl.begin(); j != fl.end();) { |
3304 | if (&(*i.current)->economy != &(*j)->economy()) { |
3305 | get_economy_observer((*j)->economy())->flags.push_back(*j); |
3306 | j = fl.erase(j); |
3307 | @@ -1576,44 +1932,111 @@ |
3308 | * |
3309 | * \returns true, if something was changed. |
3310 | */ |
3311 | -bool DefaultAI::check_productionsites(int32_t gametime) |
3312 | -{ |
3313 | - if ((next_productionsite_check_due > gametime) || productionsites.empty()) |
3314 | +bool DefaultAI::check_productionsites(int32_t gametime) { |
3315 | + if ((next_productionsite_check_due_ > gametime) || productionsites.empty()) |
3316 | return false; |
3317 | - next_productionsite_check_due = gametime + 1300; |
3318 | |
3319 | + next_productionsite_check_due_ = gametime + 5000; |
3320 | // Get link to productionsite that should be checked |
3321 | - ProductionSiteObserver & site = productionsites.front(); |
3322 | + ProductionSiteObserver& site = productionsites.front(); |
3323 | bool changed = false; |
3324 | - |
3325 | + // Reorder and set new values; - better now because there are multiple returns in the function |
3326 | + productionsites.push_back(productionsites.front()); |
3327 | + productionsites.pop_front(); |
3328 | // Get max radius of recursive workarea |
3329 | Workarea_Info::size_type radius = 0; |
3330 | - |
3331 | - const Workarea_Info & workarea_info = site.bo->desc->m_workarea_info; |
3332 | + const Workarea_Info& workarea_info = site.bo->desc->m_workarea_info; |
3333 | container_iterate_const(Workarea_Info, workarea_info, i) |
3334 | - if (radius < i.current->first) |
3335 | - radius = i.current->first; |
3336 | - |
3337 | - Map & map = game().map(); |
3338 | + |
3339 | + if (radius < i.current->first) |
3340 | + radius = i.current->first; |
3341 | + |
3342 | + Map& map = game().map(); |
3343 | + |
3344 | + // do not dismantle same type of building too soon - to give some time to update statistics |
3345 | + // yes it interferes with building updates, but not big problem here |
3346 | + if (site.bo->last_dismantle_time_ > game().get_gametime() - 30 * 1000) |
3347 | + return false; |
3348 | |
3349 | // Lumberjack / Woodcutter handling |
3350 | - if |
3351 | - (site.bo->need_trees |
3352 | - and |
3353 | - map.find_immovables |
3354 | - (Area<FCoords>(map.get_fcoords(site.site->get_position()), radius), |
3355 | - nullptr, |
3356 | - FindImmovableAttribute(Map_Object_Descr::get_attribute_id("tree"))) |
3357 | - == |
3358 | - 0) |
3359 | - { |
3360 | - if (site.site->get_statistics_percent() == 0) { |
3361 | + if (site.bo->need_trees_) { |
3362 | + if (map.find_immovables(Area<FCoords>(map.get_fcoords(site.site->get_position()), radius), |
3363 | + nullptr, |
3364 | + FindImmovableAttribute(Map_Object_Descr::get_attribute_id("tree"))) < |
3365 | + 6) { |
3366 | // Do not destruct the last lumberjack - perhaps some small trees are |
3367 | // near, a forester will plant some trees or some new trees will seed |
3368 | - // in reach. Computer players can easily run out of wood if this check |
3369 | + // in reach. Computer player_s can easily run out of wood if this check |
3370 | // is not done. |
3371 | - if (site.bo->cnt_built == 1) |
3372 | + if (site.bo->cnt_built_ <= |
3373 | + 3 + static_cast<int32_t>(mines_.size() + productionsites.size()) / 20) { |
3374 | + if (kWoodDebug) |
3375 | + printf( |
3376 | + " TDEBUG: %1d: cutter without trees, but not dismantling due to low numbers of " |
3377 | + "cutters (%2d)\n", |
3378 | + player_number(), |
3379 | + site.bo->cnt_built_); |
3380 | + |
3381 | return false; |
3382 | + } |
3383 | + |
3384 | + if (site.site->get_statistics_percent() <= 20) { |
3385 | + // destruct the building and it's flag (via flag destruction) |
3386 | + // the destruction of the flag avoids that defaultAI will have too many |
3387 | + // unused roads - if needed the road will be rebuild directly. |
3388 | + // printf (" TDEBUG: dismantling lumberjacks hut\n"); |
3389 | + site.bo->last_dismantle_time_ = game().get_gametime(); |
3390 | + flags_to_be_removed.push_back(site.site->base_flag().get_position()); |
3391 | + game().send_player_dismantle(*site.site); |
3392 | + |
3393 | + if (kWoodDebug) |
3394 | + printf(" TDEBUG %1d: cutter without trees, dismantling..., remaining cutters: %2d\n", |
3395 | + player_number(), |
3396 | + site.bo->cnt_built_); |
3397 | + |
3398 | + return true; |
3399 | + } |
3400 | + return false; |
3401 | + } |
3402 | + return false; |
3403 | + } |
3404 | + |
3405 | + // Wells handling |
3406 | + if (site.bo->mines_water_) { |
3407 | + if (site.built_time_ + 6 * 60 * 1000 < game().get_gametime() |
3408 | + and site.site->get_statistics_percent() == |
3409 | + 0) { |
3410 | + if (kWellDebug) |
3411 | + printf(" TDEBUG: dismantling Well, statistics: %3d,\n", |
3412 | + site.site->get_statistics_percent()); |
3413 | + site.bo->last_dismantle_time_ = game().get_gametime(); |
3414 | + flags_to_be_removed.push_back(site.site->base_flag().get_position()); |
3415 | + game().send_player_dismantle(*site.site); |
3416 | + |
3417 | + return true; |
3418 | + } |
3419 | + return false; |
3420 | + } |
3421 | + |
3422 | + // Quarry handling |
3423 | + if (site.bo->need_stones_) { |
3424 | + if (kQuarryDismDebug) { |
3425 | + printf(" QUARRY at %3d x %3d: statistics: %3d/%3d, age: %5d(>360s), stones:%3d\n", |
3426 | + site.site->get_position().x, |
3427 | + site.site->get_position().y, |
3428 | + site.site->get_statistics_percent(), |
3429 | + site.site->get_crude_statistics(), |
3430 | + (gametime - site.built_time_) / 1000, |
3431 | + map.find_immovables( |
3432 | + Area<FCoords>(map.get_fcoords(site.site->get_position()), radius), |
3433 | + nullptr, |
3434 | + FindImmovableAttribute(Map_Object_Descr::get_attribute_id("stone")))); |
3435 | + } |
3436 | + |
3437 | + if (map.find_immovables( |
3438 | + Area<FCoords>(map.get_fcoords(site.site->get_position()), radius), |
3439 | + nullptr, |
3440 | + FindImmovableAttribute(Map_Object_Descr::get_attribute_id("stone"))) == 0) { |
3441 | // destruct the building and it's flag (via flag destruction) |
3442 | // the destruction of the flag avoids that defaultAI will have too many |
3443 | // unused roads - if needed the road will be rebuild directly. |
3444 | @@ -1621,139 +2044,235 @@ |
3445 | game().send_player_dismantle(*site.site); |
3446 | return true; |
3447 | } |
3448 | - } |
3449 | - |
3450 | - // Quarry handling |
3451 | - if |
3452 | - (site.bo->need_stones |
3453 | - and |
3454 | - map.find_immovables |
3455 | - (Area<FCoords>(map.get_fcoords(site.site->get_position()), radius), |
3456 | - nullptr, |
3457 | - FindImmovableAttribute(Map_Object_Descr::get_attribute_id("stone"))) |
3458 | - == |
3459 | - 0) |
3460 | - { |
3461 | - // destruct the building and it's flag (via flag destruction) |
3462 | - // the destruction of the flag avoids that defaultAI will have too many |
3463 | - // unused roads - if needed the road will be rebuild directly. |
3464 | + |
3465 | + if (site.built_time_ + 6 * 60 * 1000 < game().get_gametime() |
3466 | + and site.site->get_statistics_percent() == |
3467 | + 0) { |
3468 | + // it is possible that there are stones but quary is not able to mine them |
3469 | + site.bo->last_dismantle_time_ = game().get_gametime(); |
3470 | + flags_to_be_removed.push_back(site.site->base_flag().get_position()); |
3471 | + game().send_player_dismantle(*site.site); |
3472 | + |
3473 | + return true; |
3474 | + } |
3475 | + |
3476 | + return false; |
3477 | + } |
3478 | + |
3479 | + // All other SPACE_CONSUMERS without input and above target_count |
3480 | + if (kSpaceDebug and site.bo->space_consumer_ and not site.bo->plants_trees_) |
3481 | + printf(" TDEBUG: space consumer here: %15s at %3d x %3d: statistics: %3d, age: %5d(>360s)\n", |
3482 | + site.bo->name, |
3483 | + site.site->get_position().x, |
3484 | + site.site->get_position().y, |
3485 | + site.site->get_statistics_percent(), |
3486 | + (gametime - site.built_time_) / 1000); |
3487 | + |
3488 | + if (site.bo->inputs_.empty() // does not consume anything |
3489 | + and site.bo->production_hint_ == |
3490 | + -1 // not a renewing building (forester...) |
3491 | + and site.built_time_ + |
3492 | + 6 * 60 * 1000 < |
3493 | + game().get_gametime() // > 10 minutes old |
3494 | + and site.site->can_start_working() // building is occupied |
3495 | + and site.bo->space_consumer_ and not site.bo->plants_trees_) { |
3496 | + if (site.bo->cnt_built_ > site.bo->cnt_target_) { |
3497 | + if (site.bo->stocklevel_time < game().get_gametime() - 5 * 1000) { |
3498 | + site.bo->stocklevel_ = get_stocklevel(*site.bo); |
3499 | + site.bo->stocklevel_time = game().get_gametime(); |
3500 | + } |
3501 | + |
3502 | + if (kSpaceDebug) |
3503 | + printf(" TDEBUG: considering dismantle of space consumer: %15s, count %2d/T:%2d, stock " |
3504 | + "level:%3d(>100)\n", |
3505 | + site.bo->name, |
3506 | + site.bo->cnt_built_, |
3507 | + site.bo->cnt_target_, |
3508 | + site.bo->stocklevel_); |
3509 | + |
3510 | + if (site.site->get_statistics_percent()< |
3511 | + 95 and site.bo->stocklevel_> 100) { // production stats == 0% |
3512 | + site.bo->last_dismantle_time_ = game().get_gametime(); |
3513 | + flags_to_be_removed.push_back(site.site->base_flag().get_position()); |
3514 | + game().send_player_dismantle(*site.site); |
3515 | + return true; |
3516 | + } |
3517 | + } |
3518 | + |
3519 | + if (site.site->get_statistics_percent() <= 20) { |
3520 | + if (kSpaceDebug) |
3521 | + printf(" TDEBUG: dismantling: %15s at %3d x %3d: due to low performance: %2d\n", |
3522 | + site.bo->name, |
3523 | + site.site->get_position().x, |
3524 | + site.site->get_position().y, |
3525 | + site.site->get_statistics_percent()); |
3526 | + |
3527 | + flags_to_be_removed.push_back(site.site->base_flag().get_position()); |
3528 | + game().send_player_dismantle(*site.site); |
3529 | + return true; |
3530 | + } |
3531 | + |
3532 | + return false; |
3533 | + } |
3534 | + |
3535 | + // buildings with inputs_, checking if we can a dismantle some due to low performance |
3536 | + if (site.bo->inputs_.size() > 0 and site.bo->cnt_built_ >= 3 and site.bo->current_stats_ < 30) { |
3537 | + if (kIdleDismantle) |
3538 | + printf(" kIdleDismantle: dismantling due to too many buildings: %15s at %3d x %3d, total " |
3539 | + "counts: %2d, stat: %2d\n", |
3540 | + site.bo->name, |
3541 | + site.site->get_position().x, |
3542 | + site.site->get_position().y, |
3543 | + site.bo->cnt_built_, |
3544 | + site.bo->current_stats_); |
3545 | + site.bo->last_dismantle_time_ = game().get_gametime(); |
3546 | flags_to_be_removed.push_back(site.site->base_flag().get_position()); |
3547 | game().send_player_dismantle(*site.site); |
3548 | return true; |
3549 | } |
3550 | |
3551 | - // All other productionsites without input... |
3552 | - if |
3553 | - (site.bo->inputs.empty() // does not consume anything |
3554 | - and |
3555 | - site.bo->production_hint == -1 // not a renewing building (forester...) |
3556 | - and |
3557 | - site.builttime + 600000 < game().get_gametime() // > 10 minutes old |
3558 | - and |
3559 | - site.site->can_start_working()) // building is occupied |
3560 | - { |
3561 | - if (site.site->get_statistics_percent() == 0) { // production stats == 0% |
3562 | - ++site.statszero; |
3563 | - // Only continue here, if at least 3 following times, the stats were 0% |
3564 | - if (site.statszero >= 3) { |
3565 | - // Do not destruct building, if it's basic and the last of this |
3566 | - // type left. |
3567 | - if (site.bo->is_basic && site.bo->cnt_built <= 1) |
3568 | - return false; |
3569 | - |
3570 | - // If building seems to be useless, think about destructing it and |
3571 | - // it's flag (via flag destruction) more or less randomly. The |
3572 | - // destruction of the flag avoids that defaultAI will have too many |
3573 | - // unused roads - if needed the road will be rebuild directly. |
3574 | - // |
3575 | - // Add a bonus if one building of this type is still unoccupied |
3576 | - if (((game().get_gametime() % 4) + site.bo->unoccupied) > 2) { |
3577 | - flags_to_be_removed.push_back(site.site->base_flag().get_position()); |
3578 | - game().send_player_dismantle(*site.site); |
3579 | - return true; |
3580 | - } |
3581 | - else |
3582 | - return false; |
3583 | - } |
3584 | - return false; |
3585 | - } else |
3586 | - site.statszero = 0; // reset zero counter |
3587 | + // supporting productionsites (rangers) |
3588 | + // stop/start them based on stock avaiable |
3589 | + if (site.bo->production_hint_ >= 0) { |
3590 | + // if (kStandbyDebug) printf (" TDEBUG: check_productionsites(): testing building |
3591 | + // %s\n",site.bo->name); |
3592 | + if (site.bo->stocklevel_time < game().get_gametime() - 5 * 1000) { |
3593 | + site.bo->stocklevel_ = get_stocklevel_by_hint(site.bo->production_hint_); |
3594 | + site.bo->stocklevel_time = game().get_gametime(); |
3595 | + } |
3596 | + |
3597 | + if (kStandbyDebug) |
3598 | + printf(" TDEBUG: standby review: %-16s(%dx):stock level: %3d, status: %s\n", |
3599 | + site.bo->name, |
3600 | + site.bo->cnt_built_, |
3601 | + site.bo->stocklevel_, |
3602 | + site.site->is_stopped() ? "stopped" : "running"); |
3603 | + |
3604 | + if (site.bo->stocklevel_ > 200 and site.bo->cnt_built_ > site.bo->cnt_target_) { |
3605 | + if (kStandbyDebug) |
3606 | + printf(" * dismantling the building\n"); |
3607 | + |
3608 | + site.bo->last_dismantle_time_ = game().get_gametime(); |
3609 | + flags_to_be_removed.push_back(site.site->base_flag().get_position()); |
3610 | + game().send_player_dismantle(*site.site); |
3611 | + return true; |
3612 | + } |
3613 | + |
3614 | + if (site.bo->stocklevel_ > 150 and not site.site->is_stopped()) { |
3615 | + if (kStandbyDebug) |
3616 | + printf(" * stopping building\n"); |
3617 | + |
3618 | + game().send_player_start_stop_building(*site.site); |
3619 | + } |
3620 | + |
3621 | + if (site.bo->stocklevel_ < 100 and site.site->is_stopped()) { |
3622 | + if (kStandbyDebug) |
3623 | + printf(" * starting building\n"); |
3624 | + |
3625 | + game().send_player_start_stop_building(*site.site); |
3626 | + } |
3627 | } |
3628 | |
3629 | - // Do not have too many constructionsites |
3630 | - uint32_t producers = mines.size() + productionsites.size(); |
3631 | - if (total_constructionsites >= (5 + (producers / 10))) |
3632 | + // Upgrading policy |
3633 | + // a) if there are two buildings and none enhanced, one is enhanced |
3634 | + // b) if there are two buildings and at least one functional |
3635 | + // statistics percents are decisive |
3636 | + |
3637 | + // do not upgrade if current building is only one in operation |
3638 | + if ((site.bo->cnt_built_ - site.bo->unoccupied_) <= 1) |
3639 | return false; |
3640 | |
3641 | // Check whether building is enhanceable and if wares of the enhanced |
3642 | // buildings are needed. If yes consider an upgrade. |
3643 | std::set<Building_Index> enhancements = site.site->enhancements(); |
3644 | int32_t maxprio = 0; |
3645 | - Building_Index enbld; |
3646 | + Building_Index enbld; // to get rid of this |
3647 | + BuildingObserver* bestbld = nullptr; |
3648 | container_iterate_const(std::set<Building_Index>, enhancements, x) { |
3649 | // Only enhance buildings that are allowed (scenario mode) |
3650 | if (player->is_building_type_allowed(*x.current)) { |
3651 | - const Building_Descr & bld = *tribe->get_building_descr(*x.current); |
3652 | - BuildingObserver & en_bo = get_building_observer(bld.name().c_str()); |
3653 | + const Building_Descr& bld = *tribe->get_building_descr(*x.current); |
3654 | + BuildingObserver& en_bo = get_building_observer(bld.name().c_str()); |
3655 | + |
3656 | + // do not build the same building so soon (kind of duplicity check) |
3657 | + if (gametime - en_bo.construction_decision_time_ < kBuildingMinInterval) |
3658 | + continue; |
3659 | |
3660 | // Don't enhance this building, if there is already one of same type |
3661 | - // under construction |
3662 | - if (en_bo.cnt_under_construction > 0) |
3663 | + // under construction or unoccupied_ |
3664 | + if (en_bo.cnt_under_construction_ + en_bo.unoccupied_ > 0) |
3665 | continue; |
3666 | |
3667 | // don't upgrade without workers |
3668 | if (!site.site->has_workers(*x.current, game())) |
3669 | continue; |
3670 | |
3671 | - int32_t prio = 0; // priority for enhancement |
3672 | - |
3673 | - // Find new outputs of enhanced building |
3674 | - std::vector<int16_t> & current_outputs = site.bo->outputs; |
3675 | - std::vector<int16_t> new_outputs; |
3676 | - for (uint16_t i = 0; i < en_bo.outputs.size(); ++i) { |
3677 | - for (uint16_t j = 0; j < current_outputs.size(); ++j) |
3678 | - if (current_outputs.at(j) == en_bo.outputs.at(i)) { |
3679 | - Ware_Index wt(static_cast<size_t>(current_outputs.at(j))); |
3680 | - if (site.site->economy().needs_ware(wt)) |
3681 | - prio -= |
3682 | - (2 + wares.at(current_outputs.at(j)).preciousness) / 2; |
3683 | - continue; |
3684 | - } |
3685 | - new_outputs.push_back(static_cast<int16_t>(i)); |
3686 | - } |
3687 | - |
3688 | - // Check if the new wares are needed in economy of the building |
3689 | - for (uint32_t i = 0; i < new_outputs.size(); ++i) { |
3690 | - Ware_Index wt(static_cast<size_t>(new_outputs.at(i))); |
3691 | - if (site.site->economy().needs_ware(wt)) |
3692 | - prio += 2 + wares.at(new_outputs.at(i)).preciousness; |
3693 | - } |
3694 | - |
3695 | - // Compare the number of buildings of current type with the number |
3696 | - // of buildings of enhanced type |
3697 | - prio += (site.bo->total_count() - en_bo.total_count()) * 2; |
3698 | - |
3699 | - // If the new wares are needed |
3700 | - if (prio > 0) { |
3701 | - prio = calculate_need_for_ps(en_bo, prio); |
3702 | - if (prio > maxprio) { |
3703 | - maxprio = prio; |
3704 | - enbld = (*x.current); |
3705 | - } |
3706 | + // forcing first upgrade |
3707 | + if ((en_bo.cnt_under_construction_ + en_bo.cnt_built_ + en_bo.unoccupied_) == |
3708 | + 0 and(site.bo->cnt_built_ - site.bo->unoccupied_) >= |
3709 | + 1 and(game().get_gametime() - site.built_time_) > 30 * 60 * 1000 and mines_.size() > |
3710 | + 0) { |
3711 | + if (kUpgradeDebug) |
3712 | + printf(" UPGRADE: upgrading (forcing as first) %12s at %3d x %3d: age %d min.\n", |
3713 | + site.bo->name, |
3714 | + site.site->get_position().x, |
3715 | + site.site->get_position().y, |
3716 | + (game().get_gametime() - site.built_time_) / 60000); |
3717 | + |
3718 | + game().send_player_enhance_building(*site.site, (*x.current)); |
3719 | + return true; |
3720 | + } |
3721 | + |
3722 | + // now, let consider normal upgrade |
3723 | + |
3724 | + if (kUpgradeDebug) |
3725 | + printf(" UPGRADE: %1d: working enhanced buildings (%15s): %1d, statitistics: %2d\n", |
3726 | + player_number(), |
3727 | + en_bo.name, |
3728 | + en_bo.cnt_built_ - en_bo.unoccupied_, |
3729 | + en_bo.current_stats_); |
3730 | + |
3731 | + // do not upgrade if candidate production % is too low |
3732 | + if ((en_bo.cnt_built_ - en_bo.unoccupied_) == |
3733 | + 0 or(en_bo.cnt_under_construction_ + en_bo.unoccupied_) > 0 or en_bo.current_stats_ < |
3734 | + 50) |
3735 | + continue; |
3736 | + |
3737 | + int32_t prio = 0; |
3738 | + |
3739 | + if (en_bo.current_stats_ > 65) { |
3740 | + prio = en_bo.current_stats_ - site.bo->current_stats_; // priority for enhancement |
3741 | + prio += en_bo.current_stats_ - 65; |
3742 | + |
3743 | + if (kUpgradeDebug) |
3744 | + printf(" UPGRADE: proposing upgrade (non-first building) %12s at %3d x %3d: prio: " |
3745 | + "%2d, target statistics: %2d\n", |
3746 | + site.bo->name, |
3747 | + site.site->get_position().x, |
3748 | + site.site->get_position().y, |
3749 | + prio, |
3750 | + en_bo.current_stats_); |
3751 | + } |
3752 | + |
3753 | + if (prio > maxprio) { |
3754 | + maxprio = prio; |
3755 | + enbld = (*x.current); |
3756 | + bestbld = &en_bo; |
3757 | } |
3758 | } |
3759 | } |
3760 | |
3761 | // Enhance if enhanced building is useful |
3762 | // additional: we dont want to lose the old building |
3763 | - if (maxprio > 0 && site.bo->total_count() > 1) { |
3764 | + if (maxprio > 0) { |
3765 | + if (kUpgradeDebug) |
3766 | + printf(" UPGRADE: upgrading %15s(as non first)\n", bestbld->name); |
3767 | + |
3768 | game().send_player_enhance_building(*site.site, enbld); |
3769 | + bestbld->construction_decision_time_ = gametime; |
3770 | changed = true; |
3771 | } |
3772 | |
3773 | - // Reorder and set new values; |
3774 | - productionsites.push_back(productionsites.front()); |
3775 | - productionsites.pop_front(); |
3776 | return changed; |
3777 | } |
3778 | |
3779 | @@ -1763,30 +2282,48 @@ |
3780 | * |
3781 | * \returns true, if something was changed. |
3782 | */ |
3783 | -bool DefaultAI::check_mines(int32_t const gametime) |
3784 | -{ |
3785 | - if ((next_mine_check_due > gametime) || mines.empty()) |
3786 | +bool DefaultAI::check_mines_(int32_t const gametime) { |
3787 | + if ((next_mine_check_due_ > gametime) || mines_.empty()) |
3788 | return false; |
3789 | - next_mine_check_due = gametime + 1000; |
3790 | |
3791 | + next_mine_check_due_ = gametime + 10000; // 10 seconds is enough |
3792 | + // also statistics must be recalculated |
3793 | // Get link to productionsite that should be checked |
3794 | - ProductionSiteObserver & site = mines.front(); |
3795 | - Map & map = game().map(); |
3796 | - Field * field = map.get_fcoords(site.site->get_position()).field; |
3797 | - |
3798 | - // Don't try to enhance as long as stats are not down to 0% - it is possible, |
3799 | - // that some neighbour fields still have resources |
3800 | - if (site.site->get_statistics_percent() > 0) |
3801 | + ProductionSiteObserver& site = mines_.front(); |
3802 | + Map& map = game().map(); |
3803 | + Field* field = map.get_fcoords(site.site->get_position()).field; |
3804 | + // Reorder and set new values; - due to returns within the function |
3805 | + mines_.push_back(mines_.front()); |
3806 | + mines_.pop_front(); |
3807 | + |
3808 | + if (kMinesUpdateDebug) |
3809 | + printf( |
3810 | + " MINES_UPDATE: %1d: reviewing %-15s at %3dx%3d, statistics: %3d, left resources: %2d\n", |
3811 | + player_number(), |
3812 | + site.bo->name, |
3813 | + site.site->get_position().x, |
3814 | + site.site->get_position().y, |
3815 | + site.site->get_statistics_percent(), |
3816 | + field->get_resources_amount()); |
3817 | + |
3818 | + // It takes some time till performance gets to 0 |
3819 | + // so I use 40% as a limit to check if there are some resources left |
3820 | + if (site.site->get_statistics_percent() > 40) |
3821 | return false; |
3822 | |
3823 | // Check if mine ran out of resources |
3824 | uint8_t current = field->get_resources_amount(); |
3825 | + |
3826 | if (current < 1) { |
3827 | // destruct the building and it's flag (via flag destruction) |
3828 | // the destruction of the flag avoids that defaultAI will have too many |
3829 | // unused roads - if needed the road will be rebuild directly. |
3830 | flags_to_be_removed.push_back(site.site->base_flag().get_position()); |
3831 | game().send_player_dismantle(*site.site); |
3832 | + |
3833 | + if (kMinesUpdateDebug) |
3834 | + printf(" MINES_UPDATE: Dismantling...\n"); |
3835 | + |
3836 | return true; |
3837 | } |
3838 | |
3839 | @@ -1794,23 +2331,54 @@ |
3840 | std::set<Building_Index> enhancements = site.site->enhancements(); |
3841 | int32_t maxprio = 0; |
3842 | Building_Index enbld; |
3843 | + BuildingObserver* bestbld = nullptr; |
3844 | bool changed = false; |
3845 | container_iterate_const(std::set<Building_Index>, enhancements, x) { |
3846 | // Only enhance buildings that are allowed (scenario mode) |
3847 | if (player->is_building_type_allowed(*x.current)) { |
3848 | + // first exclude possibility there are enhancements in construction or unoccupied_ |
3849 | + const Building_Descr& bld = *tribe->get_building_descr(*x.current); |
3850 | + BuildingObserver& en_bo = get_building_observer(bld.name().c_str()); |
3851 | + |
3852 | + if (kMinesUpdateDebug) |
3853 | + printf(" MINES_UPDATE: considering upgrade to %15s, count B:%1d(stat:%3d) U:%1d " |
3854 | + "C:%1d\n", |
3855 | + en_bo.name, |
3856 | + en_bo.cnt_built_, |
3857 | + en_bo.current_stats_, |
3858 | + en_bo.unoccupied_, |
3859 | + en_bo.cnt_under_construction_); |
3860 | + |
3861 | + if (en_bo.unoccupied_ + en_bo.cnt_under_construction_ > 0) |
3862 | + continue; |
3863 | + |
3864 | + // do not upgrade target building are not working properly (probably do not have food) |
3865 | + if (en_bo.cnt_built_ > 0 and en_bo.current_stats_ < 60) |
3866 | + continue; |
3867 | + |
3868 | + // do not build the same building so soon (kind of duplicity check) |
3869 | + if (gametime - en_bo.construction_decision_time_ < kBuildingMinInterval) |
3870 | + continue; |
3871 | |
3872 | // Check if mine needs an enhancement to mine more resources |
3873 | uint8_t const until = |
3874 | - field->get_starting_res_amount() * (100 - site.bo->mines_percent) |
3875 | - / |
3876 | - 100; |
3877 | + field->get_starting_res_amount() * (100 - site.bo->mines_percent_) / 100; |
3878 | + |
3879 | + if (kMinesUpdateDebug) |
3880 | + printf(" MINES_UPDATE: until:%3d ?>, current: %3d\n", until, current); |
3881 | + |
3882 | if (until >= current) { |
3883 | // add some randomness - just for the case if more than one |
3884 | // enhancement is available (not in any tribe yet) |
3885 | int32_t const prio = time(nullptr) % 3 + 1; |
3886 | + |
3887 | if (prio > maxprio) { |
3888 | maxprio = prio; |
3889 | enbld = (*x.current); |
3890 | + bestbld = &en_bo; |
3891 | + |
3892 | + if (kMinesUpdateDebug) |
3893 | + printf(" MINES_UPDATE: ..is candidate\n"); |
3894 | } |
3895 | } |
3896 | } |
3897 | @@ -1819,15 +2387,66 @@ |
3898 | // Enhance if enhanced building is useful |
3899 | if (maxprio > 0) { |
3900 | game().send_player_enhance_building(*site.site, enbld); |
3901 | + bestbld->construction_decision_time_ = gametime; |
3902 | changed = true; |
3903 | + |
3904 | + if (kMinesUpdateDebug) |
3905 | + printf(" MINES_UPDATE: ..enhancing\n"); |
3906 | } |
3907 | |
3908 | - // Reorder and set new values; |
3909 | - mines.push_back(mines.front()); |
3910 | - mines.pop_front(); |
3911 | + //// Reorder and set new values; |
3912 | + // mines_.push_back(mines_.front()); |
3913 | + // mines_.pop_front(); |
3914 | return changed; |
3915 | } |
3916 | |
3917 | +// this count ware as hints |
3918 | +uint32_t DefaultAI::get_stocklevel_by_hint(size_t hintoutput) { |
3919 | + uint32_t count = 0; |
3920 | + Ware_Index wt(hintoutput); |
3921 | + container_iterate(std::list<EconomyObserver*>, economies, l) { |
3922 | + // Don't check if the economy has no warehouse. |
3923 | + if ((*l.current)->economy.warehouses().empty()) |
3924 | + continue; |
3925 | + |
3926 | + count += (*l.current)->economy.stock_ware(wt); |
3927 | + } |
3928 | + |
3929 | + if (kStockDebug) |
3930 | + printf(" TDEBUG: stock : %3d for hint: %2d, time: %3d\n", |
3931 | + count, |
3932 | + hintoutput, |
3933 | + game().get_gametime() / 1000); |
3934 | + |
3935 | + return count; |
3936 | +} |
3937 | + |
3938 | +// this count all stock for all output |
3939 | +uint32_t DefaultAI::get_stocklevel(BuildingObserver& bo) { |
3940 | + uint32_t count = 0; |
3941 | + |
3942 | + if (bo.outputs_.size() > 0) { |
3943 | + container_iterate(std::list<EconomyObserver*>, economies, l) { |
3944 | + // Don't check if the economy has no warehouse. |
3945 | + if ((*l.current)->economy.warehouses().empty()) |
3946 | + continue; |
3947 | + |
3948 | + for (uint32_t m = 0; m < bo.outputs_.size(); ++m) { |
3949 | + Ware_Index wt(static_cast<size_t>(bo.outputs_.at(m))); |
3950 | + count += (*l.current)->economy.stock_ware(wt); |
3951 | + } |
3952 | + } |
3953 | + } |
3954 | + |
3955 | + if (kStockDebug) |
3956 | + printf(" TDEBUG: stock : %3d for building: %s, time: %3d\n", |
3957 | + count, |
3958 | + bo.name, |
3959 | + game().get_gametime() / 1000); |
3960 | + |
3961 | + return count; |
3962 | +} |
3963 | + |
3964 | /** |
3965 | * Updates the first military building in list and reenques it at the end of |
3966 | * the list afterwards. If a militarysite is in secure area but holds more than |
3967 | @@ -1836,39 +2455,58 @@ |
3968 | * |
3969 | * \returns true if something was changed |
3970 | */ |
3971 | -bool DefaultAI::check_militarysites(int32_t gametime) |
3972 | -{ |
3973 | - if (next_militarysite_check_due > gametime) |
3974 | +bool DefaultAI::check_militarysites(int32_t gametime) { |
3975 | + if (next_militarysite_check_due_ > gametime) |
3976 | return false; |
3977 | |
3978 | + // just to be sure the value is reset |
3979 | + next_militarysite_check_due_ = gametime + 5 * 1000; // 10 seconds is really fine |
3980 | + // even if there are no finished & attended military sites, probably there are ones just in |
3981 | + // construction |
3982 | + unstationed_milit_buildings_ = 0; |
3983 | + |
3984 | + for (std::list<MilitarySiteObserver>::iterator it = militarysites.begin(); |
3985 | + it != militarysites.end(); |
3986 | + ++it) |
3987 | + if (it->site->stationedSoldiers().size() == 0) |
3988 | + unstationed_milit_buildings_ += 1; |
3989 | + |
3990 | + // count militarysites in construction |
3991 | + military_under_constr_ = 0; |
3992 | + |
3993 | + for (uint32_t j = 0; j < buildings.size(); ++j) { |
3994 | + BuildingObserver& bo = buildings.at(j); |
3995 | + |
3996 | + if (bo.type == BuildingObserver::MILITARYSITE) |
3997 | + military_under_constr_ += bo.cnt_under_construction_; |
3998 | + } |
3999 | + |
4000 | // Only useable, if defaultAI owns at least one militarysite |
4001 | if (militarysites.empty()) |
4002 | return false; |
4003 | |
4004 | // Check next militarysite |
4005 | bool changed = false; |
4006 | - Map & map = game().map(); |
4007 | - MilitarySite * ms = militarysites.front().site; |
4008 | + Map& map = game().map(); |
4009 | + MilitarySite* ms = militarysites.front().site; |
4010 | uint32_t const vision = ms->vision_range(); |
4011 | FCoords f = map.get_fcoords(ms->get_position()); |
4012 | - |
4013 | // look if there is any enemy land nearby |
4014 | - FindNodeUnowned find_unowned(player, game(), true); |
4015 | + FindNodeEnemy find_enemy(player, game()); |
4016 | |
4017 | - if (map.find_fields(Area<FCoords>(f, vision), nullptr, find_unowned) == 0) { |
4018 | + // first if there are enemies nearby |
4019 | + if (map.find_fields(Area<FCoords>(f, vision), nullptr, find_enemy) == 0) { |
4020 | // If no enemy in sight - decrease the number of stationed soldiers |
4021 | // as long as it is > 1 - BUT take care that there is a warehouse in the |
4022 | // same economy where the thrown out soldiers can go to. |
4023 | if (ms->economy().warehouses().size()) { |
4024 | uint32_t const j = ms->soldierCapacity(); |
4025 | - if (MilitarySite::kPrefersRookies != ms->get_soldier_preference()) |
4026 | - { |
4027 | - game().send_player_militarysite_set_soldier_preference(*ms, MilitarySite::kPrefersRookies); |
4028 | - } |
4029 | - else |
4030 | - if (j > 1) |
4031 | + |
4032 | + if (MilitarySite::kPrefersRookies != ms->get_soldier_preference()) { |
4033 | + game().send_player_militarysite_set_soldier_preference( |
4034 | + *ms, MilitarySite::kPrefersRookies); |
4035 | + } else if (j > 1) |
4036 | game().send_player_change_soldier_capacity(*ms, -1); |
4037 | - |
4038 | // if the building is in inner land and other militarysites still |
4039 | // hold the miliary influence of the field, consider to destruct the |
4040 | // building to free some building space. |
4041 | @@ -1876,65 +2514,36 @@ |
4042 | // treat this field like a buildable and write military info to it. |
4043 | BuildableField bf(f); |
4044 | update_buildable_field(bf, vision, true); |
4045 | - |
4046 | - // watch out if there is any unowned land in vision range. If there |
4047 | - // is none, there must be another building nearer to the frontier. |
4048 | - if (bf.unowned_land_nearby == 0) { |
4049 | - // bigger buildings are only checked after all smaller |
4050 | - // ones are at least one time checked. |
4051 | - if (militarysites.front().checks == 0) { |
4052 | - // If the military influence of other near buildings is higher |
4053 | - // than the own doubled max SoldierCapacity destruct the |
4054 | - // building and it's flag (via flag destruction) |
4055 | - // the destruction of the flag avoids that defaultAI will have |
4056 | - // too many unused roads - if needed the road will be rebuild |
4057 | - // directly. |
4058 | - if (static_cast<int32_t>(ms->maxSoldierCapacity() * 4) < bf.military_influence) { |
4059 | - if (ms->get_playercaps() & Widelands::Building::PCap_Dismantle) { |
4060 | - flags_to_be_removed.push_back(ms->base_flag().get_position()); |
4061 | - game().send_player_dismantle(*ms); |
4062 | - } else { |
4063 | - game().send_player_bulldoze(*ms); |
4064 | - } |
4065 | - } |
4066 | - |
4067 | - // Else consider enhancing the building (if possible) |
4068 | - else { |
4069 | - // Do not have too many constructionsites |
4070 | - uint32_t producers = mines.size() + productionsites.size(); |
4071 | - if (total_constructionsites >= (5 + (producers / 10))) |
4072 | - goto reorder; |
4073 | - std::set<Building_Index> enhancements = ms->enhancements(); |
4074 | - int32_t maxprio = 10000; // surely never reached |
4075 | - Building_Index enbld; |
4076 | - container_iterate_const |
4077 | - (std::set<Building_Index>, enhancements, x) |
4078 | - { |
4079 | - // Only enhance building to allowed (scenario mode) |
4080 | - if (player->is_building_type_allowed(*x.current)) { |
4081 | - const Building_Descr & bld = |
4082 | - *tribe->get_building_descr(*x.current); |
4083 | - BuildingObserver & en_bo = |
4084 | - get_building_observer(bld.name().c_str()); |
4085 | - |
4086 | - // Don't enhance this building, if there is |
4087 | - // already one of same type under construction |
4088 | - if (en_bo.cnt_under_construction > 0) |
4089 | - continue; |
4090 | - if (en_bo.cnt_built < maxprio) { |
4091 | - maxprio = en_bo.cnt_built; |
4092 | - enbld = (*x.current); |
4093 | - } |
4094 | - } |
4095 | - } |
4096 | - // Enhance if enhanced building is useful |
4097 | - if (maxprio < 10000) { |
4098 | - game().send_player_enhance_building(*ms, enbld); |
4099 | - changed = true; |
4100 | - } |
4101 | - } |
4102 | - } else |
4103 | - --militarysites.front().checks; |
4104 | + const int32_t size_penalty = ms->get_size() - 1; |
4105 | + |
4106 | + if (kMilDismDebug) |
4107 | + printf(" DISMANTLE CHECK: testing finished building %3dx%3d, capacity: %2d(>9), " |
4108 | + "presence: %2d(>3), loneliness: %4d(<160), stationed: %1d(>2+%d as size " |
4109 | + "penalty)\n", |
4110 | + f.x, |
4111 | + f.y, |
4112 | + bf.military_capacity_, |
4113 | + bf.military_presence_, |
4114 | + bf.military_loneliness_, |
4115 | + bf.military_stationed_, |
4116 | + size_penalty); |
4117 | + |
4118 | + if (bf.military_capacity_ > 9 and bf.military_presence_ > |
4119 | + 3 and bf.military_loneliness_<160 and bf.military_stationed_>(2 + size_penalty)) { |
4120 | + if (kMilDismDebug) |
4121 | + printf( |
4122 | + " DISMANTLE CHECK: * dismantling the building on %5d, last dismantle: %5d\n", |
4123 | + game().get_gametime() / 1000, |
4124 | + military_last_dismantle_ / 1000); |
4125 | + |
4126 | + if (ms->get_playercaps() & Widelands::Building::PCap_Dismantle) { |
4127 | + flags_to_be_removed.push_back(ms->base_flag().get_position()); |
4128 | + game().send_player_dismantle(*ms); |
4129 | + military_last_dismantle_ = game().get_gametime(); |
4130 | + } else { |
4131 | + game().send_player_bulldoze(*ms); |
4132 | + military_last_dismantle_ = game().get_gametime(); |
4133 | + } |
4134 | } |
4135 | } |
4136 | } |
4137 | @@ -1943,20 +2552,23 @@ |
4138 | // at maximum - set it to maximum. |
4139 | uint32_t const j = ms->maxSoldierCapacity(); |
4140 | uint32_t const k = ms->soldierCapacity(); |
4141 | + |
4142 | if (j > k) |
4143 | game().send_player_change_soldier_capacity(*ms, j - k); |
4144 | + |
4145 | if (MilitarySite::kPrefersHeroes != ms->get_soldier_preference()) |
4146 | game().send_player_militarysite_set_soldier_preference(*ms, MilitarySite::kPrefersHeroes); |
4147 | + |
4148 | changed = true; |
4149 | } |
4150 | - reorder:; |
4151 | + |
4152 | + // reorder:; |
4153 | militarysites.push_back(militarysites.front()); |
4154 | militarysites.pop_front(); |
4155 | - next_militarysite_check_due = gametime + 1000; |
4156 | + next_militarysite_check_due_ = gametime + 5 * 1000; // 10 seconds is really fine |
4157 | return changed; |
4158 | } |
4159 | |
4160 | - |
4161 | /** |
4162 | * This function takes care about the unowned and opposing territory and |
4163 | * recalculates the priority for none military buildings depending on the |
4164 | @@ -1967,31 +2579,30 @@ |
4165 | * |
4166 | * \returns the recalculated priority |
4167 | */ |
4168 | -int32_t DefaultAI::recalc_with_border_range(const BuildableField & bf, int32_t prio) |
4169 | -{ |
4170 | +int32_t DefaultAI::recalc_with_border_range(const BuildableField& bf, int32_t prio) { |
4171 | // Prefer building space in the inner land. |
4172 | - prio /= (1 + (bf.unowned_land_nearby / 4)); |
4173 | + prio /= (1 + (bf.unowned_land_nearby_ / 4)); |
4174 | + |
4175 | + if (bf.unowned_land_nearby_ > 15) |
4176 | + prio -= (bf.unowned_land_nearby_ - 15); |
4177 | |
4178 | // Especially places near the frontier to the enemies are unlikely |
4179 | - // NOTE take care about the type of computer player. The more |
4180 | - // NOTE aggressive a computer player is, the more important is |
4181 | + // NOTE take care about the type of computer player_. The more |
4182 | + // NOTE aggressive a computer player_ is, the more important is |
4183 | // NOTE this check. So we add \var type as bonus. |
4184 | - if (bf.enemy_nearby) |
4185 | + if (bf.enemy_nearby_ and prio > 0) |
4186 | prio /= (3 + type); |
4187 | |
4188 | return prio; |
4189 | } |
4190 | |
4191 | - |
4192 | - |
4193 | /** |
4194 | * calculates how much a productionsite of type \arg bo is needed inside it's |
4195 | * economy. \arg prio is initial value for this calculation |
4196 | * |
4197 | * \returns the calculated priority |
4198 | */ |
4199 | -int32_t DefaultAI::calculate_need_for_ps(BuildingObserver & bo, int32_t prio) |
4200 | -{ |
4201 | +int32_t DefaultAI::calculate_need_for_ps(BuildingObserver& bo, int32_t prio) { |
4202 | // some randomness to avoid that defaultAI is building always |
4203 | // the same (always == another game but same map with |
4204 | // defaultAI on same coords) |
4205 | @@ -1999,77 +2610,73 @@ |
4206 | |
4207 | // check if current economy can supply enough material for |
4208 | // production. |
4209 | - for (uint32_t k = 0; k < bo.inputs.size(); ++k) { |
4210 | - prio += 2 * wares.at(bo.inputs.at(k)).producers; |
4211 | - prio -= wares.at(bo.inputs.at(k)).consumers; |
4212 | + for (uint32_t k = 0; k < bo.inputs_.size(); ++k) { |
4213 | + prio += 2 * wares.at(bo.inputs_.at(k)).producers_; |
4214 | + prio -= wares.at(bo.inputs_.at(k)).consumers_; |
4215 | } |
4216 | - if (bo.inputs.empty()) |
4217 | + |
4218 | + if (bo.inputs_.empty()) |
4219 | prio += 4; |
4220 | |
4221 | int32_t output_prio = 0; |
4222 | - for (uint32_t k = 0; k < bo.outputs.size(); ++k) { |
4223 | - WareObserver & wo = wares.at(bo.outputs.at(k)); |
4224 | - if (wo.consumers > 0) { |
4225 | - output_prio += wo.preciousness; |
4226 | - output_prio += wo.consumers * 2; |
4227 | - output_prio -= wo.producers * 2; |
4228 | + |
4229 | + for (uint32_t k = 0; k < bo.outputs_.size(); ++k) { |
4230 | + WareObserver& wo = wares.at(bo.outputs_.at(k)); |
4231 | + |
4232 | + if (wo.consumers_ > 0) { |
4233 | + output_prio += wo.preciousness_; |
4234 | + output_prio += wo.consumers_ * 2; |
4235 | + output_prio -= wo.producers_ * 2; |
4236 | + |
4237 | if (bo.total_count() == 0) |
4238 | - output_prio += 10; // add a big bonus |
4239 | + output_prio += 10; // add a big bonus |
4240 | } |
4241 | } |
4242 | - if (bo.outputs.size() > 1) |
4243 | - output_prio = static_cast<int32_t> |
4244 | - (ceil(output_prio / sqrt(static_cast<double>(bo.outputs.size())))); |
4245 | + |
4246 | + if (bo.outputs_.size() > 1) |
4247 | + output_prio = |
4248 | + static_cast<int32_t>(ceil(output_prio / sqrt(static_cast<double>(bo.outputs_.size())))); |
4249 | + |
4250 | prio += 2 * output_prio; |
4251 | |
4252 | // If building consumes some wares, multiply with current statistics of all |
4253 | // other buildings of this type to avoid constructing buildings where already |
4254 | // some are running on low resources. |
4255 | // Else at least add a part of the stats t the calculation. |
4256 | - if (!bo.inputs.empty()) { |
4257 | - prio *= bo.current_stats; |
4258 | + if (!bo.inputs_.empty()) { |
4259 | + prio *= bo.current_stats_; |
4260 | prio /= 100; |
4261 | } else |
4262 | - prio = ((prio * bo.current_stats) / 100) + (prio / 2); |
4263 | + prio = ((prio * bo.current_stats_) / 100) + (prio / 2); |
4264 | |
4265 | return prio; |
4266 | } |
4267 | |
4268 | - |
4269 | -void DefaultAI::consider_productionsite_influence |
4270 | - (BuildableField & field, Coords coords, const BuildingObserver & bo) |
4271 | -{ |
4272 | - if |
4273 | - (bo.space_consumer |
4274 | - and |
4275 | - game().map().calc_distance(coords, field.coords) < 4) |
4276 | - ++field.space_consumers_nearby; |
4277 | - |
4278 | - for (size_t i = 0; i < bo.inputs.size(); ++i) |
4279 | - ++field.consumers_nearby.at(bo.inputs.at(i)); |
4280 | - for (size_t i = 0; i < bo.outputs.size(); ++i) |
4281 | - ++field.producers_nearby.at(bo.outputs.at(i)); |
4282 | +void DefaultAI::consider_productionsite_influence(BuildableField& field, |
4283 | + Coords coords, |
4284 | + const BuildingObserver& bo) { |
4285 | + if (bo.space_consumer_ and game().map().calc_distance(coords, field.coords) < 4) |
4286 | + ++field.space_consumers_nearby_; |
4287 | + |
4288 | + for (size_t i = 0; i < bo.inputs_.size(); ++i) |
4289 | + ++field.consumers_nearby_.at(bo.inputs_.at(i)); |
4290 | + |
4291 | + for (size_t i = 0; i < bo.outputs_.size(); ++i) |
4292 | + ++field.producers_nearby_.at(bo.outputs_.at(i)); |
4293 | } |
4294 | |
4295 | - |
4296 | /// \returns the economy observer containing \arg economy |
4297 | -EconomyObserver * DefaultAI::get_economy_observer(Economy & economy) |
4298 | -{ |
4299 | - for |
4300 | - (std::list<EconomyObserver *>::iterator i = economies.begin(); |
4301 | - i != economies.end(); |
4302 | - ++i) |
4303 | +EconomyObserver* DefaultAI::get_economy_observer(Economy& economy) { |
4304 | + for (std::list<EconomyObserver*>::iterator i = economies.begin(); i != economies.end(); ++i) |
4305 | if (&(*i)->economy == &economy) |
4306 | return *i; |
4307 | |
4308 | - economies.push_front (new EconomyObserver(economy)); |
4309 | - |
4310 | + economies.push_front(new EconomyObserver(economy)); |
4311 | return economies.front(); |
4312 | } |
4313 | |
4314 | /// \returns the building observer |
4315 | -BuildingObserver & DefaultAI::get_building_observer(char const * const name) |
4316 | -{ |
4317 | +BuildingObserver& DefaultAI::get_building_observer(char const* const name) { |
4318 | if (tribe == nullptr) |
4319 | late_initialization(); |
4320 | |
4321 | @@ -2080,182 +2687,163 @@ |
4322 | throw wexception("Help: I do not know what to do with a %s", name); |
4323 | } |
4324 | |
4325 | - |
4326 | /// this is called whenever we gain ownership of a PlayerImmovable |
4327 | -void DefaultAI::gain_immovable(PlayerImmovable & pi) |
4328 | -{ |
4329 | - if (upcast(Building, building, &pi)) |
4330 | - gain_building (*building); |
4331 | - else if (upcast(Flag const, flag, &pi)) |
4332 | - new_flags.push_back (flag); |
4333 | - else if (upcast(Road const, road, &pi)) |
4334 | - roads .push_front(road); |
4335 | +void DefaultAI::gain_immovable(PlayerImmovable& pi) { |
4336 | + if (upcast(Building, building, &pi)) |
4337 | + gain_building(*building); |
4338 | + else if (upcast(Flag const, flag, &pi)) |
4339 | + new_flags.push_back(flag); |
4340 | + else if (upcast(Road const, road, &pi)) |
4341 | + roads.push_front(road); |
4342 | } |
4343 | |
4344 | /// this is called whenever we lose ownership of a PlayerImmovable |
4345 | -void DefaultAI::lose_immovable(const PlayerImmovable & pi) |
4346 | -{ |
4347 | - if (upcast(Building const, building, &pi)) |
4348 | - lose_building (*building); |
4349 | - else if (upcast(Flag const, flag, &pi)) { |
4350 | - container_iterate_const(std::list<EconomyObserver *>, economies, i) |
4351 | - container_iterate(std::list<Flag const *>, (*i.current)->flags, j) |
4352 | - if (*j.current == flag) { |
4353 | - (*i.current)->flags.erase (j.current); |
4354 | - return; |
4355 | - } |
4356 | - container_iterate(std::list<Flag const *>, new_flags, i) |
4357 | - if (*i.current == flag) { |
4358 | - new_flags.erase(i.current); |
4359 | - return; |
4360 | - } |
4361 | - } else if (upcast(Road const, road, &pi)) |
4362 | - roads.remove (road); |
4363 | +void DefaultAI::lose_immovable(const PlayerImmovable& pi) { |
4364 | + if (upcast(Building const, building, &pi)) |
4365 | + lose_building(*building); |
4366 | + else if (upcast(Flag const, flag, &pi)) { |
4367 | + container_iterate_const(std::list<EconomyObserver*>, economies, i) |
4368 | + container_iterate(std::list<Flag const*>, (*i.current)->flags, j) |
4369 | + |
4370 | + if (*j.current == flag) { |
4371 | + (*i.current)->flags.erase(j.current); |
4372 | + return; |
4373 | + } |
4374 | + |
4375 | + container_iterate(std::list<Flag const*>, new_flags, i) |
4376 | + |
4377 | + if (*i.current == flag) { |
4378 | + new_flags.erase(i.current); |
4379 | + return; |
4380 | + } |
4381 | + } else if (upcast(Road const, road, &pi)) |
4382 | + roads.remove(road); |
4383 | } |
4384 | |
4385 | /// this is called whenever we gain a new building |
4386 | -void DefaultAI::gain_building(Building & b) |
4387 | -{ |
4388 | - BuildingObserver & bo = get_building_observer(b.name().c_str()); |
4389 | +void DefaultAI::gain_building(Building& b) { |
4390 | + BuildingObserver& bo = get_building_observer(b.name().c_str()); |
4391 | |
4392 | if (bo.type == BuildingObserver::CONSTRUCTIONSITE) { |
4393 | - BuildingObserver & target_bo = |
4394 | - get_building_observer |
4395 | - (ref_cast<ConstructionSite, Building>(b) |
4396 | - .building().name().c_str()); |
4397 | - ++target_bo.cnt_under_construction; |
4398 | + BuildingObserver& target_bo = |
4399 | + get_building_observer(ref_cast<ConstructionSite, Building>(b).building().name().c_str()); |
4400 | + ++target_bo.cnt_under_construction_; |
4401 | ++total_constructionsites; |
4402 | // Let defaultAI try to directly connect the constructionsite |
4403 | - next_road_due = game().get_gametime(); |
4404 | - } |
4405 | - else { |
4406 | - ++bo.cnt_built; |
4407 | + next_road_due_ = game().get_gametime(); |
4408 | + } else { |
4409 | + ++bo.cnt_built_; |
4410 | |
4411 | if (bo.type == BuildingObserver::PRODUCTIONSITE) { |
4412 | - productionsites.push_back (ProductionSiteObserver()); |
4413 | + productionsites.push_back(ProductionSiteObserver()); |
4414 | productionsites.back().site = &ref_cast<ProductionSite, Building>(b); |
4415 | productionsites.back().bo = &bo; |
4416 | - productionsites.back().builttime = game().get_gametime(); |
4417 | - productionsites.back().statszero = 0; |
4418 | - |
4419 | - for (uint32_t i = 0; i < bo.outputs.size(); ++i) |
4420 | - ++wares.at(bo.outputs.at(i)).producers; |
4421 | - |
4422 | - for (uint32_t i = 0; i < bo.inputs.size(); ++i) |
4423 | - ++wares.at(bo.inputs.at(i)).consumers; |
4424 | + productionsites.back().built_time_ = game().get_gametime(); |
4425 | + productionsites.back().stats_zero_ = 0; |
4426 | + |
4427 | + for (uint32_t i = 0; i < bo.outputs_.size(); ++i) |
4428 | + ++wares.at(bo.outputs_.at(i)).producers_; |
4429 | + |
4430 | + for (uint32_t i = 0; i < bo.inputs_.size(); ++i) |
4431 | + ++wares.at(bo.inputs_.at(i)).consumers_; |
4432 | } else if (bo.type == BuildingObserver::MINE) { |
4433 | - mines.push_back (ProductionSiteObserver()); |
4434 | - mines.back().site = &ref_cast<ProductionSite, Building>(b); |
4435 | - mines.back().bo = &bo; |
4436 | - |
4437 | - for (uint32_t i = 0; i < bo.outputs.size(); ++i) |
4438 | - ++wares.at(bo.outputs.at(i)).producers; |
4439 | - |
4440 | - for (uint32_t i = 0; i < bo.inputs.size(); ++i) |
4441 | - ++wares.at(bo.inputs.at(i)).consumers; |
4442 | + mines_.push_back(ProductionSiteObserver()); |
4443 | + mines_.back().site = &ref_cast<ProductionSite, Building>(b); |
4444 | + mines_.back().bo = &bo; |
4445 | + |
4446 | + for (uint32_t i = 0; i < bo.outputs_.size(); ++i) |
4447 | + ++wares.at(bo.outputs_.at(i)).producers_; |
4448 | + |
4449 | + for (uint32_t i = 0; i < bo.inputs_.size(); ++i) |
4450 | + ++wares.at(bo.inputs_.at(i)).consumers_; |
4451 | } else if (bo.type == BuildingObserver::MILITARYSITE) { |
4452 | - militarysites.push_back (MilitarySiteObserver()); |
4453 | + militarysites.push_back(MilitarySiteObserver()); |
4454 | militarysites.back().site = &ref_cast<MilitarySite, Building>(b); |
4455 | militarysites.back().bo = &bo; |
4456 | militarysites.back().checks = bo.desc->get_size(); |
4457 | } else if (bo.type == BuildingObserver::WAREHOUSE) |
4458 | - ++numof_warehouses; |
4459 | + ++numof_warehouses_; |
4460 | } |
4461 | } |
4462 | |
4463 | /// this is called whenever we lose a building |
4464 | -void DefaultAI::lose_building(const Building & b) |
4465 | -{ |
4466 | - BuildingObserver & bo = get_building_observer(b.name().c_str()); |
4467 | +void DefaultAI::lose_building(const Building& b) { |
4468 | + BuildingObserver& bo = get_building_observer(b.name().c_str()); |
4469 | |
4470 | if (bo.type == BuildingObserver::CONSTRUCTIONSITE) { |
4471 | - BuildingObserver & target_bo = |
4472 | - get_building_observer |
4473 | - (ref_cast<ConstructionSite const, Building const>(b) |
4474 | - .building().name().c_str()); |
4475 | - --target_bo.cnt_under_construction; |
4476 | + BuildingObserver& target_bo = get_building_observer( |
4477 | + ref_cast<ConstructionSite const, Building const>(b).building().name().c_str()); |
4478 | + --target_bo.cnt_under_construction_; |
4479 | --total_constructionsites; |
4480 | } else { |
4481 | - --bo.cnt_built; |
4482 | + --bo.cnt_built_; |
4483 | |
4484 | if (bo.type == BuildingObserver::PRODUCTIONSITE) { |
4485 | - for |
4486 | - (std::list<ProductionSiteObserver>::iterator i = |
4487 | - productionsites.begin(); |
4488 | - i != productionsites.end(); |
4489 | - ++i) |
4490 | + for (std::list<ProductionSiteObserver>::iterator i = productionsites.begin(); |
4491 | + i != productionsites.end(); |
4492 | + ++i) |
4493 | if (i->site == &b) { |
4494 | productionsites.erase(i); |
4495 | break; |
4496 | } |
4497 | |
4498 | - for (uint32_t i = 0; i < bo.outputs.size(); ++i) |
4499 | - --wares.at(bo.outputs.at(i)).producers; |
4500 | + for (uint32_t i = 0; i < bo.outputs_.size(); ++i) |
4501 | + --wares.at(bo.outputs_.at(i)).producers_; |
4502 | |
4503 | - for (uint32_t i = 0; i < bo.inputs.size(); ++i) |
4504 | - --wares.at(bo.inputs.at(i)).consumers; |
4505 | + for (uint32_t i = 0; i < bo.inputs_.size(); ++i) |
4506 | + --wares.at(bo.inputs_.at(i)).consumers_; |
4507 | } else if (bo.type == BuildingObserver::MINE) { |
4508 | - for |
4509 | - (std::list<ProductionSiteObserver>::iterator i = |
4510 | - mines.begin(); |
4511 | - i != mines.end(); |
4512 | - ++i) |
4513 | + for (std::list<ProductionSiteObserver>::iterator i = mines_.begin(); i != mines_.end(); |
4514 | + ++i) |
4515 | if (i->site == &b) { |
4516 | - mines.erase(i); |
4517 | + mines_.erase(i); |
4518 | break; |
4519 | } |
4520 | |
4521 | - for (uint32_t i = 0; i < bo.outputs.size(); ++i) |
4522 | - --wares.at(bo.outputs.at(i)).producers; |
4523 | + for (uint32_t i = 0; i < bo.outputs_.size(); ++i) |
4524 | + --wares.at(bo.outputs_.at(i)).producers_; |
4525 | |
4526 | - for (uint32_t i = 0; i < bo.inputs.size(); ++i) |
4527 | - --wares.at(bo.inputs.at(i)).consumers; |
4528 | + for (uint32_t i = 0; i < bo.inputs_.size(); ++i) |
4529 | + --wares.at(bo.inputs_.at(i)).consumers_; |
4530 | } else if (bo.type == BuildingObserver::MILITARYSITE) { |
4531 | - for |
4532 | - (std::list<MilitarySiteObserver>::iterator i = |
4533 | - militarysites.begin(); |
4534 | - i != militarysites.end(); |
4535 | - ++i) |
4536 | + for (std::list<MilitarySiteObserver>::iterator i = militarysites.begin(); |
4537 | + i != militarysites.end(); |
4538 | + ++i) |
4539 | if (i->site == &b) { |
4540 | militarysites.erase(i); |
4541 | break; |
4542 | } |
4543 | } else if (bo.type == BuildingObserver::WAREHOUSE) { |
4544 | - assert(numof_warehouses > 0); |
4545 | - --numof_warehouses; |
4546 | + assert(numof_warehouses_ > 0); |
4547 | + --numof_warehouses_; |
4548 | } |
4549 | } |
4550 | + |
4551 | m_buildable_changed = true; |
4552 | m_mineable_changed = true; |
4553 | } |
4554 | |
4555 | - |
4556 | /// Checks that supply line exists for given building. |
4557 | -/// Recurcsively verify that all inputs have a producer. |
4558 | +/// Recurcsively verify that all inputs_ have a producer. |
4559 | // TODO: this function leads to periodic freezes of ~1 second on big games on my system. |
4560 | // TODO: It needs profiling and optimization. |
4561 | -bool DefaultAI::check_supply(const BuildingObserver & bo) |
4562 | -{ |
4563 | +// NOTE: This is not needed anymore and it seems it is not missed neither |
4564 | +bool DefaultAI::check_supply(const BuildingObserver& bo) { |
4565 | size_t supplied = 0; |
4566 | - container_iterate_const(std::vector<int16_t>, bo.inputs, i) |
4567 | - container_iterate_const(std::vector<BuildingObserver>, buildings, j) |
4568 | - if |
4569 | - (j.current->cnt_built && |
4570 | - std::find |
4571 | - (j.current->outputs.begin(), j.current->outputs.end(), |
4572 | - *i.current) |
4573 | - != |
4574 | - j.current->outputs.end() |
4575 | - && |
4576 | - check_supply(*j.current)) |
4577 | - { |
4578 | - ++supplied; |
4579 | - break; |
4580 | - } |
4581 | - return supplied == bo.inputs.size(); |
4582 | + container_iterate_const(std::vector<int16_t>, bo.inputs_, i) |
4583 | + container_iterate_const(std::vector<BuildingObserver>, buildings, j) |
4584 | + |
4585 | + if (j.current->cnt_built_ && |
4586 | + std::find(j.current->outputs_.begin(), j.current->outputs_.end(), *i.current) != |
4587 | + j.current->outputs_.end() && |
4588 | + check_supply(*j.current)) { |
4589 | + ++supplied; |
4590 | + break; |
4591 | + } |
4592 | + |
4593 | + return supplied == bo.inputs_.size(); |
4594 | } |
4595 | |
4596 | - |
4597 | /** |
4598 | * The defaultAi "considers" via this function whether to attack an |
4599 | * enemy, if opposing military buildings are in sight. In case of an attack it |
4600 | @@ -2268,37 +2856,37 @@ |
4601 | if (militarysites.empty()) |
4602 | return false; |
4603 | |
4604 | - Map & map = game().map(); |
4605 | + Map& map = game().map(); |
4606 | uint16_t const pn = player_number(); |
4607 | - |
4608 | // Check next militarysite |
4609 | - MilitarySite * ms = militarysites.front().site; |
4610 | + MilitarySite* ms = militarysites.front().site; |
4611 | uint32_t const vision = ms->vision_range(); |
4612 | FCoords f = map.get_fcoords(ms->get_position()); |
4613 | - |
4614 | - Building * target = ms; // dummy initialisation to silence the compiler |
4615 | - int32_t chance = 0; |
4616 | - uint32_t attackers = 0; |
4617 | - uint8_t retreat = ms->owner().get_retreat_percentage(); |
4618 | - |
4619 | + Building* target = ms; // dummy initialisation to silence the compiler |
4620 | + int32_t chance = 0; |
4621 | + uint32_t attackers = 0; |
4622 | + uint8_t retreat = ms->owner().get_retreat_percentage(); |
4623 | // Search in a radius of the vision of the militarysite and collect |
4624 | // information about immovables in the area |
4625 | std::vector<ImmovableFound> immovables; |
4626 | - map.find_immovables |
4627 | - (Area<FCoords>(f, vision), &immovables, FindImmovableAttackable()); |
4628 | + map.find_immovables(Area<FCoords>(f, vision), &immovables, FindImmovableAttackable()); |
4629 | |
4630 | for (uint32_t j = 0; j < immovables.size(); ++j) |
4631 | if (upcast(MilitarySite, bld, immovables.at(j).object)) { |
4632 | if (!player->is_hostile(bld->owner())) |
4633 | continue; |
4634 | + |
4635 | if (bld->canAttack()) { |
4636 | int32_t ta = player->findAttackSoldiers(bld->base_flag()); |
4637 | + |
4638 | if (type == NORMAL) |
4639 | ta = ta * 2 / 3; |
4640 | + |
4641 | if (ta < 1) |
4642 | continue; |
4643 | |
4644 | int32_t const tc = ta - bld->presentSoldiers().size(); |
4645 | + |
4646 | if (tc > chance) { |
4647 | target = bld; |
4648 | chance = tc; |
4649 | @@ -2308,13 +2896,16 @@ |
4650 | } else if (upcast(Warehouse, wh, immovables.at(j).object)) { |
4651 | if (!player->is_hostile(wh->owner())) |
4652 | continue; |
4653 | + |
4654 | if (wh->canAttack()) { |
4655 | int32_t ta = player->findAttackSoldiers(wh->base_flag()); |
4656 | + |
4657 | if (ta < 1) |
4658 | continue; |
4659 | |
4660 | // extra priority push! |
4661 | int32_t tc = ta * 2; |
4662 | + |
4663 | if (tc > chance) { |
4664 | target = wh; |
4665 | chance = tc; |
4666 | @@ -2329,7 +2920,7 @@ |
4667 | |
4668 | // Return if chance to win is too low |
4669 | if (chance < 3) { |
4670 | - next_attack_consideration_due = gametime % 7 * 1000 + gametime; |
4671 | + next_attack_consideration_due_ = gametime % 7 * 1000 + gametime; |
4672 | return false; |
4673 | } |
4674 | |
4675 | @@ -2338,10 +2929,8 @@ |
4676 | } |
4677 | |
4678 | // Attack the selected target. |
4679 | - game().send_player_enemyflagaction |
4680 | - (target->base_flag(), pn, attackers, retreat); |
4681 | - |
4682 | + game().send_player_enemyflagaction(target->base_flag(), pn, attackers, retreat); |
4683 | // Do not attack again too soon - returning soldiers must get healed first. |
4684 | - next_attack_consideration_due = (gametime % 51 + 10) * 1000 + gametime; |
4685 | + next_attack_consideration_due_ = (gametime % 51 + 10) * 1000 + gametime; |
4686 | return true; |
4687 | } |
4688 | |
4689 | === modified file 'src/ai/defaultai.h' |
4690 | --- src/ai/defaultai.h 2014-02-22 18:04:02 +0000 |
4691 | +++ src/ai/defaultai.h 2014-06-10 18:35:21 +0000 |
4692 | @@ -41,8 +41,8 @@ |
4693 | * It should be able to expand it's territory and to recruit some soldiers from |
4694 | * the weapons made out of it's mined resources. |
4695 | * It does only construct buildable and allowed (scenario mode) buildings. |
4696 | - * It behaves after preciousness of a ware, which can be defined in wares conf |
4697 | - * file. The higher the preciousness, the more will defaultAI care for that ware |
4698 | + * It behaves after preciousness_ of a ware, which can be defined in wares conf |
4699 | + * file. The higher the preciousness_, the more will defaultAI care for that ware |
4700 | * and will try to build up an infrastructure to create that ware. |
4701 | * |
4702 | * \NOTE Network safeness: |
4703 | @@ -62,47 +62,50 @@ |
4704 | * - improvements and speedups in the whole defaultAI code. |
4705 | * - handling of trainingsites (if supply line is broken - send some soldiers |
4706 | * out, to have some more forces. Reincrease the number of soldiers that |
4707 | - * should be trained if inputs get filled again.). |
4708 | + * should be trained if inputs_ get filled again.). |
4709 | * |
4710 | */ |
4711 | struct DefaultAI : Computer_Player { |
4712 | - DefaultAI(Widelands::Game &, const Widelands::Player_Number, uint8_t); |
4713 | + DefaultAI(Widelands::Game&, const Widelands::Player_Number, uint8_t); |
4714 | ~DefaultAI(); |
4715 | - virtual void think () override; |
4716 | + virtual void think() override; |
4717 | |
4718 | - virtual void receive(const Widelands::NoteImmovable &) override; |
4719 | - virtual void receive(const Widelands::NoteFieldPossession &) override; |
4720 | + virtual void receive(const Widelands::NoteImmovable&) override; |
4721 | + virtual void receive(const Widelands::NoteFieldPossession&) override; |
4722 | |
4723 | enum { |
4724 | AGGRESSIVE = 2, |
4725 | - NORMAL = 1, |
4726 | - DEFENSIVE = 0, |
4727 | + NORMAL = 1, |
4728 | + DEFENSIVE = 0, |
4729 | }; |
4730 | |
4731 | /// Implementation for Aggressive |
4732 | struct AggressiveImpl : public Computer_Player::Implementation { |
4733 | - AggressiveImpl() {name = _("Aggressive");} |
4734 | - Computer_Player * instantiate |
4735 | - (Widelands::Game & game, Widelands::Player_Number const p) const override |
4736 | - { |
4737 | + AggressiveImpl() { |
4738 | + name = _("Aggressive"); |
4739 | + } |
4740 | + Computer_Player* instantiate(Widelands::Game& game, |
4741 | + Widelands::Player_Number const p) const override { |
4742 | return new DefaultAI(game, p, AGGRESSIVE); |
4743 | } |
4744 | }; |
4745 | |
4746 | struct NormalImpl : public Computer_Player::Implementation { |
4747 | - NormalImpl() {name = _("Normal");} |
4748 | - Computer_Player * instantiate |
4749 | - (Widelands::Game & game, Widelands::Player_Number const p) const override |
4750 | - { |
4751 | + NormalImpl() { |
4752 | + name = _("Normal"); |
4753 | + } |
4754 | + Computer_Player* instantiate(Widelands::Game& game, |
4755 | + Widelands::Player_Number const p) const override { |
4756 | return new DefaultAI(game, p, NORMAL); |
4757 | } |
4758 | }; |
4759 | |
4760 | struct DefensiveImpl : public Computer_Player::Implementation { |
4761 | - DefensiveImpl() {name = _("Defensive");} |
4762 | - Computer_Player * instantiate |
4763 | - (Widelands::Game & game, Widelands::Player_Number const p) const override |
4764 | - { |
4765 | + DefensiveImpl() { |
4766 | + name = _("Defensive"); |
4767 | + } |
4768 | + Computer_Player* instantiate(Widelands::Game& game, |
4769 | + Widelands::Player_Number const p) const override { |
4770 | return new DefaultAI(game, p, DEFENSIVE); |
4771 | } |
4772 | }; |
4773 | @@ -112,47 +115,50 @@ |
4774 | static DefensiveImpl defensiveImpl; |
4775 | |
4776 | private: |
4777 | - void late_initialization (); |
4778 | - |
4779 | - void update_all_buildable_fields (int32_t); |
4780 | - void update_all_mineable_fields (int32_t); |
4781 | - void update_all_not_buildable_fields (); |
4782 | - |
4783 | - void update_buildable_field(BuildableField &, uint16_t = 6, bool = false); |
4784 | - void update_mineable_field (MineableField &); |
4785 | + void late_initialization(); |
4786 | + |
4787 | + void update_all_buildable_fields(int32_t); |
4788 | + void update_all_mineable_fields(int32_t); |
4789 | + void update_all_not_buildable_fields(); |
4790 | + |
4791 | + void update_buildable_field(BuildableField&, uint16_t = 6, bool = false); |
4792 | + void update_mineable_field(MineableField&); |
4793 | |
4794 | void update_productionsite_stats(int32_t); |
4795 | |
4796 | - bool construct_building (int32_t); |
4797 | - bool construct_roads (int32_t); |
4798 | - bool improve_roads (int32_t); |
4799 | - |
4800 | - bool improve_transportation_ways (const Widelands::Flag &); |
4801 | - bool connect_flag_to_another_economy (const Widelands::Flag &); |
4802 | - |
4803 | - bool check_economies (); |
4804 | - bool check_productionsites (int32_t); |
4805 | - bool check_mines (int32_t); |
4806 | - bool check_militarysites (int32_t); |
4807 | - |
4808 | - int32_t recalc_with_border_range(const BuildableField &, int32_t); |
4809 | - int32_t calculate_need_for_ps(BuildingObserver &, int32_t); |
4810 | - |
4811 | - void consider_productionsite_influence |
4812 | - (BuildableField &, Widelands::Coords, const BuildingObserver &); |
4813 | - |
4814 | - EconomyObserver * get_economy_observer (Widelands::Economy &); |
4815 | - BuildingObserver & get_building_observer(char const *); |
4816 | - |
4817 | - void gain_immovable (Widelands::PlayerImmovable &); |
4818 | - void lose_immovable (const Widelands::PlayerImmovable &); |
4819 | - void gain_building (Widelands::Building &); |
4820 | - void lose_building (const Widelands::Building &); |
4821 | - |
4822 | - bool check_supply (const BuildingObserver &); |
4823 | - |
4824 | - bool consider_attack (int32_t); |
4825 | - |
4826 | + bool construct_building(int32_t); |
4827 | + bool construct_roads(int32_t); |
4828 | + bool improve_roads(int32_t); |
4829 | + |
4830 | + bool improve_transportation_ways(const Widelands::Flag&); |
4831 | + bool connect_flag_to_another_economy(const Widelands::Flag&); |
4832 | + |
4833 | + bool check_economies(); |
4834 | + bool check_productionsites(int32_t); |
4835 | + bool check_mines_(int32_t); |
4836 | + bool check_militarysites(int32_t); |
4837 | + uint32_t get_stocklevel_by_hint(size_t); |
4838 | + uint32_t get_stocklevel(BuildingObserver&); |
4839 | + uint32_t get_stocklevel(size_t); // count all direct outputs_ |
4840 | + void check_helpersites(int32_t); |
4841 | + |
4842 | + int32_t recalc_with_border_range(const BuildableField&, int32_t); |
4843 | + int32_t calculate_need_for_ps(BuildingObserver&, int32_t); |
4844 | + |
4845 | + void |
4846 | + consider_productionsite_influence(BuildableField&, Widelands::Coords, const BuildingObserver&); |
4847 | + |
4848 | + EconomyObserver* get_economy_observer(Widelands::Economy&); |
4849 | + BuildingObserver& get_building_observer(char const*); |
4850 | + |
4851 | + void gain_immovable(Widelands::PlayerImmovable&); |
4852 | + void lose_immovable(const Widelands::PlayerImmovable&); |
4853 | + void gain_building(Widelands::Building&); |
4854 | + void lose_building(const Widelands::Building&); |
4855 | + |
4856 | + bool check_supply(const BuildingObserver&); |
4857 | + |
4858 | + bool consider_attack(int32_t); |
4859 | |
4860 | private: |
4861 | // Variables of default AI |
4862 | @@ -161,37 +167,48 @@ |
4863 | bool m_buildable_changed; |
4864 | bool m_mineable_changed; |
4865 | |
4866 | - Widelands::Player * player; |
4867 | - Widelands::Tribe_Descr const * tribe; |
4868 | - |
4869 | - std::vector<BuildingObserver> buildings; |
4870 | - uint32_t total_constructionsites; |
4871 | - |
4872 | - std::list<Widelands::FCoords> unusable_fields; |
4873 | - std::list<BuildableField *> buildable_fields; |
4874 | - std::list<BlockedField> blocked_fields; |
4875 | - std::list<MineableField *> mineable_fields; |
4876 | - std::list<Widelands::Flag const *> new_flags; |
4877 | - std::list<Widelands::Coords> flags_to_be_removed; |
4878 | - std::list<Widelands::Road const *> roads; |
4879 | - std::list<EconomyObserver *> economies; |
4880 | - std::list<ProductionSiteObserver> productionsites; |
4881 | - std::list<ProductionSiteObserver> mines; |
4882 | - std::list<MilitarySiteObserver> militarysites; |
4883 | - |
4884 | - std::vector<WareObserver> wares; |
4885 | - |
4886 | - int32_t next_road_due; |
4887 | - int32_t next_stats_update_due; |
4888 | - int32_t next_construction_due; |
4889 | - int32_t next_productionsite_check_due; |
4890 | - int32_t next_mine_check_due; |
4891 | - int32_t next_militarysite_check_due; |
4892 | - int32_t next_attack_consideration_due; |
4893 | - int32_t inhibit_road_building; |
4894 | - int32_t time_of_last_construction; |
4895 | - |
4896 | - uint16_t numof_warehouses; |
4897 | + Widelands::Player* player; |
4898 | + Widelands::Tribe_Descr const* tribe; |
4899 | + |
4900 | + std::vector<BuildingObserver> buildings; |
4901 | + uint32_t total_constructionsites; |
4902 | + |
4903 | + std::list<Widelands::FCoords> unusable_fields; |
4904 | + std::list<BuildableField*> buildable_fields; |
4905 | + std::list<BlockedField> blocked_fields; |
4906 | + std::list<MineableField*> mineable_fields; |
4907 | + std::list<Widelands::Flag const*> new_flags; |
4908 | + std::list<Widelands::Coords> flags_to_be_removed; |
4909 | + std::list<Widelands::Road const*> roads; |
4910 | + std::list<EconomyObserver*> economies; |
4911 | + std::list<ProductionSiteObserver> productionsites; |
4912 | + std::list<ProductionSiteObserver> mines_; |
4913 | + std::list<MilitarySiteObserver> militarysites; |
4914 | + |
4915 | + std::vector<WareObserver> wares; |
4916 | + |
4917 | + int32_t next_road_due_; |
4918 | + int32_t next_stats_update_due_; |
4919 | + int32_t next_construction_due_; |
4920 | + int32_t next_mine_construction_due_; |
4921 | + int32_t next_productionsite_check_due_; |
4922 | + int32_t next_mine_check_due_; |
4923 | + int32_t next_militarysite_check_due_; |
4924 | + int32_t next_attack_consideration_due_; |
4925 | + int32_t next_helpersites_check_due_; |
4926 | + int32_t inhibit_road_building_; |
4927 | + int32_t time_of_last_construction_; |
4928 | + int32_t next_wood_cutting_check_due_; |
4929 | + |
4930 | + uint16_t numof_warehouses_; |
4931 | + |
4932 | + bool new_buildings_stop_; |
4933 | + uint16_t unstationed_milit_buildings_; // counts empty military buildings (ones where no soldier |
4934 | + // is belogning to) |
4935 | + uint16_t military_under_constr_; |
4936 | + uint16_t military_last_dismantle_; |
4937 | + int32_t military_last_build_; // sometimes expansions just stops, this is time of last military |
4938 | + // building build |
4939 | }; |
4940 | |
4941 | #endif |
4942 | |
4943 | === modified file 'src/constants.h' |
4944 | --- src/constants.h 2014-03-18 17:30:38 +0000 |
4945 | +++ src/constants.h 2014-06-10 18:35:21 +0000 |
4946 | @@ -88,6 +88,7 @@ |
4947 | #define UI_FONT_CLR_BAD_HEX "bb0000" |
4948 | #define UI_FONT_CLR_OK_HEX "ffe11e" |
4949 | #define UI_FONT_CLR_GOOD_HEX "00bb00" |
4950 | +#define UI_FONT_CLR_IDLE_HEX "0090ff" |
4951 | //@} |
4952 | |
4953 | /** \name Text colors |
4954 | |
4955 | === modified file 'src/economy/economy.cc' |
4956 | --- src/economy/economy.cc 2014-05-04 17:24:41 +0000 |
4957 | +++ src/economy/economy.cc 2014-06-10 18:35:21 +0000 |
4958 | @@ -650,8 +650,8 @@ |
4959 | best_cost)) |
4960 | { |
4961 | if (!best_route) |
4962 | - throw wexception |
4963 | - ("Economy::find_best_supply: COULD NOT FIND A ROUTE!"); |
4964 | + // throw wexception |
4965 | + printf ("Economy::find_best_supply: COULD NOT FIND A ROUTE!"); |
4966 | continue; |
4967 | } |
4968 | |
4969 | |
4970 | === modified file 'src/graphic/animation.cc' |
4971 | --- src/graphic/animation.cc 2014-04-21 10:47:03 +0000 |
4972 | +++ src/graphic/animation.cc 2014-06-10 18:35:21 +0000 |
4973 | @@ -205,11 +205,18 @@ |
4974 | if (g_fs->FileExists(pc_filename)) { |
4975 | hasplrclrs_ = true; |
4976 | const Image* pc_image = g_gr->images().get(pc_filename); |
4977 | - if (frames_[0]->width() != pc_image->width() or frames_[0]->height() != pc_image->height()) |
4978 | - throw wexception |
4979 | - ("playercolor mask has wrong size: (%u, %u), should " |
4980 | - "be (%u, %u) like the animation frame", |
4981 | - pc_image->width(), pc_image->height(), frames_[0]->width(), frames_[0]->height()); |
4982 | + //temporary workaround, just to avoid crashes |
4983 | + if (frames_[0]->width() != pc_image->width() or frames_[0]->height() != pc_image->height()){ |
4984 | + printf("ANIMATION ERROR: playercolor mask has wrong size: (%s: %u, %u), should " |
4985 | + "be (%u, %u) like the animation frame\n", |
4986 | + pc_filename.c_str(),pc_image->width(), pc_image->height(), frames_[0]->width(), frames_[0]->height()); |
4987 | + hasplrclrs_ = false; |
4988 | + break; |
4989 | + } |
4990 | + //throw wexception |
4991 | + //("playercolor mask has wrong size: (%s: %u, %u), should " |
4992 | + //"be (%u, %u) like the animation frame", |
4993 | + //pc_filename.c_str(),pc_image->width(), pc_image->height(), frames_[0]->width(), frames_[0]->height()); |
4994 | pcmasks_.push_back(pc_image); |
4995 | } |
4996 | } |
4997 | |
4998 | === modified file 'src/logic/cmd_queue.h' |
4999 | --- src/logic/cmd_queue.h 2014-05-31 10:31:18 +0000 |
5000 | +++ src/logic/cmd_queue.h 2014-06-10 18:35:21 +0000 |
I started reviewing this, but it still contains a bunch of stuff that needs cleaning up (calls to valgrind, commented code and their like). So I stopped since it is not ready for merging in this state.
Also, you have a strange comment with "owned by me" in there. As long as I do not understand if you are willing to contribute this back to the code base, I am unsure if reviewing is a useful activity. Could you clarify please?