Merge lp:~tiborb95/widelands/tiborb-ai into lp:widelands

Proposed by TiborB
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
Reviewer Review Type Date Requested Status
SirVer Approve
Review via email: mp+219947@code.launchpad.net

Description of the change

conflicts should be resolved now

To post a comment you must log in.
Revision history for this message
SirVer (sirver) wrote :

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?

review: Needs Fixing
Revision history for this message
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.

Revision history for this message
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?

Revision history for this message
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.

Revision history for this message
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.

Revision history for this message
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.

review: Approve
Revision history for this message
TiborB (tiborb95) wrote :

Glad to hear it! (I do not mean the bug :) )

Revision history for this message
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 :)

Revision history for this message
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://code.launchpad.net/~tiborb95/widelands/tiborb-ai/+merge/219947
> You are the owner of lp:~tiborb95/widelands/tiborb-ai.
>

Revision history for this message
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://code.launchpad.net/~tiborb95/widelands/tiborb-ai/+merge/219947
> You are the owner of lp:~tiborb95/widelands/tiborb-ai.
>

Revision history for this message
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

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
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
The diff has been truncated for viewing.

Subscribers

People subscribed via source and target branches

to status/vote changes: