Merge lp:~widelands-dev/widelands/ai_small_tweaks into lp:widelands

Proposed by TiborB
Status: Merged
Merged at revision: 7851
Proposed branch: lp:~widelands-dev/widelands/ai_small_tweaks
Merge into: lp:widelands
Diff against target: 5211 lines (+1550/-1302)
6 files modified
src/ai/ai_help_structs.cc (+304/-14)
src/ai/ai_help_structs.h (+245/-318)
src/ai/defaultai.cc (+948/-927)
src/ai/defaultai.h (+34/-43)
src/logic/widelands_geometry.cc (+13/-0)
src/logic/widelands_geometry.h (+6/-0)
To merge this branch: bzr merge lp:~widelands-dev/widelands/ai_small_tweaks
Reviewer Review Type Date Requested Status
GunChleoc Approve
Review via email: mp+286407@code.launchpad.net

Description of the change

Another bunch of changes to AI, partially code cleaning and partially functional improvements, areas affected
- blocked fields management
- player strength processing
- attacking reworked a bit
- road management modified
- other nits

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

I have fixed up some data types and added some NOCOMs.

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

OK, I will rework it, but not until next week. BTW, you are really right with your comments...

Revision history for this message
GunChleoc (gunchleoc) wrote :

I could take care of splitting the ai_hintsh/.cc, since I'm waiting for a bunch of reviews anyway :)

Revision history for this message
TiborB (tiborb95) wrote :

For me it does not make a significant difference, it is not much of work. But if you fixed it all, you could merge it before I am back. It is up to you...

Revision history for this message
GunChleoc (gunchleoc) wrote :

All done. Please double-check my code changes and wait for Travis before merging.

review: Approve
Revision history for this message
bunnybot (widelandsofficial) wrote :

Continuous integration builds have changed state:

Travis build 732. State: passed. Details: https://travis-ci.org/widelands/widelands/builds/110188250.
Appveyor build 579. State: success. Details: https://ci.appveyor.com/project/widelands-dev/widelands/build/_widelands_dev_widelands_ai_small_tweaks-579.

Revision history for this message
TiborB (tiborb95) wrote :

OK, it seems it works as before, I checked a code a bit, and I trust you that you had not changed the functionality of my code..

@bunnybot merge

Revision history for this message
bunnybot (widelandsofficial) wrote :

Bunnybot encountered an error while working on this merge proposal:

Running 'bzr merge ../_widelands_dev_widelands_ai_small_tweaks' failed. Output:

 M src/ai/ai_help_structs.cc
 M src/ai/ai_help_structs.h
 M src/ai/defaultai.cc
 M src/ai/defaultai.h
 M src/logic/widelands_geometry.cc
 M src/logic/widelands_geometry.h
Text conflict in src/ai/ai_help_structs.h
Text conflict in src/ai/defaultai.cc
2 conflicts encountered.

Revision history for this message
bunnybot (widelandsofficial) wrote :

Bunnybot encountered an error while working on this merge proposal:

Running 'bzr pull --overwrite' failed. Output:

ssh_exchange_identification: Connection closed by remote host
ConnectionReset reading response for 'BzrDir.open_2.1', retrying
ssh_exchange_identification: Connection closed by remote host
bzr: ERROR: Connection closed: Unexpected end of message. Please check connectivity and permissions, and report a bug if problems persist.
Using saved parent location: bzr+ssh://bazaar.launchpad.net/~widelands-dev/widelands/ai_small_tweaks/

Revision history for this message
bunnybot (widelandsofficial) wrote :

Bunnybot encountered an error while working on this merge proposal:

Running 'bzr pull --overwrite' failed. Output:

ssh_exchange_identification: Connection closed by remote host
ConnectionReset reading response for 'BzrDir.open_2.1', retrying
ssh_exchange_identification: Connection closed by remote host
bzr: ERROR: Connection closed: Unexpected end of message. Please check connectivity and permissions, and report a bug if problems persist.
Using saved parent location: bzr+ssh://bazaar.launchpad.net/~widelands-dev/widelands/ai_small_tweaks/

Revision history for this message
bunnybot (widelandsofficial) wrote :

Continuous integration builds have changed state:

Travis build 732. State: passed. Details: https://travis-ci.org/widelands/widelands/builds/110188250.
Appveyor build 579. State: success. Details: https://ci.appveyor.com/project/widelands-dev/widelands/build/_widelands_dev_widelands_ai_small_tweaks-579.

Revision history for this message
GunChleoc (gunchleoc) wrote :

@bunnybot merge

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 2014-09-30 20:31:43 +0000
3+++ src/ai/ai_help_structs.cc 2016-02-22 08:51:02 +0000
4@@ -24,19 +24,13 @@
5
6 namespace Widelands {
7
8-// FindNodeWithFlagOrRoad
9-bool FindNodeWithFlagOrRoad::accept(const Map&, FCoords fc) const {
10- if (upcast(PlayerImmovable const, pimm, fc.field->get_immovable()))
11- return (dynamic_cast<Flag const*>(pimm) ||
12- (dynamic_cast<Road const*>(pimm) && (fc.field->nodecaps() & BUILDCAPS_FLAG)));
13- return false;
14-}
15-
16 // CheckStepRoadAI
17+CheckStepRoadAI::CheckStepRoadAI(Player* const pl, uint8_t const mc, bool const oe)
18+ : player(pl), movecaps(mc), open_end(oe) {}
19
20 bool CheckStepRoadAI::allowed(
21 Map& map, FCoords start, FCoords end, int32_t, CheckStep::StepId const id) const {
22- uint8_t endcaps = player_->get_buildcaps(end);
23+ uint8_t endcaps = player->get_buildcaps(end);
24
25 // we should not cross fields with road or flags (or any other immovable)
26 if ((map.get_immovable(start)) && !(id == CheckStep::stepFirst)) {
27@@ -44,13 +38,13 @@
28 }
29
30 // Calculate cost and passability
31- if (!(endcaps & movecaps_))
32+ if (!(endcaps & movecaps))
33 return false;
34
35 // Check for blocking immovables
36 if (BaseImmovable const* const imm = map.get_immovable(end))
37 if (imm->get_size() >= BaseImmovable::SMALL) {
38- if (id != CheckStep::stepLast && !open_end_)
39+ if (id != CheckStep::stepLast && !open_end)
40 return false;
41
42 if (dynamic_cast<Flag const*>(imm))
43@@ -66,8 +60,8 @@
44 bool CheckStepRoadAI::reachable_dest(Map& map, FCoords const dest) const {
45 NodeCaps const caps = dest.field->nodecaps();
46
47- if (!(caps & movecaps_)) {
48- if (!((movecaps_ & MOVECAPS_SWIM) && (caps & MOVECAPS_WALK)))
49+ if (!(caps & movecaps)) {
50+ if (!((movecaps & MOVECAPS_SWIM) && (caps & MOVECAPS_WALK)))
51 return false;
52
53 if (!map.can_reach_by_water(dest))
54@@ -76,4 +70,300 @@
55
56 return true;
57 }
58-}
59+
60+// We are looking for fields we can walk on
61+// and owned by hostile player.
62+FindNodeEnemy::FindNodeEnemy(Player* p, Game& g) : player(p), game(g) {}
63+
64+bool FindNodeEnemy::accept(const Map&, const FCoords& fc) const {
65+ return (fc.field->nodecaps() & MOVECAPS_WALK) && fc.field->get_owned_by() != 0 &&
66+ player->is_hostile(*game.get_player(fc.field->get_owned_by()));
67+}
68+
69+// We are looking for buildings owned by hostile player
70+// (sometimes there is a enemy's teritorry without buildings, and
71+// this confuses the AI)
72+FindNodeEnemiesBuilding::FindNodeEnemiesBuilding(Player* p, Game& g) : player(p), game(g) {}
73+
74+bool FindNodeEnemiesBuilding::accept(const Map&, const FCoords& fc) const {
75+ return (fc.field->get_immovable()) && fc.field->get_owned_by() != 0 &&
76+ player->is_hostile(*game.get_player(fc.field->get_owned_by()));
77+}
78+
79+// When looking for unowned terrain to acquire, we are actually
80+// only interested in fields we can walk on.
81+// Fields should either be completely unowned or owned by an opposing player
82+FindNodeUnowned::FindNodeUnowned(Player* p, Game& g, bool oe) : player(p), game(g), only_enemies(oe) {}
83+
84+bool FindNodeUnowned::accept(const Map&, const FCoords& fc) const {
85+ return (fc.field->nodecaps() & MOVECAPS_WALK) &&
86+ ((fc.field->get_owned_by() == 0) ||
87+ player->is_hostile(*game.get_player(fc.field->get_owned_by()))) &&
88+ (!only_enemies || (fc.field->get_owned_by() != 0));
89+}
90+
91+// Sometimes we need to know how many nodes our allies owns
92+FindNodeAllyOwned::FindNodeAllyOwned(Player* p, Game& g, PlayerNumber n) :
93+ player(p), game(g), player_number(n) {}
94+
95+bool FindNodeAllyOwned::accept(const Map&, const FCoords& fc) const {
96+ return (fc.field->nodecaps() & MOVECAPS_WALK) && (fc.field->get_owned_by() != 0) &&
97+ (fc.field->get_owned_by() != player_number) &&
98+ !player->is_hostile(*game.get_player(fc.field->get_owned_by()));
99+}
100+
101+// When looking for unowned terrain to acquire, we must
102+// pay speciall attention to fields where mines can be built.
103+// Fields should be completely unowned
104+FindNodeUnownedMineable::FindNodeUnownedMineable(Player* p, Game& g) : player(p), game(g) {}
105+
106+bool FindNodeUnownedMineable::accept(const Map&, const FCoords& fc) const {
107+ return (fc.field->nodecaps() & BUILDCAPS_MINE) && (fc.field->get_owned_by() == 0);
108+}
109+
110+// Unowned but walkable fields nearby
111+FindNodeUnownedWalkable::FindNodeUnownedWalkable(Player* p, Game& g) : player(p), game(g) {}
112+
113+bool FindNodeUnownedWalkable::accept(const Map&, const FCoords& fc) const {
114+ return (fc.field->nodecaps() & MOVECAPS_WALK) && (fc.field->get_owned_by() == 0);
115+}
116+
117+// Looking only for mines-capable fields nearby
118+// of specific type
119+FindNodeMineable::FindNodeMineable(Game& g, int32_t r) : game(g), res(r) {}
120+
121+bool FindNodeMineable::accept(const Map&, const FCoords& fc) const {
122+
123+ return (fc.field->nodecaps() & BUILDCAPS_MINE) && (fc.field->get_resources() == res);
124+}
125+
126+
127+// Fishers and fishbreeders must be built near water
128+FindNodeWater::FindNodeWater(const World& world) : world_(world) {}
129+
130+bool FindNodeWater::accept(const Map& /* map */, const FCoords& coord) const {
131+ return (world_.terrain_descr(coord.field->terrain_d()).get_is() &
132+ TerrainDescription::Is::kWater) ||
133+ (world_.terrain_descr(coord.field->terrain_r()).get_is() &
134+ TerrainDescription::Is::kWater);
135+}
136+
137+// FindNodeWithFlagOrRoad
138+bool FindNodeWithFlagOrRoad::accept(const Map&, FCoords fc) const {
139+ if (upcast(PlayerImmovable const, pimm, fc.field->get_immovable()))
140+ return (dynamic_cast<Flag const*>(pimm) ||
141+ (dynamic_cast<Road const*>(pimm) && (fc.field->nodecaps() & BUILDCAPS_FLAG)));
142+ return false;
143+}
144+
145+NearFlag::NearFlag(const Flag& f, int32_t const c, int32_t const d) : flag(&f), cost(c), distance(d) {}
146+
147+BuildableField::BuildableField(const Widelands::FCoords& fc)
148+ : coords(fc),
149+ field_info_expiration(20000),
150+ preferred(false),
151+ enemy_nearby(0),
152+ unowned_land_nearby(0),
153+ near_border(false),
154+ unowned_mines_spots_nearby(0),
155+ trees_nearby(0),
156+ // explanation of starting values
157+ // this is done to save some work for AI (CPU utilization)
158+ // base rules are:
159+ // count of rocks can only decrease, so amount of rocks
160+ // is recalculated only when previous count is positive
161+ // count of water fields are stable, so if the current count is
162+ // non-negative, water is not recaldulated
163+ rocks_nearby(1),
164+ water_nearby(-1),
165+ distant_water(0),
166+ fish_nearby(-1),
167+ critters_nearby(-1),
168+ ground_water(1),
169+ space_consumers_nearby(0),
170+ rangers_nearby(0),
171+ area_military_capacity(0),
172+ military_loneliness(1000),
173+ military_in_constr_nearby(0),
174+ area_military_presence(0),
175+ military_stationed(0),
176+ military_unstationed(0),
177+ is_portspace(false),
178+ port_nearby(false),
179+ portspace_nearby(Widelands::ExtendedBool::kUnset),
180+ max_buildcap_nearby(0),
181+ last_resources_check_time(0) {
182+}
183+
184+int32_t BuildableField::own_military_sites_nearby_() {
185+ return military_stationed + military_unstationed;
186+}
187+
188+MineableField::MineableField(const Widelands::FCoords& fc)
189+ : coords(fc),
190+ field_info_expiration(20000),
191+ preferred(false),
192+ mines_nearby(0),
193+ same_mine_fields_nearby(0) {
194+}
195+
196+EconomyObserver::EconomyObserver(Widelands::Economy& e) : economy(e) {
197+ dismantle_grace_time = std::numeric_limits<int32_t>::max();
198+}
199+
200+int32_t BuildingObserver::total_count() const {
201+ return cnt_built + cnt_under_construction;
202+}
203+
204+Widelands::AiModeBuildings BuildingObserver::aimode_limit_status() {
205+ if (total_count() > cnt_limit_by_aimode) {
206+ return Widelands::AiModeBuildings::kLimitExceeded;
207+ } else if (total_count() == cnt_limit_by_aimode) {
208+ return Widelands::AiModeBuildings::kOnLimit;
209+ } else {
210+ return Widelands::AiModeBuildings::kAnotherAllowed;
211+ }
212+}
213+bool BuildingObserver::buildable(Widelands::Player& p) {
214+ return is_buildable && p.is_building_type_allowed(id);
215+}
216+
217+
218+// Computer player does not get notification messages about enemy militarysites
219+// and warehouses, so following is collected based on observation
220+// It is conventient to have some information preserved, like nearby minefields,
221+// when it was attacked, whether it is warehouse and so on
222+// Also AI test more such targets when considering attack and calculated score is
223+// is stored in the observer
224+EnemySiteObserver::EnemySiteObserver()
225+ : is_warehouse(false),
226+ attack_soldiers_strength(0),
227+ defenders_strength(0),
228+ stationed_soldiers(0),
229+ last_time_attackable(std::numeric_limits<uint32_t>::max()),
230+ last_tested(0),
231+ score(0),
232+ mines_nearby(Widelands::ExtendedBool::kUnset),
233+ no_attack_counter(0) {}
234+
235+
236+// as all mines have 3 levels, AI does not know total count of mines per mined material
237+// so this observer will be used for this
238+MineTypesObserver::MineTypesObserver() : in_construction(0), finished(0) {}
239+
240+uint16_t MineTypesObserver::total_count() const {
241+ return in_construction + finished;
242+}
243+
244+// this is used to count militarysites by their size
245+MilitarySiteSizeObserver::MilitarySiteSizeObserver() : in_construction(0), finished(0) {}
246+
247+// this represents a scheduler task
248+SchedulerTask::SchedulerTask
249+ (const uint32_t time, const Widelands::SchedulerTaskId t, const uint8_t p, const char* d):
250+ due_time(time), id(t), priority(p), descr(d) {}
251+
252+bool SchedulerTask::operator<(SchedulerTask other) const {
253+ return priority > other.priority;
254+}
255+
256+
257+// List of blocked fields with block time, with some accompanying functions
258+void BlockedFields::add(Widelands::Coords coords, uint32_t till) {
259+ const uint32_t hash = coords.hash();
260+ if (blocked_fields_.count(hash) == 0) {
261+ blocked_fields_.insert(std::pair<uint32_t, uint32_t>(hash, till));
262+ } else if (blocked_fields_[hash] < till) {
263+ blocked_fields_[hash] = till;
264+ }
265+ // The third possibility is that a field has been already blocked for longer time than 'till'
266+}
267+
268+uint32_t BlockedFields::count() {
269+ return blocked_fields_.size();
270+}
271+
272+void BlockedFields::remove_expired(uint32_t gametime) {
273+ std::vector<uint32_t> fields_to_remove;
274+ for (auto field: blocked_fields_) {
275+ if (field.second < gametime) {
276+ fields_to_remove.push_back(field.first);
277+ }
278+ }
279+ while (!fields_to_remove.empty()) {
280+ blocked_fields_.erase(fields_to_remove.back());
281+ fields_to_remove.pop_back();
282+ }
283+}
284+
285+bool BlockedFields::is_blocked(Coords coords) {
286+ return (blocked_fields_.count(coords.hash()) != 0);
287+}
288+
289+// This is an struct that stores strength of players, info on teams and provides some outputs from these data
290+PlayersStrengths::PlayerStat::PlayerStat() {}
291+PlayersStrengths::PlayerStat::PlayerStat(Widelands::TeamNumber tc, uint32_t pp) :
292+ team_number(tc), players_power(pp) {}
293+
294+// Inserting/updating data
295+void PlayersStrengths::add(Widelands::PlayerNumber pn, Widelands::TeamNumber tn, uint32_t pp) {
296+ if (all_stats.count(pn) == 0) {
297+ all_stats.insert(std::pair<Widelands::PlayerNumber, PlayerStat>(pn, PlayerStat(tn, pp)));
298+ } else {
299+ all_stats[pn].players_power = pp;
300+ }
301+}
302+
303+void PlayersStrengths::recalculate_team_power() {
304+ team_powers.clear();
305+ for (auto& item: all_stats) {
306+ if (item.second.team_number > 0) { // is a member of a team
307+ if (team_powers.count(item.second.team_number) > 0) {
308+ team_powers[item.second.team_number] += item.second.players_power;
309+ } else {
310+ team_powers[item.second.team_number] = item.second.players_power;
311+ }
312+ }
313+ }
314+}
315+
316+// This is strength of player plus third of strength of other members of his team
317+uint32_t PlayersStrengths::get_modified_player_power(Widelands::PlayerNumber pn) {
318+ uint32_t result = 0;
319+ Widelands::TeamNumber team = 0;
320+ if (all_stats.count(pn) > 0) {
321+ result = all_stats[pn].players_power;
322+ team = all_stats[pn].team_number;
323+ };
324+ if (team > 0 && team_powers.count(team) > 0) {
325+ result = result + (team_powers[team] - result) / 3;
326+ };
327+ return result;
328+}
329+
330+bool PlayersStrengths::players_in_same_team(Widelands::PlayerNumber pl1, Widelands::PlayerNumber pl2) {
331+ if (all_stats.count(pl1) > 0 && all_stats.count(pl2) > 0 && pl1 != pl2) {
332+ // team number 0 = no team
333+ return all_stats[pl1].team_number > 0 && all_stats[pl1].team_number == all_stats[pl2].team_number;
334+ } else {
335+ return false;
336+ }
337+}
338+
339+bool PlayersStrengths::strong_enough(Widelands::PlayerNumber pl) {
340+ if (all_stats.count(pl) == 0) {
341+ return false;
342+ }
343+ uint32_t my_strength = all_stats[pl].players_power;
344+ uint32_t strongest_opponent_strength = 0;
345+ for (auto item : all_stats) {
346+ if (!players_in_same_team(item.first, pl) && pl != item.first) {
347+ if (get_modified_player_power(item.first) > strongest_opponent_strength) {
348+ strongest_opponent_strength = get_modified_player_power(item.first);
349+ }
350+ }
351+ }
352+ return my_strength > strongest_opponent_strength + 50;
353+}
354+
355+} // namespace WIdelands
356
357=== modified file 'src/ai/ai_help_structs.h'
358--- src/ai/ai_help_structs.h 2016-02-18 08:42:46 +0000
359+++ src/ai/ai_help_structs.h 2016-02-22 08:51:02 +0000
360@@ -43,10 +43,13 @@
361 class MilitarySite;
362
363 enum class ExtendedBool : uint8_t {kUnset, kTrue, kFalse};
364+
365 enum class BuildingNecessity : uint8_t
366 {kForced, kNeeded, kNotNeeded, kUnset, kNotBuildable, kAllowed, kNeededPending, kForbidden};
367+
368 enum class AiModeBuildings : uint8_t
369 {kAnotherAllowed, kOnLimit, kLimitExceeded};
370+
371 enum class SchedulerTaskId : uint8_t {
372 kBbuildableFieldsCheck,
373 kMineableFieldsCheck,
374@@ -69,35 +72,25 @@
375 };
376
377 struct CheckStepRoadAI {
378- CheckStepRoadAI(Player* const pl, uint8_t const mc, bool const oe)
379- : player_(pl), movecaps_(mc), open_end_(oe) {
380- }
381-
382- void set_openend(bool const oe) {
383- open_end_ = oe;
384- }
385+ CheckStepRoadAI(Player* const pl, uint8_t const mc, bool const oe);
386
387 bool allowed(Map&, FCoords start, FCoords end, int32_t dir, CheckStep::StepId) const;
388 bool reachable_dest(Map&, FCoords dest) const;
389
390- Player* player_;
391- uint8_t movecaps_;
392- bool open_end_;
393+ Player* player;
394+ uint8_t movecaps;
395+ bool open_end;
396 };
397
398 // We are looking for fields we can walk on
399 // and owned by hostile player.
400 struct FindNodeEnemy {
401- bool accept(const Map&, const FCoords& fc) const {
402- return (fc.field->nodecaps() & MOVECAPS_WALK) && fc.field->get_owned_by() != 0 &&
403- player->is_hostile(*game.get_player(fc.field->get_owned_by()));
404- }
405+ FindNodeEnemy(Player* p, Game& g);
406+
407+ bool accept(const Map&, const FCoords& fc) const;
408
409 Player* player;
410 Game& game;
411-
412- FindNodeEnemy(Player* p, Game& g) : player(p), game(g) {
413- }
414 };
415
416 // We are looking for buildings owned by hostile player
417@@ -105,95 +98,76 @@
418 // this confuses the AI)
419
420 struct FindNodeEnemiesBuilding {
421- bool accept(const Map&, const FCoords& fc) const {
422- return (fc.field->get_immovable()) && fc.field->get_owned_by() != 0 &&
423- player->is_hostile(*game.get_player(fc.field->get_owned_by()));
424- }
425+ FindNodeEnemiesBuilding(Player* p, Game& g);
426+
427+ bool accept(const Map&, const FCoords& fc) const;
428
429 Player* player;
430 Game& game;
431-
432- FindNodeEnemiesBuilding(Player* p, Game& g) : player(p), game(g) {
433- }
434 };
435
436 // When looking for unowned terrain to acquire, we are actually
437 // only interested in fields we can walk on.
438 // Fields should either be completely unowned or owned by an opposing player_
439 struct FindNodeUnowned {
440- bool accept(const Map&, const FCoords& fc) const {
441- return (fc.field->nodecaps() & MOVECAPS_WALK) &&
442- ((fc.field->get_owned_by() == 0) ||
443- player_->is_hostile(*game.get_player(fc.field->get_owned_by()))) &&
444- (!only_enemies_ || (fc.field->get_owned_by() != 0));
445- }
446-
447- Player* player_;
448+ FindNodeUnowned(Player* p, Game& g, bool oe = false);
449+
450+ bool accept(const Map&, const FCoords& fc) const;
451+
452+ Player* player;
453 Game& game;
454- bool only_enemies_;
455-
456- FindNodeUnowned(Player* p, Game& g, bool oe = false) : player_(p), game(g), only_enemies_(oe) {
457- }
458+ bool only_enemies;
459 };
460
461 // Sometimes we need to know how many nodes our allies owns
462 struct FindNodeAllyOwned {
463- bool accept(const Map&, const FCoords& fc) const {
464- return (fc.field->nodecaps() & MOVECAPS_WALK) && (fc.field->get_owned_by() != 0) &&
465- (fc.field->get_owned_by() != pn) &&
466- !player_->is_hostile(*game.get_player(fc.field->get_owned_by()));
467- }
468-
469- Player* player_;
470+ FindNodeAllyOwned(Player* p, Game& g, PlayerNumber n);
471+
472+ bool accept(const Map&, const FCoords& fc) const;
473+
474+ Player* player;
475 Game& game;
476- PlayerNumber pn;
477-
478- FindNodeAllyOwned(Player* p, Game& g, PlayerNumber n) : player_(p), game(g), pn(n) {
479- }
480+ PlayerNumber player_number;
481 };
482
483 // When looking for unowned terrain to acquire, we must
484 // pay speciall attention to fields where mines can be built.
485 // Fields should be completely unowned
486 struct FindNodeUnownedMineable {
487- bool accept(const Map&, const FCoords& fc) const {
488-
489- return (fc.field->nodecaps() & BUILDCAPS_MINE) && (fc.field->get_owned_by() == 0);
490- }
491-
492- Player* player_;
493- Game& game;
494-
495- FindNodeUnownedMineable(Player* p, Game& g) : player_(p), game(g) {
496- }
497+ FindNodeUnownedMineable(Player* p, Game& g);
498+
499+ bool accept(const Map&, const FCoords& fc) const;
500+
501+ Player* player;
502+ Game& game;
503+};
504+
505+// Unowned but walkable fields nearby
506+struct FindNodeUnownedWalkable {
507+ FindNodeUnownedWalkable(Player* p, Game& g);
508+
509+ bool accept(const Map&, const FCoords& fc) const;
510+
511+ Player* player;
512+ Game& game;
513 };
514
515 // Looking only for mines-capable fields nearby
516 // of specific type
517 struct FindNodeMineable {
518- bool accept(const Map&, const FCoords& fc) const {
519+ FindNodeMineable(Game& g, int32_t r);
520
521- return (fc.field->nodecaps() & BUILDCAPS_MINE) && (fc.field->get_resources() == res);
522- }
523+ bool accept(const Map&, const FCoords& fc) const;
524
525 Game& game;
526 int32_t res;
527-
528- FindNodeMineable(Game& g, int32_t r) : game(g), res(r) {
529- }
530 };
531
532 // Fishers and fishbreeders must be built near water
533 struct FindNodeWater {
534- FindNodeWater(const World& world) : world_(world) {
535- }
536+ FindNodeWater(const World& world);
537
538- bool accept(const Map& /* map */, const FCoords& coord) const {
539- return (world_.terrain_descr(coord.field->terrain_d()).get_is() &
540- TerrainDescription::Is::kWater) ||
541- (world_.terrain_descr(coord.field->terrain_r()).get_is() &
542- TerrainDescription::Is::kWater);
543- }
544+ bool accept(const Map& /* map */, const FCoords& coord) const;
545
546 private:
547 const World& world_;
548@@ -204,283 +178,216 @@
549 };
550
551 struct NearFlag {
552- Flag const* flag;
553- int32_t cost_;
554- int32_t distance_;
555+ // ordering nearflags by biggest reduction
556+ struct CompareShortening {
557+ bool operator()(const NearFlag& a, const NearFlag& b) const {
558+ return (a.cost - a.distance) > (b.cost - b.distance);
559+ }
560+ };
561
562- NearFlag(const Flag& f, int32_t const c, int32_t const d) : flag(&f), cost_(c), distance_(d) {
563- }
564+ NearFlag(const Flag& f, int32_t const c, int32_t const d);
565
566 bool operator<(const NearFlag& f) const {
567- return cost_ > f.cost_;
568+ return cost > f.cost;
569 }
570
571- bool operator == (Flag const* const f) const {
572+ bool operator==(Flag const* const f) const {
573 return flag == f;
574 }
575-};
576-
577-struct CompareDistance {
578- bool operator()(const NearFlag& a, const NearFlag& b) const {
579- return a.distance_ < b.distance_;
580- }
581-};
582-
583-// ordering nearflags by biggest reduction
584-struct CompareShortening {
585- bool operator()(const NearFlag& a, const NearFlag& b) const {
586- return (a.cost_ - a.distance_) > (b.cost_ - b.distance_);
587- }
588-};
589+
590+ Flag const* flag;
591+ int32_t cost;
592+ int32_t distance;
593+};
594+
595+
596
597 struct WalkableSpot {
598 Coords coords;
599- bool has_flag_;
600+ bool has_flag;
601
602- int32_t cost_;
603+ int32_t cost;
604 void* eco;
605
606- int16_t from_;
607+ int16_t from;
608 int16_t neighbours[6];
609 };
610-}
611-
612-struct BlockedField {
613- Widelands::FCoords coords;
614- uint32_t blocked_until_;
615-
616- BlockedField(Widelands::FCoords c, int32_t until) : coords(c), blocked_until_(until) {
617- }
618-};
619+
620
621 struct BuildableField {
622+ BuildableField(const Widelands::FCoords& fc);
623+
624+ int32_t own_military_sites_nearby_();
625+
626 Widelands::FCoords coords;
627
628- uint32_t field_info_expiration_;
629-
630- bool preferred_;
631- bool enemy_nearby_;
632-
633- uint8_t unowned_land_nearby_;
634+ uint32_t field_info_expiration;
635+
636+ bool preferred;
637+ bool enemy_nearby;
638+
639+ uint8_t unowned_land_nearby;
640 // to identify that field is too close to border and no production building should be built there
641- bool near_border_;
642- uint8_t unowned_mines_spots_nearby_;
643- uint8_t trees_nearby_;
644- uint8_t rocks_nearby_;
645- int16_t water_nearby_;
646- int16_t distant_water_;
647- int8_t fish_nearby_;
648- int8_t critters_nearby_;
649- int8_t ground_water_; // used by wells
650- uint8_t space_consumers_nearby_;
651- uint8_t rangers_nearby_;
652+ bool near_border;
653+ uint8_t unowned_mines_spots_nearby;
654+ uint8_t trees_nearby;
655+ uint8_t rocks_nearby;
656+ int16_t water_nearby;
657+ int16_t distant_water;
658+ int8_t fish_nearby;
659+ int8_t critters_nearby;
660+ int8_t ground_water; // used by wells
661+ uint8_t space_consumers_nearby;
662+ uint8_t rangers_nearby;
663 // to manage the military better following variables exists:
664 // capacity of nearby buildings:
665- int16_t area_military_capacity_;
666+ int16_t area_military_capacity;
667 // distance to near buldings:
668- int16_t military_loneliness_;
669+ int16_t military_loneliness;
670 // count of military buildings in construction
671 // when making decision on new mulitary buildings it considers also
672 // unowned fields and mines, but this information is not quite correct as there
673 // are construction sites that will change this once they are built
674- int16_t military_in_constr_nearby_;
675+ int16_t military_in_constr_nearby;
676 // actual count of soldiers in nearby buldings
677- int16_t area_military_presence_;
678- // stationed (manned) military buildings nearby
679- int16_t military_stationed_;
680- // stationed (manned) military buildings nearby
681- int16_t military_unstationed_;
682- bool is_portspace_;
683- bool port_nearby_; // to increase priority if a port is nearby,
684+ int16_t area_military_presence;
685+ // stationed (manned) military buildings nearby
686+ int16_t military_stationed;
687+ // stationed (manned) military buildings nearby
688+ int16_t military_unstationed;
689+ bool is_portspace;
690+ bool port_nearby; // to increase priority if a port is nearby,
691 // especially for new colonies
692- Widelands::ExtendedBool portspace_nearby_; // prefer military buildings closer to the portspace
693- int32_t max_buildcap_nearby_;
694+ Widelands::ExtendedBool portspace_nearby; // prefer military buildings closer to the portspace
695+ int32_t max_buildcap_nearby;
696 // it is not necessary to check resources (stones, fish...) too frequently as they do not change fast
697 // this stores time of last check
698- uint32_t last_resources_check_time_;
699+ uint32_t last_resources_check_time;
700
701- std::vector<uint8_t> consumers_nearby_;
702- std::vector<uint8_t> producers_nearby_;
703+ std::vector<uint8_t> consumers_nearby;
704+ std::vector<uint8_t> producers_nearby;
705 // and for rangers, fishbreeders:
706- std::vector<uint8_t> supporters_nearby_;
707-
708- BuildableField(const Widelands::FCoords& fc)
709- : coords(fc),
710- field_info_expiration_(20000),
711- preferred_(false),
712- enemy_nearby_(0),
713- unowned_land_nearby_(0),
714- near_border_(false),
715- unowned_mines_spots_nearby_(0),
716- trees_nearby_(0),
717- // explanation of starting values
718- // this is done to save some work for AI (CPU utilization)
719- // base rules are:
720- // count of rocks can only decrease, so amount of rocks
721- // is recalculated only when previous count is positive
722- // count of water fields are stable, so if the current count is
723- // non-negative, water is not recaldulated
724- rocks_nearby_(1),
725- water_nearby_(-1),
726- distant_water_(0),
727- fish_nearby_(-1),
728- critters_nearby_(-1),
729- ground_water_(1),
730- space_consumers_nearby_(0),
731- rangers_nearby_(0),
732- area_military_capacity_(0),
733- military_loneliness_(1000),
734- military_in_constr_nearby_(0),
735- area_military_presence_(0),
736- military_stationed_(0),
737- military_unstationed_(0),
738- is_portspace_(false),
739- port_nearby_(false),
740- portspace_nearby_(Widelands::ExtendedBool::kUnset),
741- max_buildcap_nearby_(0),
742- last_resources_check_time_(0) {
743- }
744-
745- int32_t own_military_sites_nearby_() {
746- return military_stationed_ + military_unstationed_;
747- }
748+ std::vector<uint8_t> supporters_nearby;
749 };
750
751 struct MineableField {
752+ MineableField(const Widelands::FCoords& fc);
753+
754 Widelands::FCoords coords;
755-
756- uint32_t field_info_expiration_;
757-
758- bool preferred_;
759-
760- int32_t mines_nearby_;
761+ uint32_t field_info_expiration;
762+ bool preferred;
763+ int32_t mines_nearby;
764 // this is to provide that a mine is not built on the edge of mine area
765- int32_t same_mine_fields_nearby_;
766-
767- MineableField(const Widelands::FCoords& fc)
768- : coords(fc),
769- field_info_expiration_(20000),
770- preferred_(false),
771- mines_nearby_(0),
772- same_mine_fields_nearby_(0) {
773- }
774+ int32_t same_mine_fields_nearby;
775 };
776
777 struct EconomyObserver {
778+ EconomyObserver(Widelands::Economy& e);
779+
780 Widelands::Economy& economy;
781 std::list<Widelands::Flag const*> flags;
782- int32_t dismantle_grace_time_;
783-
784- EconomyObserver(Widelands::Economy& e) : economy(e) {
785- dismantle_grace_time_ = std::numeric_limits<int32_t>::max();
786- }
787+ int32_t dismantle_grace_time;
788 };
789
790 struct BuildingObserver {
791+
792+ enum class Type {
793+ kBoring,
794+ kConstructionsite,
795+ kProductionsite,
796+ kMilitarysite,
797+ kWarehouse,
798+ kTrainingsite,
799+ kMine
800+ };
801+
802+ int32_t total_count() const;
803+ Widelands::AiModeBuildings aimode_limit_status();
804+ bool buildable(Widelands::Player& p);
805+
806 char const* name;
807 Widelands::DescriptionIndex id;
808 Widelands::BuildingDescr const* desc;
809
810- enum {
811- BORING,
812- CONSTRUCTIONSITE,
813- PRODUCTIONSITE,
814- MILITARYSITE,
815- WAREHOUSE,
816- TRAININGSITE,
817- MINE
818- } type;
819-
820- bool plants_trees_;
821- bool recruitment_; // is "producing" workers?
822- Widelands::BuildingNecessity new_building_;
823- uint32_t new_building_overdue_;
824- int32_t primary_priority_;
825- bool is_buildable_;
826- bool need_trees_; // lumberjack = true
827- bool need_rocks_; // quarry = true
828- bool mines_water_; // wells
829- bool need_water_; // fisher, fish_breeder = true
830- bool is_hunter_; // need to identify hunters
831- bool is_fisher_; // need to identify fishers
832- bool is_port_;
833- bool is_shipyard_;
834- bool space_consumer_; // farm, vineyard... = true
835- bool expansion_type_; // military building used that can be used to control area
836- bool fighting_type_; // military building built near enemies
837- bool mountain_conqueror_; // military building built near mountains
838- uint32_t prohibited_till_; // do not build before (ms)
839- uint32_t forced_after_; // do not wait until ware is needed
840- TrainingSiteType trainingsite_type_;
841-
842- uint16_t unconnected_count_; // to any warehouse (count of such buildings)
843-
844- int32_t mines_; // type of resource it mines_
845- uint16_t mines_percent_; // % of res it can mine
846- uint32_t current_stats_;
847-
848- std::vector<int16_t> inputs_;
849- std::vector<int16_t> outputs_;
850- std::vector<Widelands::DescriptionIndex> critical_built_mat_;
851-
852- bool built_mat_producer_;
853+ Type type;
854+
855+ bool plants_trees;
856+ bool recruitment; // is "producing" workers?
857+ Widelands::BuildingNecessity new_building;
858+ uint32_t new_building_overdue;
859+ int32_t primary_priority;
860+ bool is_buildable;
861+ bool need_trees; // lumberjack = true
862+ bool need_rocks; // quarry = true
863+ bool mines_water; // wells
864+ bool need_water; // fisher, fish_breeder = true
865+ bool is_hunter; // need to identify hunters
866+ bool is_fisher; // need to identify fishers
867+ bool is_port;
868+ bool is_shipyard;
869+ bool space_consumer; // farm, vineyard... = true
870+ bool expansion_type; // military building used that can be used to control area
871+ bool fighting_type; // military building built near enemies
872+ bool mountain_conqueror; // military building built near mountains
873+ uint32_t prohibited_till; // do not build before (ms)
874+ uint32_t forced_after; // do not wait until ware is needed
875+ TrainingSiteType trainingsite_type;
876+
877+ uint16_t unconnected_count; // to any warehouse (count of such buildings)
878+
879+ int32_t mines; // type of resource it mines_
880+ uint16_t mines_percent; // % of res it can mine
881+ uint32_t current_stats;
882+
883+ std::vector<int16_t> inputs;
884+ std::vector<int16_t> outputs;
885+ std::vector<Widelands::DescriptionIndex> critical_building_material;
886+
887+ bool produces_building_material;
888
889 // an enhancement to this building:
890 // produces all wares as current building, and perhaps more
891- bool upgrade_substitutes_;
892+ bool upgrade_substitutes;
893 // produces some additional wares
894- bool upgrade_extends_;
895+ bool upgrade_extends;
896
897 // It seems that fish and meat are subsitutes (for trainingsites), so
898 // when testing if a trainingsite is supplied enough
899 // we count the wares together
900- std::unordered_set<Widelands::DescriptionIndex> substitute_inputs_;
901- int32_t substitutes_count_;
902+ std::unordered_set<Widelands::DescriptionIndex> substitute_inputs;
903+ int32_t substitutes_count;
904
905- int16_t production_hint_;
906+ int16_t production_hint;
907
908 // information needed for decision on new building construction
909- int16_t max_preciousness_;
910- int16_t max_needed_preciousness_;
911+ int16_t max_preciousness;
912+ int16_t max_needed_preciousness;
913
914- int32_t cnt_built_;
915- int32_t cnt_under_construction_;
916- int32_t cnt_target_; // number of buildings as target
917- int32_t cnt_limit_by_aimode_; // limit imposed by weak or normal AI mode
918+ int32_t cnt_built;
919+ int32_t cnt_under_construction;
920+ int32_t cnt_target; // number of buildings as target
921+ int32_t cnt_limit_by_aimode; // limit imposed by weak or normal AI mode
922
923 // used to track amount of wares produced by building
924- uint32_t stocklevel_;
925+ uint32_t stocklevel;
926 uint32_t stocklevel_time; // time when stocklevel_ was last time recalculated
927- uint32_t last_dismantle_time_;
928- uint32_t construction_decision_time_;
929-
930- uint32_t unoccupied_count_;
931-
932- bool build_material_shortage_;
933-
934- int32_t total_count() const {
935- return cnt_built_ + cnt_under_construction_;
936- }
937- Widelands::AiModeBuildings aimode_limit_status() {
938- if (total_count() > cnt_limit_by_aimode_) {
939- return Widelands::AiModeBuildings::kLimitExceeded;
940- } else if (total_count() == cnt_limit_by_aimode_) {
941- return Widelands::AiModeBuildings::kOnLimit;
942- } else {
943- return Widelands::AiModeBuildings::kAnotherAllowed;
944- }
945- }
946- bool buildable(Widelands::Player& player_) {
947- return is_buildable_ && player_.is_building_type_allowed(id);
948- }
949+ uint32_t last_dismantle_time;
950+ uint32_t construction_decision_time;
951+ uint32_t last_building_built;
952+
953+ uint32_t unoccupied_count;
954+
955+ bool build_material_shortage;
956+
957+
958 };
959
960 struct ProductionSiteObserver {
961 Widelands::ProductionSite* site;
962- uint32_t built_time_;
963- uint32_t unoccupied_till_;
964- uint8_t stats_zero_;
965- uint32_t no_resources_since_;
966+ uint32_t built_time;
967+ uint32_t unoccupied_till;
968+ uint8_t stats_zero;
969+ uint32_t no_resources_since;
970 BuildingObserver* bo;
971 };
972
973@@ -490,7 +397,7 @@
974 uint8_t checks;
975 // when considering attack most military sites are inside territory and should be skipped during
976 // evaluation
977- bool enemies_nearby_;
978+ bool enemies_nearby;
979 };
980
981 struct TrainingSiteObserver {
982@@ -505,8 +412,8 @@
983
984 struct ShipObserver {
985 Widelands::Ship* ship;
986- Widelands::Coords expedition_start_point_;
987- std::unordered_set<uint32_t> visited_spots_;
988+ Widelands::Coords expedition_start_point;
989+ std::unordered_set<uint32_t> visited_spots;
990
991 // a ship circumvents all islands in the same direction, the value
992 // is assigned only once
993@@ -516,9 +423,9 @@
994 };
995
996 struct WareObserver {
997- uint8_t producers_;
998- uint8_t consumers_;
999- uint8_t preciousness_;
1000+ uint8_t producers;
1001+ uint8_t consumers;
1002+ uint8_t preciousness;
1003 };
1004
1005 // Computer player does not get notification messages about enemy militarysites
1006@@ -528,7 +435,9 @@
1007 // Also AI test more such targets when considering attack and calculated score is
1008 // is stored in the observer
1009 struct EnemySiteObserver {
1010- bool warehouse_;
1011+ EnemySiteObserver();
1012+
1013+ bool is_warehouse;
1014 int32_t attack_soldiers_strength;
1015 int32_t defenders_strength;
1016 uint8_t stationed_soldiers;
1017@@ -537,60 +446,78 @@
1018 int16_t score;
1019 Widelands::ExtendedBool mines_nearby;
1020 int16_t no_attack_counter;
1021-
1022- EnemySiteObserver()
1023- : warehouse_(false),
1024- attack_soldiers_strength(0),
1025- defenders_strength(0),
1026- stationed_soldiers(0),
1027- last_time_attackable(std::numeric_limits<uint32_t>::max()),
1028- last_tested(0),
1029- score(0),
1030- mines_nearby(Widelands::ExtendedBool::kUnset),
1031- no_attack_counter(0) {
1032- }
1033 };
1034
1035 // as all mines have 3 levels, AI does not know total count of mines per mined material
1036 // so this observer will be used for this
1037 struct MineTypesObserver {
1038+ MineTypesObserver();
1039+
1040+ uint16_t total_count() const;
1041+
1042 uint16_t in_construction;
1043 uint16_t finished;
1044-
1045- uint16_t total_count() const {
1046- return in_construction + finished;
1047- }
1048-
1049- MineTypesObserver() : in_construction(0), finished(0) {
1050- }
1051 };
1052
1053 // this is used to count militarysites by their size
1054 struct MilitarySiteSizeObserver {
1055+ MilitarySiteSizeObserver();
1056+
1057 uint16_t in_construction;
1058 uint16_t finished;
1059-
1060- MilitarySiteSizeObserver() : in_construction(0), finished(0) {
1061- }
1062 };
1063
1064 // this represents a scheduler task
1065 struct SchedulerTask {
1066+ SchedulerTask(const uint32_t time, const Widelands::SchedulerTaskId t, const uint8_t p, const char* d);
1067+
1068+ bool operator<(SchedulerTask other) const;
1069+
1070 uint32_t due_time;
1071 Widelands::SchedulerTaskId id;
1072 // used to sort jobs when AI has to perform more jobs at once
1073 uint8_t priority;
1074 // used only for debug purposes
1075 std::string descr;
1076-
1077- bool operator<(SchedulerTask other) const {
1078- return priority > other.priority;
1079- }
1080-
1081- SchedulerTask
1082- (const uint32_t time, const Widelands::SchedulerTaskId t, const uint8_t p, const char* d):
1083- due_time(time), id(t), priority(p), descr(d) {}
1084-
1085-};
1086+};
1087+
1088+// List of blocked fields with block time, with some accompanying functions
1089+struct BlockedFields {
1090+ void add(Coords coords, uint32_t till);
1091+ uint32_t count();
1092+ void remove_expired(uint32_t gametime);
1093+ bool is_blocked(Coords coords);
1094+
1095+private:
1096+ // <hash of field coordinates, time till blocked>
1097+ std::map<uint32_t, uint32_t> blocked_fields_;
1098+};
1099+
1100+// This is a struct that stores strength of players, info on teams and provides some outputs from these data
1101+struct PlayersStrengths {
1102+ struct PlayerStat {
1103+ PlayerStat();
1104+ PlayerStat(Widelands::TeamNumber tc, uint32_t pp);
1105+
1106+ Widelands::TeamNumber team_number;
1107+ uint32_t players_power;
1108+ };
1109+
1110+ // Inserting/updating data
1111+ void add(Widelands::PlayerNumber pn, Widelands::TeamNumber tn, uint32_t pp);
1112+ void recalculate_team_power();
1113+
1114+ // This is strength of player plus third of strength of other members of his team
1115+ uint32_t get_modified_player_power(Widelands::PlayerNumber pn);
1116+ bool players_in_same_team(Widelands::PlayerNumber pl1, Widelands::PlayerNumber pl2);
1117+ bool strong_enough(Widelands::PlayerNumber pl);
1118+
1119+ // This is the core part of this struct
1120+ std::map<Widelands::PlayerNumber, PlayerStat> all_stats;
1121+
1122+ // Number of team, sum of players' strength
1123+ std::map<Widelands::TeamNumber, uint32_t> team_powers;
1124+};
1125+} // namespace Widelands
1126
1127 #endif // end of include guard: WL_AI_AI_HELP_STRUCTS_H
1128
1129=== modified file 'src/ai/defaultai.cc'
1130--- src/ai/defaultai.cc 2016-02-18 08:42:46 +0000
1131+++ src/ai/defaultai.cc 2016-02-22 08:51:02 +0000
1132@@ -75,6 +75,10 @@
1133 constexpr uint32_t kNever = std::numeric_limits<uint32_t>::max();
1134 constexpr uint32_t kNoExpedition = 0;
1135
1136+// following two are used for roads management, for creating shortcuts and dismantling dispensable roads
1137+constexpr int32_t kSpotsTooLittle = 15;
1138+constexpr int32_t kSpotsEnough = 25;
1139+
1140 // this is intended for map developers, by default should be off
1141 constexpr bool kPrintStats = false;
1142
1143@@ -477,9 +481,9 @@
1144
1145 wares.resize(game().tribes().nrwares());
1146 for (DescriptionIndex i = 0; i < static_cast<DescriptionIndex>(game().tribes().nrwares()); ++i) {
1147- wares.at(i).producers_ = 0;
1148- wares.at(i).consumers_ = 0;
1149- wares.at(i).preciousness_ = game().tribes().get_ware_descr(i)->preciousness(tribe_->name());
1150+ wares.at(i).producers = 0;
1151+ wares.at(i).consumers = 0;
1152+ wares.at(i).preciousness = game().tribes().get_ware_descr(i)->preciousness(tribe_->name());
1153 }
1154
1155 const DescriptionIndex& nr_buildings = game().tribes().nrbuildings();
1156@@ -499,116 +503,117 @@
1157 bo.name = building_name.c_str();
1158 bo.id = building_index;
1159 bo.desc = &bld;
1160- bo.type = BuildingObserver::BORING;
1161- bo.cnt_built_ = 0;
1162- bo.cnt_under_construction_ = 0;
1163- bo.cnt_target_ = 1; // default for everything
1164- bo.cnt_limit_by_aimode_ = std::numeric_limits<int32_t>::max();
1165- bo.stocklevel_ = 0;
1166+ bo.type = BuildingObserver::Type::kBoring;
1167+ bo.cnt_built = 0;
1168+ bo.cnt_under_construction = 0;
1169+ bo.cnt_target = 1; // default for everything
1170+ bo.cnt_limit_by_aimode = std::numeric_limits<int32_t>::max();
1171+ bo.stocklevel = 0;
1172 bo.stocklevel_time = 0;
1173- bo.last_dismantle_time_ = 0;
1174+ bo.last_dismantle_time = 0;
1175 // this is set to negative number, otherwise the AI would wait 25 sec
1176 // after game start not building anything
1177- bo.construction_decision_time_ = -60 * 60 * 1000;
1178- bo.build_material_shortage_ = false;
1179- bo.production_hint_ = kUncalculated;
1180- bo.current_stats_ = 0;
1181- bo.unoccupied_count_ = 0;
1182- bo.unconnected_count_ = 0;
1183- bo.new_building_overdue_ = 0;
1184- bo.primary_priority_ = 0;
1185- bo.is_buildable_ = bld.is_buildable();
1186- bo.need_trees_ = bh.is_logproducer();
1187- bo.need_rocks_ = bh.is_graniteproducer();
1188- bo.need_water_ = bh.get_needs_water();
1189- bo.mines_water_ = bh.mines_water();
1190- bo.recruitment_ = bh.for_recruitment();
1191- bo.space_consumer_ = bh.is_space_consumer();
1192- bo.expansion_type_ = bh.is_expansion_type();
1193- bo.fighting_type_ = bh.is_fighting_type();
1194- bo.mountain_conqueror_ = bh.is_mountain_conqueror();
1195- bo.prohibited_till_ = bh.get_prohibited_till() * 1000; // value in conf is in seconds
1196- bo.forced_after_ = bh.get_forced_after() * 1000; // value in conf is in seconds
1197- bo.is_port_ = bld.get_isport();
1198- bo.trainingsite_type_ = TrainingSiteType::kNoTS;
1199- bo.upgrade_substitutes_ = false;
1200- bo.upgrade_extends_ = false;
1201- bo.built_mat_producer_ = false;
1202- bo.max_preciousness_ = 0;
1203- bo.max_needed_preciousness_ = 0;
1204+ bo.construction_decision_time = -60 * 60 * 1000;
1205+ bo.last_building_built = kNever;
1206+ bo.build_material_shortage = false;
1207+ bo.production_hint = kUncalculated;
1208+ bo.current_stats = 0;
1209+ bo.unoccupied_count = 0;
1210+ bo.unconnected_count = 0;
1211+ bo.new_building_overdue = 0;
1212+ bo.primary_priority = 0;
1213+ bo.is_buildable = bld.is_buildable();
1214+ bo.need_trees = bh.is_logproducer();
1215+ bo.need_rocks = bh.is_graniteproducer();
1216+ bo.need_water = bh.get_needs_water();
1217+ bo.mines_water = bh.mines_water();
1218+ bo.recruitment = bh.for_recruitment();
1219+ bo.space_consumer = bh.is_space_consumer();
1220+ bo.expansion_type = bh.is_expansion_type();
1221+ bo.fighting_type = bh.is_fighting_type();
1222+ bo.mountain_conqueror = bh.is_mountain_conqueror();
1223+ bo.prohibited_till = bh.get_prohibited_till() * 1000; // value in conf is in seconds
1224+ bo.forced_after = bh.get_forced_after() * 1000; // value in conf is in seconds
1225+ bo.is_port = bld.get_isport();
1226+ bo.trainingsite_type = TrainingSiteType::kNoTS;
1227+ bo.upgrade_substitutes = false;
1228+ bo.upgrade_extends = false;
1229+ bo.produces_building_material = false;
1230+ bo.max_preciousness = 0;
1231+ bo.max_needed_preciousness = 0;
1232
1233 if (bh.renews_map_resource()) {
1234- bo.production_hint_ = tribe_->safe_ware_index(bh.get_renews_map_resource());
1235+ bo.production_hint = tribe_->safe_ware_index(bh.get_renews_map_resource());
1236 }
1237
1238 // I just presume cut wood is named "log" in the game
1239- if (tribe_->safe_ware_index("log") == bo.production_hint_) {
1240- bo.plants_trees_ = true;
1241+ if (tribe_->safe_ware_index("log") == bo.production_hint) {
1242+ bo.plants_trees = true;
1243 } else {
1244- bo.plants_trees_ = false;
1245+ bo.plants_trees = false;
1246 }
1247
1248 // Is total count of this building limited by AI mode?
1249 if (type_ == DefaultAI::Type::kVeryWeak && bh.get_very_weak_ai_limit() >= 0) {
1250- bo.cnt_limit_by_aimode_ = bh.get_very_weak_ai_limit();
1251+ bo.cnt_limit_by_aimode = bh.get_very_weak_ai_limit();
1252 log (" %d: AI 'very weak' mode: applying limit %d building(s) for %s\n",
1253 player_number(),
1254- bo.cnt_limit_by_aimode_,
1255+ bo.cnt_limit_by_aimode,
1256 bo.name);
1257 }
1258 if (type_ == DefaultAI::Type::kWeak && bh.get_weak_ai_limit() >= 0) {
1259- bo.cnt_limit_by_aimode_ = bh.get_weak_ai_limit();
1260+ bo.cnt_limit_by_aimode = bh.get_weak_ai_limit();
1261 log (" %d: AI 'weak' mode: applying limit %d building(s) for %s\n",
1262 player_number(),
1263- bo.cnt_limit_by_aimode_,
1264+ bo.cnt_limit_by_aimode,
1265 bo.name);
1266 }
1267
1268 // Read all interesting data from ware producing buildings
1269 if (bld.type() == MapObjectType::PRODUCTIONSITE) {
1270 const ProductionSiteDescr& prod = dynamic_cast<const ProductionSiteDescr&>(bld);
1271- bo.type = bld.get_ismine() ? BuildingObserver::MINE : BuildingObserver::PRODUCTIONSITE;
1272+ bo.type = bld.get_ismine() ? BuildingObserver::Type::kMine : BuildingObserver::Type::kProductionsite;
1273 for (const WareAmount& temp_input : prod.inputs()) {
1274- bo.inputs_.push_back(temp_input.first);
1275+ bo.inputs.push_back(temp_input.first);
1276 }
1277 for (const DescriptionIndex& temp_output : prod.output_ware_types()) {
1278- bo.outputs_.push_back(temp_output);
1279+ bo.outputs.push_back(temp_output);
1280 }
1281
1282- if (bo.type == BuildingObserver::MINE) {
1283+ if (bo.type == BuildingObserver::Type::kMine) {
1284 // get the resource needed by the mine
1285 if (bh.get_mines()) {
1286- bo.mines_ = game().world().get_resource(bh.get_mines());
1287+ bo.mines = game().world().get_resource(bh.get_mines());
1288 }
1289
1290- bo.mines_percent_ = bh.get_mines_percent();
1291+ bo.mines_percent = bh.get_mines_percent();
1292
1293 // populating mines_per_type map
1294- if (mines_per_type.count(bo.mines_) == 0) {
1295- mines_per_type[bo.mines_] = MineTypesObserver();
1296+ if (mines_per_type.count(bo.mines) == 0) {
1297+ mines_per_type[bo.mines] = MineTypesObserver();
1298 }
1299 }
1300
1301 // here we identify hunters
1302- if (bo.outputs_.size() == 1 && tribe_->safe_ware_index("meat") == bo.outputs_.at(0)) {
1303- bo.is_hunter_ = true;
1304+ if (bo.outputs.size() == 1 && tribe_->safe_ware_index("meat") == bo.outputs.at(0)) {
1305+ bo.is_hunter = true;
1306 } else {
1307- bo.is_hunter_ = false;
1308+ bo.is_hunter = false;
1309 }
1310
1311 // and fishers
1312- if (bo.outputs_.size() == 1 && tribe_->safe_ware_index("fish") == bo.outputs_.at(0)) {
1313- bo.is_fisher_ = true;
1314+ if (bo.outputs.size() == 1 && tribe_->safe_ware_index("fish") == bo.outputs.at(0)) {
1315+ bo.is_fisher = true;
1316 } else {
1317- bo.is_fisher_ = false;
1318+ bo.is_fisher = false;
1319 }
1320
1321- bo.is_shipyard_ = bh.is_shipyard();
1322+ bo.is_shipyard = bh.is_shipyard();
1323
1324 // now we find out if the upgrade of the building is a full substitution
1325 // (produces all wares as current one)
1326 const DescriptionIndex enhancement = bld.enhancement();
1327- if (enhancement != INVALID_INDEX && bo.type == BuildingObserver::PRODUCTIONSITE) {
1328+ if (enhancement != INVALID_INDEX && bo.type == BuildingObserver::Type::kProductionsite) {
1329 std::unordered_set<DescriptionIndex> enh_outputs;
1330 const ProductionSiteDescr& enh_prod
1331 =
1332@@ -620,23 +625,23 @@
1333 }
1334 // now testing outputs of current building
1335 // and comparing
1336- bo.upgrade_substitutes_ = true;
1337- for (DescriptionIndex ware : bo.outputs_) {
1338+ bo.upgrade_substitutes = true;
1339+ for (DescriptionIndex ware : bo.outputs) {
1340 if (enh_outputs.count(ware) == 0) {
1341- bo.upgrade_substitutes_ = false;
1342+ bo.upgrade_substitutes = false;
1343 break;
1344 }
1345 }
1346
1347 std::unordered_set<DescriptionIndex> cur_outputs;
1348 // collecting wares that are produced in enhanced building
1349- for (const DescriptionIndex& ware : bo.outputs_) {
1350+ for (const DescriptionIndex& ware : bo.outputs) {
1351 cur_outputs.insert(ware);
1352 }
1353- bo.upgrade_extends_ = false;
1354+ bo.upgrade_extends = false;
1355 for (DescriptionIndex ware : enh_outputs) {
1356 if (cur_outputs.count(ware) == 0) {
1357- bo.upgrade_extends_ = true;
1358+ bo.upgrade_extends = true;
1359 break;
1360 }
1361 }
1362@@ -644,23 +649,23 @@
1363
1364 // now we identify producers of critical build materials
1365 // hardwood now
1366- for (DescriptionIndex ware : bo.outputs_) {
1367+ for (DescriptionIndex ware : bo.outputs) {
1368 // iterating over wares subsitutes
1369 if (tribe_->ware_index("wood") == ware ||
1370 tribe_->ware_index("blackwood") == ware ||
1371 tribe_->ware_index("marble") == ware ||
1372 tribe_->ware_index("planks") == ware) {
1373- bo.built_mat_producer_ = true;
1374+ bo.produces_building_material = true;
1375 }
1376 }
1377 continue;
1378 }
1379
1380- // now for every military building, we fill critical_built_mat_ vector
1381+ // now for every military building, we fill critical_building_material vector
1382 // with critical construction wares
1383 // non critical are excluded (see below)
1384 if (bld.type() == MapObjectType::MILITARYSITE) {
1385- bo.type = BuildingObserver::MILITARYSITE;
1386+ bo.type = BuildingObserver::Type::kMilitarysite;
1387 const MilitarySiteDescr& milit = dynamic_cast<const MilitarySiteDescr&>(bld);
1388 for (const std::pair<unsigned char, unsigned char>& temp_buildcosts : milit.buildcost()) {
1389 // bellow are non-critical wares (well, various types of wood)
1390@@ -669,28 +674,28 @@
1391 tribe_->ware_index("planks") == temp_buildcosts.first)
1392 continue;
1393
1394- bo.critical_built_mat_.push_back(temp_buildcosts.first);
1395+ bo.critical_building_material.push_back(temp_buildcosts.first);
1396 }
1397 continue;
1398 }
1399
1400 if (bld.type() == MapObjectType::WAREHOUSE) {
1401- bo.type = BuildingObserver::WAREHOUSE;
1402+ bo.type = BuildingObserver::Type::kWarehouse;
1403 continue;
1404 }
1405
1406 if (bld.type() == MapObjectType::TRAININGSITE) {
1407- bo.type = BuildingObserver::TRAININGSITE;
1408+ bo.type = BuildingObserver::Type::kTrainingsite;
1409 const TrainingSiteDescr& train = dynamic_cast<const TrainingSiteDescr&>(bld);
1410 for (const WareAmount& temp_input : train.inputs()) {
1411- bo.inputs_.push_back(temp_input.first);
1412+ bo.inputs.push_back(temp_input.first);
1413
1414 // collecting subsitutes
1415 if (tribe_->ware_index("meat") == temp_input.first ||
1416 tribe_->ware_index("fish") == temp_input.first ||
1417 tribe_->ware_index("smoked_meat") == temp_input.first ||
1418 tribe_->ware_index("smoked_fish") == temp_input.first) {
1419- bo.substitute_inputs_.insert(temp_input.first);
1420+ bo.substitute_inputs.insert(temp_input.first);
1421 }
1422
1423 for (const std::pair<unsigned char, unsigned char>& temp_buildcosts : train.buildcost()) {
1424@@ -698,19 +703,19 @@
1425 if (tribe_->ware_index("spidercloth") == temp_buildcosts.first ||
1426 tribe_->ware_index("gold") == temp_buildcosts.first ||
1427 tribe_->ware_index("grout") == temp_buildcosts.first) {
1428- bo.critical_built_mat_.push_back(temp_buildcosts.first);
1429+ bo.critical_building_material.push_back(temp_buildcosts.first);
1430 }
1431 }
1432 }
1433- bo.trainingsite_type_ = bh.get_trainingsite_type();
1434+ bo.trainingsite_type = bh.get_trainingsite_type();
1435 // it would behave badly if no type was set
1436 // make sure all TS have its type set properly in conf files
1437- assert(bo.trainingsite_type_ != TrainingSiteType::kNoTS);
1438+ assert(bo.trainingsite_type != TrainingSiteType::kNoTS);
1439 continue;
1440 }
1441
1442 if (bld.type() == MapObjectType::CONSTRUCTIONSITE) {
1443- bo.type = BuildingObserver::CONSTRUCTIONSITE;
1444+ bo.type = BuildingObserver::Type::kConstructionsite;
1445 continue;
1446 }
1447 }
1448@@ -763,7 +768,7 @@
1449 for (const Coords& c : map.get_port_spaces()) {
1450 MapRegion<Area<FCoords>> mr(map, Area<FCoords>(map.get_fcoords(c), 3));
1451 do {
1452- const int32_t hash = coords_hash(map.get_fcoords(*(mr.location().field)));
1453+ const int32_t hash = map.get_fcoords(*(mr.location().field)).hash();
1454 if (port_reserved_coords.count(hash) == 0)
1455 port_reserved_coords.insert(hash);
1456 } while (mr.advance(map));
1457@@ -773,7 +778,7 @@
1458 map.get_tln(c, &c_nw);
1459 MapRegion<Area<FCoords>> mr_nw(map, Area<FCoords>(map.get_fcoords(c_nw), 3));
1460 do {
1461- const int32_t hash = coords_hash(map.get_fcoords(*(mr_nw.location().field)));
1462+ const int32_t hash = map.get_fcoords(*(mr_nw.location().field)).hash();
1463 if (port_reserved_coords.count(hash) == 0)
1464 port_reserved_coords.insert(hash);
1465 } while (mr_nw.advance(map));
1466@@ -827,13 +832,11 @@
1467
1468 // blocking space consumers vicinity (when reloading a game)
1469 for (const ProductionSiteObserver& ps_obs : productionsites) {
1470- if (ps_obs.bo->space_consumer_ && !ps_obs.bo->plants_trees_) {
1471+ if (ps_obs.bo->space_consumer && !ps_obs.bo->plants_trees) {
1472 MapRegion<Area<FCoords>> mr(
1473 map, Area<FCoords>(map.get_fcoords(ps_obs.site->get_position()), 4));
1474 do {
1475- BlockedField blocked2(
1476- map.get_fcoords(*(mr.location().field)), game().get_gametime() + 20 * 60 * 1000);
1477- blocked_fields.push_back(blocked2);
1478+ blocked_fields.add(mr.location(), game().get_gametime() + 20 * 60 * 1000);
1479 } while (mr.advance(map));
1480 }
1481 }
1482@@ -887,7 +890,7 @@
1483
1484 // we test 40 fields that were update more than 1 seconds ago
1485 while (!buildable_fields.empty() &&
1486- (buildable_fields.front()->field_info_expiration_ - kFieldInfoExpiration + 1000) <=
1487+ (buildable_fields.front()->field_info_expiration - kFieldInfoExpiration + 1000) <=
1488 gametime &&
1489 i < 40) {
1490 BuildableField& bf = *buildable_fields.front();
1491@@ -908,7 +911,7 @@
1492 }
1493
1494 update_buildable_field(bf);
1495- bf.field_info_expiration_ = gametime + kFieldInfoExpiration;
1496+ bf.field_info_expiration = gametime + kFieldInfoExpiration;
1497 buildable_fields.push_back(&bf);
1498 buildable_fields.pop_front();
1499
1500@@ -929,7 +932,7 @@
1501 // we test 30 fields that were updated more than 1 seconds ago
1502 // to avoid re-test of the same field twice
1503 while (!mineable_fields.empty() &&
1504- (mineable_fields.front()->field_info_expiration_ - kMineFieldInfoExpiration + 1000) <=
1505+ (mineable_fields.front()->field_info_expiration - kMineFieldInfoExpiration + 1000) <=
1506 gametime &&
1507 i < 30) {
1508 MineableField* mf = mineable_fields.front();
1509@@ -950,7 +953,7 @@
1510 }
1511
1512 update_mineable_field(*mf);
1513- mf->field_info_expiration_ = gametime + kMineFieldInfoExpiration;
1514+ mf->field_info_expiration = gametime + kMineFieldInfoExpiration;
1515 mineable_fields.push_back(mf);
1516 mineable_fields.pop_front();
1517
1518@@ -1003,22 +1006,22 @@
1519 // look if there is any unowned land nearby
1520 Map& map = game().map();
1521 const uint32_t gametime = game().get_gametime();
1522- FindNodeUnowned find_unowned(player_, game());
1523+ FindNodeUnownedWalkable find_unowned_walkable(player_, game());
1524 FindNodeUnownedMineable find_unowned_mines_pots(player_, game());
1525 PlayerNumber const pn = player_->player_number();
1526 const World& world = game().world();
1527- field.unowned_land_nearby_ =
1528- map.find_fields(Area<FCoords>(field.coords, range), nullptr, find_unowned);
1529+ field.unowned_land_nearby =
1530+ map.find_fields(Area<FCoords>(field.coords, range), nullptr, find_unowned_walkable);
1531 FindNodeAllyOwned find_ally(player_, game(), player_number());
1532 const int32_t AllyOwnedFields =
1533 map.find_fields(Area<FCoords>(field.coords, 3), nullptr, find_ally);
1534
1535- field.near_border_ = false;
1536+ field.near_border = false;
1537 if (AllyOwnedFields > 0) {
1538- field.near_border_ = true;
1539- } else if (field.unowned_land_nearby_ > 0) {
1540- if (map.find_fields(Area<FCoords>(field.coords, 4), nullptr, find_unowned) > 0) {
1541- field.near_border_ = true;
1542+ field.near_border = true;
1543+ } else if (field.unowned_land_nearby > 0) {
1544+ if (map.find_fields(Area<FCoords>(field.coords, 4), nullptr, find_unowned_walkable) > 0) {
1545+ field.near_border = true;
1546 }
1547 }
1548
1549@@ -1026,15 +1029,15 @@
1550 // are we going to count resources now?
1551 bool resource_count_now = false;
1552 // Testing in first 10 seconds or if last testing was more then 60 sec ago
1553- if (field.last_resources_check_time_ < 10000 ||
1554- field.last_resources_check_time_ - gametime > 60 * 1000) {
1555+ if (field.last_resources_check_time < 10000 ||
1556+ field.last_resources_check_time - gametime > 60 * 1000) {
1557 resource_count_now = true;
1558- field.last_resources_check_time_ = gametime;
1559+ field.last_resources_check_time = gametime;
1560 }
1561
1562 // to save some CPU
1563 if (mines_.size() > 8 && !resource_count_now) {
1564- field.unowned_mines_spots_nearby_ = 0;
1565+ field.unowned_mines_spots_nearby = 0;
1566 } else {
1567 uint32_t close_mines =
1568 map.find_fields(Area<FCoords>(field.coords, 4), nullptr, find_unowned_mines_pots);
1569@@ -1043,26 +1046,26 @@
1570 nullptr,
1571 find_unowned_mines_pots);
1572 distant_mines = distant_mines - close_mines;
1573- field.unowned_mines_spots_nearby_ = 4 * close_mines + distant_mines / 2;
1574+ field.unowned_mines_spots_nearby = 4 * close_mines + distant_mines / 2;
1575 if (distant_mines > 0) {
1576- field.unowned_mines_spots_nearby_ += 15;
1577+ field.unowned_mines_spots_nearby += 15;
1578 }
1579 }
1580
1581 // identifying portspace fields
1582- if (!field.is_portspace_) { // if we know it, no need to do it once more
1583+ if (!field.is_portspace) { // if we know it, no need to do it once more
1584 if (player_->get_buildcaps(field.coords) & BUILDCAPS_PORT) {
1585- field.is_portspace_ = true;
1586+ field.is_portspace = true;
1587 }
1588 }
1589
1590 // testing for near portspaces
1591- if (field.portspace_nearby_ == Widelands::ExtendedBool::kUnset) {
1592- field.portspace_nearby_ = ExtendedBool::kFalse;
1593- MapRegion<Area<FCoords>> mr(map, Area<FCoords>(field.coords, 2));
1594+ if (field.portspace_nearby == Widelands::ExtendedBool::kUnset) {
1595+ field.portspace_nearby = ExtendedBool::kFalse;
1596+ MapRegion<Area<FCoords>> mr(map, Area<FCoords>(field.coords, 4));
1597 do {
1598- if (port_reserved_coords.count(coords_hash(mr.location())) > 0) {
1599- field.portspace_nearby_ = ExtendedBool::kTrue;
1600+ if (port_reserved_coords.count(mr.location().hash()) > 0) {
1601+ field.portspace_nearby = ExtendedBool::kTrue;
1602 break;
1603 }
1604 } while (mr.advance(map));
1605@@ -1075,23 +1078,23 @@
1606 nearest_distance = std::min(nearest_distance, actual_distance);
1607 }
1608 if (nearest_distance < 15) {
1609- field.port_nearby_ = true;
1610+ field.port_nearby = true;
1611 } else {
1612- field.port_nearby_ = false;
1613+ field.port_nearby = false;
1614 }
1615
1616 // testing fields in radius 1 to find biggest buildcaps.
1617 // This is to calculate capacity that will be lost if something is
1618 // built here
1619- field.max_buildcap_nearby_ = 0;
1620+ field.max_buildcap_nearby = 0;
1621 MapRegion<Area<FCoords>> mr(map, Area<FCoords>(field.coords, 1));
1622 do {
1623- if ((player_->get_buildcaps(mr.location()) & BUILDCAPS_SIZEMASK) > field.max_buildcap_nearby_) {
1624- field.max_buildcap_nearby_ = player_->get_buildcaps(mr.location()) & BUILDCAPS_SIZEMASK;
1625+ if ((player_->get_buildcaps(mr.location()) & BUILDCAPS_SIZEMASK) > field.max_buildcap_nearby) {
1626+ field.max_buildcap_nearby = player_->get_buildcaps(mr.location()) & BUILDCAPS_SIZEMASK;
1627 }
1628 } while (mr.advance(map));
1629
1630- assert ((player_->get_buildcaps(field.coords) & BUILDCAPS_SIZEMASK) <= field.max_buildcap_nearby_);
1631+ assert ((player_->get_buildcaps(field.coords) & BUILDCAPS_SIZEMASK) <= field.max_buildcap_nearby);
1632
1633 // collect information about resources in the area
1634 std::vector<ImmovableFound> immovables;
1635@@ -1102,50 +1105,50 @@
1636 // (second is used in check_militarysites)
1637 if (!military) {
1638 int32_t const tree_attr = MapObjectDescr::get_attribute_id("tree");
1639- field.preferred_ = false;
1640- field.enemy_nearby_ = false;
1641- field.area_military_capacity_ = 0;
1642- field.military_loneliness_ = 1000; // instead of floats(v-
1643- field.area_military_presence_ = 0;
1644- field.military_stationed_ = 0;
1645- field.trees_nearby_ = 0;
1646- field.space_consumers_nearby_ = 0;
1647- field.rangers_nearby_ = 0;
1648- field.producers_nearby_.clear();
1649- field.producers_nearby_.resize(wares.size());
1650- field.consumers_nearby_.clear();
1651- field.consumers_nearby_.resize(wares.size());
1652- field.supporters_nearby_.clear();
1653- field.supporters_nearby_.resize(wares.size());
1654+ field.preferred = false;
1655+ field.enemy_nearby = false;
1656+ field.area_military_capacity = 0;
1657+ field.military_loneliness = 1000; // instead of floats(v-
1658+ field.area_military_presence = 0;
1659+ field.military_stationed = 0;
1660+ field.trees_nearby = 0;
1661+ field.space_consumers_nearby = 0;
1662+ field.rangers_nearby = 0;
1663+ field.producers_nearby.clear();
1664+ field.producers_nearby.resize(wares.size());
1665+ field.consumers_nearby.clear();
1666+ field.consumers_nearby.resize(wares.size());
1667+ field.supporters_nearby.clear();
1668+ field.supporters_nearby.resize(wares.size());
1669 std::vector<Coords> water_list;
1670 std::vector<Coords> resource_list;
1671 std::vector<Bob*> critters_list;
1672
1673- if (field.water_nearby_ == kUncalculated) {
1674+ if (field.water_nearby == kUncalculated) {
1675
1676 FindNodeWater find_water(game().world());
1677 map.find_fields(Area<FCoords>(field.coords, 5), &water_list, find_water);
1678- field.water_nearby_ = water_list.size();
1679+ field.water_nearby = water_list.size();
1680
1681 if (resource_necessity_water_needed_) { // for atlanteans
1682 map.find_fields(Area<FCoords>(field.coords, 14), &water_list, find_water);
1683- field.distant_water_ = water_list.size() - field.water_nearby_;
1684+ field.distant_water = water_list.size() - field.water_nearby;
1685 }
1686 }
1687
1688 // counting fields with fish
1689- if (field.water_nearby_ > 0 && (field.fish_nearby_ == kUncalculated || resource_count_now)) {
1690+ if (field.water_nearby > 0 && (field.fish_nearby == kUncalculated || resource_count_now)) {
1691 map.find_fields(Area<FCoords>(field.coords, 6),
1692 &resource_list,
1693 FindNodeResource(world.get_resource("fish")));
1694- field.fish_nearby_ = resource_list.size();
1695+ field.fish_nearby = resource_list.size();
1696 }
1697
1698 // counting fields with critters (game)
1699 // not doing this always, this does not change fast
1700 if (resource_count_now) {
1701 map.find_bobs(Area<FCoords>(field.coords, 6), &critters_list, FindBobCritter());
1702- field.critters_nearby_ = critters_list.size();
1703+ field.critters_nearby = critters_list.size();
1704 }
1705
1706 FCoords fse;
1707@@ -1154,7 +1157,7 @@
1708 if (BaseImmovable const* const imm = fse.field->get_immovable()) {
1709 if (dynamic_cast<Flag const*>(imm) ||
1710 (dynamic_cast<Road const*>(imm) && (fse.field->nodecaps() & BUILDCAPS_FLAG))) {
1711- field.preferred_ = true;
1712+ field.preferred = true;
1713 }
1714 }
1715
1716@@ -1167,7 +1170,7 @@
1717 // allied sites should be counted for military influence
1718 if (player_immovable->owner().player_number() != pn) {
1719 if (player_->is_hostile(player_immovable->owner())) {
1720- field.enemy_nearby_ = true;
1721+ field.enemy_nearby = true;
1722 }
1723
1724 continue;
1725@@ -1186,26 +1189,26 @@
1726 }
1727
1728 if (immovables.at(i).object->has_attribute(tree_attr)) {
1729- ++field.trees_nearby_;
1730+ ++field.trees_nearby;
1731 }
1732 }
1733
1734 // Rocks are not renewable, we will count them only if previous state is nonzero
1735- if (field.rocks_nearby_ > 0 && resource_count_now) {
1736+ if (field.rocks_nearby > 0 && resource_count_now) {
1737
1738- field.rocks_nearby_ =
1739+ field.rocks_nearby =
1740 map.find_immovables(Area<FCoords>(map.get_fcoords(field.coords), 6),
1741 nullptr,
1742 FindImmovableAttribute(MapObjectDescr::get_attribute_id("rocks")));
1743
1744 // adding 10 if rocks found
1745- field.rocks_nearby_ = (field.rocks_nearby_ > 0) ? field.rocks_nearby_ + 10:0;
1746+ field.rocks_nearby = (field.rocks_nearby > 0) ? field.rocks_nearby + 10:0;
1747 }
1748
1749 // ground water is not renewable and its amount can only fall, we will count them only if
1750 // previous state is nonzero
1751- if (field.ground_water_ > 0) {
1752- field.ground_water_ = field.coords.field->get_resources_amount();
1753+ if (field.ground_water > 0) {
1754+ field.ground_water = field.coords.field->get_resources_amount();
1755 }
1756 }
1757
1758@@ -1214,12 +1217,12 @@
1759 // we get immovables with higher radius
1760 immovables.clear();
1761 map.find_immovables(Area<FCoords>(field.coords, (range < 11) ? 11 : range), &immovables);
1762- field.military_stationed_ = 0;
1763- field.military_unstationed_ = 0;
1764- field.military_in_constr_nearby_ = 0;
1765- field.area_military_capacity_ = 0;
1766- field.military_loneliness_ = 1000;
1767- field.area_military_presence_ = 0;
1768+ field.military_stationed = 0;
1769+ field.military_unstationed = 0;
1770+ field.military_in_constr_nearby = 0;
1771+ field.area_military_capacity = 0;
1772+ field.military_loneliness = 1000;
1773+ field.area_military_presence = 0;
1774
1775 for (uint32_t i = 0; i < immovables.size(); ++i) {
1776
1777@@ -1233,7 +1236,7 @@
1778 // allied sites should be counted for military influence
1779 if (player_immovable->owner().player_number() != pn) {
1780 if (player_->is_hostile(player_immovable->owner())) {
1781- field.enemy_nearby_ = true;
1782+ field.enemy_nearby = true;
1783 }
1784 continue;
1785 }
1786@@ -1249,12 +1252,12 @@
1787 const int32_t radius = target_ms_d->get_conquers() + 4;
1788
1789 if (radius > dist) {
1790- field.area_military_capacity_ +=
1791+ field.area_military_capacity +=
1792 target_ms_d->get_max_number_of_soldiers() / 2 + 1;
1793 if (field.coords != immovables.at(i).coords) {
1794- field.military_loneliness_ *= static_cast<double_t>(dist) / radius;
1795+ field.military_loneliness *= static_cast<double_t>(dist) / radius;
1796 }
1797- field.military_in_constr_nearby_ += 1;
1798+ field.military_in_constr_nearby += 1;
1799 }
1800 }
1801 }
1802@@ -1265,17 +1268,17 @@
1803
1804 if (radius > dist) {
1805
1806- field.area_military_capacity_ += militarysite->max_soldier_capacity();
1807- field.area_military_presence_ += militarysite->stationed_soldiers().size();
1808+ field.area_military_capacity += militarysite->max_soldier_capacity();
1809+ field.area_military_presence += militarysite->stationed_soldiers().size();
1810
1811 if (militarysite->stationed_soldiers().empty()) {
1812- field.military_unstationed_ += 1;
1813+ field.military_unstationed += 1;
1814 } else {
1815- field.military_stationed_ += 1;
1816+ field.military_stationed += 1;
1817 }
1818
1819 if (field.coords != immovables.at(i).coords) {
1820- field.military_loneliness_ *= static_cast<double_t>(dist) / radius;
1821+ field.military_loneliness *= static_cast<double_t>(dist) / radius;
1822 }
1823 }
1824 }
1825@@ -1289,15 +1292,15 @@
1826 std::vector<ImmovableFound> immovables;
1827 Map& map = game().map();
1828 map.find_immovables(Area<FCoords>(field.coords, 5), &immovables);
1829- field.preferred_ = false;
1830- field.mines_nearby_ = 0;
1831+ field.preferred = false;
1832+ field.mines_nearby = 0;
1833 FCoords fse;
1834 map.get_brn(field.coords, &fse);
1835
1836 if (BaseImmovable const* const imm = fse.field->get_immovable()) {
1837 if (dynamic_cast<Flag const*>(imm) ||
1838 (dynamic_cast<Road const*>(imm) && (fse.field->nodecaps() & BUILDCAPS_FLAG))) {
1839- field.preferred_ = true;
1840+ field.preferred = true;
1841 }
1842 }
1843
1844@@ -1307,15 +1310,15 @@
1845 continue;
1846 }
1847 if (bld->descr().get_ismine()) {
1848- if (get_building_observer(bld->descr().name().c_str()).mines_ ==
1849+ if (get_building_observer(bld->descr().name().c_str()).mines ==
1850 field.coords.field->get_resources()) {
1851- ++field.mines_nearby_;
1852+ ++field.mines_nearby;
1853 }
1854 } else if (upcast(ConstructionSite const, cs, bld)) {
1855 if (cs->building().get_ismine()) {
1856- if (get_building_observer(cs->building().name().c_str()).mines_ ==
1857+ if (get_building_observer(cs->building().name().c_str()).mines ==
1858 field.coords.field->get_resources()) {
1859- ++field.mines_nearby_;
1860+ ++field.mines_nearby;
1861 }
1862 }
1863 }
1864@@ -1323,9 +1326,9 @@
1865 }
1866
1867 // 0 is default, and thus indicates that counting must be done
1868- if (field.same_mine_fields_nearby_ == 0) {
1869+ if (field.same_mine_fields_nearby == 0) {
1870 FindNodeMineable find_mines_spots_nearby(game(), field.coords.field->get_resources());
1871- field.same_mine_fields_nearby_ =
1872+ field.same_mine_fields_nearby =
1873 map.find_fields(Area<FCoords>(field.coords, 4), nullptr, find_mines_spots_nearby);
1874 }
1875 }
1876@@ -1336,14 +1339,14 @@
1877
1878 // Reset statistics for all buildings
1879 for (uint32_t i = 0; i < buildings_.size(); ++i) {
1880- buildings_.at(i).current_stats_ = 0;
1881- buildings_.at(i).unoccupied_count_ = 0;
1882- buildings_.at(i).unconnected_count_ = 0;
1883+ buildings_.at(i).current_stats = 0;
1884+ buildings_.at(i).unoccupied_count = 0;
1885+ buildings_.at(i).unconnected_count = 0;
1886 }
1887
1888 // Check all available productionsites
1889 for (uint32_t i = 0; i < productionsites.size(); ++i) {
1890- assert(productionsites.front().bo->cnt_built_ > 0);
1891+ assert(productionsites.front().bo->cnt_built > 0);
1892 // is connected
1893 const bool connected_to_wh =
1894 !productionsites.front().site->get_economy()->warehouses().empty();
1895@@ -1351,20 +1354,20 @@
1896 // unconnected buildings are excluded from statistics review
1897 if (connected_to_wh) {
1898 // Add statistics value
1899- productionsites.front().bo->current_stats_ +=
1900+ productionsites.front().bo->current_stats +=
1901 productionsites.front().site->get_crude_statistics();
1902
1903 // counting fishers
1904- if (productionsites.front().bo->is_fisher_) {
1905+ if (productionsites.front().bo->is_fisher) {
1906 fishers_count += 1;
1907 }
1908
1909 // Check whether this building is completely occupied
1910 if (!productionsites.front().site->can_start_working()) {
1911- productionsites.front().bo->unoccupied_count_ += 1;
1912+ productionsites.front().bo->unoccupied_count += 1;
1913 }
1914 } else {
1915- productionsites.front().bo->unconnected_count_ += 1;
1916+ productionsites.front().bo->unconnected_count += 1;
1917 }
1918
1919 // Now reorder the buildings
1920@@ -1385,7 +1388,7 @@
1921 // for mines_ also
1922 // Check all available mines
1923 for (uint32_t i = 0; i < mines_.size(); ++i) {
1924- assert(mines_.front().bo->cnt_built_ > 0);
1925+ assert(mines_.front().bo->cnt_built > 0);
1926
1927 const bool connected_to_wh =
1928 !mines_.front().site->get_economy()->warehouses().empty();
1929@@ -1393,13 +1396,13 @@
1930 // unconnected mines are excluded from statistics review
1931 if (connected_to_wh) {
1932 // Add statistics value
1933- mines_.front().bo->current_stats_ += mines_.front().site->get_statistics_percent();
1934+ mines_.front().bo->current_stats += mines_.front().site->get_statistics_percent();
1935 // Check whether this building is completely occupied
1936 if (!mines_.front().site->can_start_working()) {
1937- mines_.front().bo->unoccupied_count_ += 1;
1938+ mines_.front().bo->unoccupied_count += 1;
1939 }
1940 } else {
1941- mines_.front().bo->unconnected_count_ += 1;
1942+ mines_.front().bo->unconnected_count += 1;
1943 }
1944
1945 // Now reorder the buildings
1946@@ -1409,9 +1412,9 @@
1947
1948 // Scale statistics down
1949 for (uint32_t i = 0; i < buildings_.size(); ++i) {
1950- if ((buildings_.at(i).cnt_built_ - buildings_.at(i).unconnected_count_) > 0) {
1951- buildings_.at(i).current_stats_ /=
1952- (buildings_.at(i).cnt_built_ - buildings_.at(i).unconnected_count_);
1953+ if ((buildings_.at(i).cnt_built - buildings_.at(i).unconnected_count) > 0) {
1954+ buildings_.at(i).current_stats /=
1955+ (buildings_.at(i).cnt_built - buildings_.at(i).unconnected_count);
1956 }
1957 }
1958 }
1959@@ -1442,7 +1445,6 @@
1960 }
1961 // Just used for easy checking whether a mine or something else was built.
1962 bool mine = false;
1963- bool field_blocked = false;
1964 uint32_t consumers_nearby_count = 0;
1965 std::vector<int32_t> spots_avail;
1966 spots_avail.resize(4);
1967@@ -1487,12 +1489,12 @@
1968 // to be built. As AI does not traverse all building fields at once, these thresholds
1969 // are gradually going down until it finds a field&building that are above threshold
1970 // and this combination is used...
1971- // least_military_score_ is hardlimit, floating very slowly
1972- // target_military_score_ is always set according to latest best building (using the same
1973- // score) and quickly falling down until it reaches the least_military_score_
1974- // this one (=target_military_score_) is actually used to decide if building&field is allowed
1975+ // least_military_score is hardlimit, floating very slowly
1976+ // target_military_score is always set according to latest best building (using the same
1977+ // score) and quickly falling down until it reaches the least_military_score
1978+ // this one (=target_military_score) is actually used to decide if building&field is allowed
1979 // candidate
1980- // least_military_score_ is allowed to get bellow 100 only if there is no military site in construction
1981+ // least_military_score is allowed to get bellow 100 only if there is no military site in construction
1982 // right now in order to (try to) avoid expansion lockup
1983
1984 // Bools below are helpers to improve readability of code
1985@@ -1515,7 +1517,7 @@
1986 (vacant_mil_positions_ * 3 > static_cast<int32_t>(militarysites.size()));
1987 const int32_t kUpperLimit = 325;
1988 const int32_t kBottomLimit = 40; // to prevent too dense militarysites
1989- // modifying least_military_score_, down if more military sites are needed and vice versa
1990+ // modifying least_military_score, down if more military sites are needed and vice versa
1991 if (too_many_ms_constructionsites || too_many_vacant_mil || needs_boost_economy) {
1992 if (persistent_data->least_military_score < kUpperLimit) { //no sense to let it grow too high
1993 persistent_data->least_military_score += 20;
1994@@ -1635,12 +1637,7 @@
1995 Coords proposed_coords;
1996
1997 // Remove outdated fields from blocker list
1998- for (std::list<BlockedField>::iterator i = blocked_fields.begin(); i != blocked_fields.end();)
1999- if (i->blocked_until_ < gametime) {
2000- i = blocked_fields.erase(i);
2001- } else {
2002- ++i;
2003- }
2004+ blocked_fields.remove_expired(gametime);
2005
2006 // testing big military buildings, whether critical construction
2007 // material is available (at least in amount of
2008@@ -1651,26 +1648,27 @@
2009 }
2010
2011 // not doing this for non-military buildins
2012- if (!(bo.type == BuildingObserver::MILITARYSITE || bo.type == BuildingObserver::TRAININGSITE))
2013+ if (!(bo.type == BuildingObserver::Type::kMilitarysite ||
2014+ bo.type == BuildingObserver::Type::kTrainingsite))
2015 continue;
2016
2017 // and neither for small military buildings
2018- if (bo.type == BuildingObserver::MILITARYSITE && bo.desc->get_size() == BaseImmovable::SMALL)
2019+ if (bo.type == BuildingObserver::Type::kMilitarysite && bo.desc->get_size() == BaseImmovable::SMALL)
2020 continue;
2021
2022- bo.build_material_shortage_ = false;
2023+ bo.build_material_shortage = false;
2024
2025 // checking we have enough critical material on stock
2026- for (uint32_t m = 0; m < bo.critical_built_mat_.size(); ++m) {
2027- DescriptionIndex wt(static_cast<size_t>(bo.critical_built_mat_.at(m)));
2028+ for (uint32_t m = 0; m < bo.critical_building_material.size(); ++m) {
2029+ DescriptionIndex wt(static_cast<size_t>(bo.critical_building_material.at(m)));
2030 uint32_t treshold = 3;
2031 // generally trainingsites are more important
2032- if (bo.type == BuildingObserver::TRAININGSITE) {
2033+ if (bo.type == BuildingObserver::Type::kTrainingsite) {
2034 treshold = 2;
2035 }
2036
2037 if (get_warehoused_stock(wt) < treshold) {
2038- bo.build_material_shortage_ = true;
2039+ bo.build_material_shortage = true;
2040 break;
2041 }
2042 }
2043@@ -1681,90 +1679,91 @@
2044 BuildingObserver& bo = buildings_.at(j);
2045
2046 if (!bo.buildable(*player_)) {
2047- bo.new_building_ = BuildingNecessity::kNotNeeded;
2048- } else if (bo.type == BuildingObserver::PRODUCTIONSITE || bo.type == BuildingObserver::MINE) {
2049-
2050- bo.new_building_ = check_building_necessity(bo, PerfEvaluation::kForConstruction, gametime);
2051-
2052- if (bo.new_building_ == BuildingNecessity::kAllowed) {
2053- bo.new_building_overdue_ = 0;
2054+ bo.new_building = BuildingNecessity::kNotNeeded;
2055+ } else if (bo.type == BuildingObserver::Type::kProductionsite ||
2056+ bo.type == BuildingObserver::Type::kMine) {
2057+
2058+ bo.new_building = check_building_necessity(bo, PerfEvaluation::kForConstruction, gametime);
2059+
2060+ if (bo.new_building == BuildingNecessity::kAllowed) {
2061+ bo.new_building_overdue = 0;
2062 }
2063
2064- // Now verifying that all 'buildable' buildings has positive max_needed_preciousness_
2065- // if they have outputs, all other must have zero max_needed_preciousness_
2066- if ((bo.new_building_ == BuildingNecessity::kNeeded
2067- || bo.new_building_ == BuildingNecessity::kForced
2068- || bo.new_building_ == BuildingNecessity::kAllowed
2069- || bo.new_building_ == BuildingNecessity::kNeededPending) && !bo.outputs_.empty()) {
2070- if (bo.max_needed_preciousness_ <= 0) {
2071+ // Now verifying that all 'buildable' buildings has positive max_needed_preciousness
2072+ // if they have outputs, all other must have zero max_needed_preciousness
2073+ if ((bo.new_building == BuildingNecessity::kNeeded
2074+ || bo.new_building == BuildingNecessity::kForced
2075+ || bo.new_building == BuildingNecessity::kAllowed
2076+ || bo.new_building == BuildingNecessity::kNeededPending) && !bo.outputs.empty()) {
2077+ if (bo.max_needed_preciousness <= 0) {
2078 throw wexception("AI: Max presciousness must not be <= 0 for building: %s",
2079 bo.desc->name().c_str());
2080 }
2081- } else if (bo.new_building_ == BuildingNecessity::kForbidden) {
2082- bo.max_needed_preciousness_ = 0;
2083+ } else if (bo.new_building == BuildingNecessity::kForbidden) {
2084+ bo.max_needed_preciousness = 0;
2085 } else {
2086- // For other situations we make sure max_needed_preciousness_ is zero
2087- assert (bo.max_needed_preciousness_ == 0);
2088+ // For other situations we make sure max_needed_preciousness is zero
2089+ assert (bo.max_needed_preciousness == 0);
2090 }
2091
2092- // Positive max_needed_preciousness_ says a building type is needed
2093+ // Positive max_needed_preciousness says a building type is needed
2094 // here we increase or reset the counter
2095 // The counter is added to score when considering new building
2096- if (bo.max_needed_preciousness_ > 0) {
2097- bo.new_building_overdue_ += 1;
2098+ if (bo.max_needed_preciousness > 0) {
2099+ bo.new_building_overdue += 1;
2100 } else {
2101- bo.new_building_overdue_ = 0;
2102+ bo.new_building_overdue = 0;
2103 }
2104
2105 // Here we consider a time how long a building needed
2106 // We calculate primary_priority used later in construct_building(),
2107 // it is basically max_needed_preciousness_ plus some 'bonus' for due time
2108 // Following scenarios are possible:
2109- // a) building is needed or forced: primary_priority_ grows with time
2110- // b) building is allowed: primary_priority_ = max_needed_preciousness_ (no time consideration)
2111- // c) all other cases: primary_priority_ = 0;
2112- if (bo.max_needed_preciousness_ > 0) {
2113- if (bo.new_building_ == BuildingNecessity::kAllowed) {
2114- bo.primary_priority_ = bo.max_needed_preciousness_;
2115+ // a) building is needed or forced: primary_priority grows with time
2116+ // b) building is allowed: primary_priority = max_needed_preciousness (no time consideration)
2117+ // c) all other cases: primary_priority = 0;
2118+ if (bo.max_needed_preciousness > 0) {
2119+ if (bo.new_building == BuildingNecessity::kAllowed) {
2120+ bo.primary_priority = bo.max_needed_preciousness;
2121 } else {
2122- bo.primary_priority_ = bo.max_needed_preciousness_ +
2123- bo.max_needed_preciousness_ * bo.new_building_overdue_ / 100 +
2124- bo.new_building_overdue_ / 20;
2125+ bo.primary_priority = bo.max_needed_preciousness +
2126+ bo.max_needed_preciousness * bo.new_building_overdue / 100 +
2127+ bo.new_building_overdue / 20;
2128 }
2129 } else {
2130- bo.primary_priority_ = 0;
2131+ bo.primary_priority = 0;
2132 }
2133
2134 // Generally we don't start another building if there is some of the same type in construction
2135 // Some types of building allow two buildings in construction though, but not more
2136 // Below checks are to guarantee that there is no logical error in previous steps, or
2137 // inconsistency in AI data
2138- if (bo.new_building_ == BuildingNecessity::kNeeded
2139- || bo.new_building_ == BuildingNecessity::kForced
2140- || bo.new_building_ == BuildingNecessity::kAllowed
2141- || bo.new_building_ == BuildingNecessity::kNeededPending) {
2142- if (bo.plants_trees_ || bo.need_trees_ || bo.max_needed_preciousness_ >= 10) {
2143- if (bo.cnt_under_construction_ + bo.unoccupied_count_ > 1) {
2144+ if (bo.new_building == BuildingNecessity::kNeeded
2145+ || bo.new_building == BuildingNecessity::kForced
2146+ || bo.new_building == BuildingNecessity::kAllowed
2147+ || bo.new_building == BuildingNecessity::kNeededPending) {
2148+ if (bo.plants_trees || bo.need_trees || bo.max_needed_preciousness >= 10) {
2149+ if (bo.cnt_under_construction + bo.unoccupied_count > 1) {
2150 throw wexception("AI inconsistency: %s: total_count %d > 1, unoccupied: %d",
2151- bo.name, bo.total_count(), bo.unoccupied_count_);
2152+ bo.name, bo.total_count(), bo.unoccupied_count);
2153 }
2154 } else {
2155- if (bo.cnt_under_construction_ + bo.unoccupied_count_ > 0) {
2156+ if (bo.cnt_under_construction + bo.unoccupied_count > 0) {
2157 throw wexception("AI inconsistency: %s: total_count %d > 0, unoccupied: %d",
2158- bo.name, bo.total_count(), bo.unoccupied_count_);
2159+ bo.name, bo.total_count(), bo.unoccupied_count);
2160 }
2161 }
2162 }
2163
2164- } else if (bo.type == BuildingObserver::MILITARYSITE) {
2165- bo.new_building_ = check_building_necessity(bo.desc->get_size(), gametime);
2166- } else if (bo.type == BuildingObserver::TRAININGSITE) {
2167- bo.new_building_ = check_building_necessity(bo, PerfEvaluation::kForConstruction, gametime);
2168+ } else if (bo.type == BuildingObserver::Type::kMilitarysite) {
2169+ bo.new_building = check_building_necessity(bo.desc->get_size(), gametime);
2170+ } else if (bo.type == BuildingObserver::Type::kTrainingsite) {
2171+ bo.new_building = check_building_necessity(bo, PerfEvaluation::kForConstruction, gametime);
2172 } else if (bo.aimode_limit_status() != AiModeBuildings::kAnotherAllowed) {
2173- bo.new_building_ = BuildingNecessity::kNotNeeded;
2174+ bo.new_building = BuildingNecessity::kNotNeeded;
2175 } else {
2176- bo.new_building_ = BuildingNecessity::kAllowed;
2177- bo.primary_priority_ = 0;
2178+ bo.new_building = BuildingNecessity::kAllowed;
2179+ bo.primary_priority = 0;
2180 }
2181 }
2182
2183@@ -1774,22 +1773,12 @@
2184 ++i) {
2185 BuildableField* const bf = *i;
2186
2187- if (bf->field_info_expiration_ < gametime) {
2188+ if (bf->field_info_expiration < gametime) {
2189 continue;
2190 }
2191
2192 // Continue if field is blocked at the moment
2193- field_blocked = false;
2194-
2195- for (std::list<BlockedField>::iterator j = blocked_fields.begin(); j != blocked_fields.end();
2196- ++j) {
2197- if (j->coords == bf->coords) {
2198- field_blocked = true;
2199- }
2200- }
2201-
2202- // continue;
2203- if (field_blocked) {
2204+ if (blocked_fields.is_blocked(bf->coords)) {
2205 continue;
2206 }
2207
2208@@ -1803,15 +1792,15 @@
2209 continue;
2210 }
2211
2212- if (bo.new_building_ == BuildingNecessity::kNotNeeded ||
2213- bo.new_building_ == BuildingNecessity::kNeededPending ||
2214- bo.new_building_ == BuildingNecessity::kForbidden) {
2215+ if (bo.new_building == BuildingNecessity::kNotNeeded ||
2216+ bo.new_building == BuildingNecessity::kNeededPending ||
2217+ bo.new_building == BuildingNecessity::kForbidden) {
2218 continue;
2219 }
2220
2221- assert (bo.new_building_ == BuildingNecessity::kForced ||
2222- bo.new_building_ == BuildingNecessity::kNeeded ||
2223- bo.new_building_ == BuildingNecessity::kAllowed);
2224+ assert (bo.new_building == BuildingNecessity::kForced ||
2225+ bo.new_building == BuildingNecessity::kNeeded ||
2226+ bo.new_building == BuildingNecessity::kAllowed);
2227
2228 assert(bo.aimode_limit_status() == AiModeBuildings::kAnotherAllowed);
2229
2230@@ -1821,8 +1810,8 @@
2231 }
2232
2233 // testing for reserved ports
2234- if (!bo.is_port_) {
2235- if (port_reserved_coords.count(coords_hash(bf->coords)) > 0) {
2236+ if (!bo.is_port) {
2237+ if (port_reserved_coords.count(bf->coords.hash()) > 0) {
2238 continue;
2239 }
2240 }
2241@@ -1831,73 +1820,73 @@
2242 continue;
2243 } // add randomnes and ease AI
2244
2245- if (bo.type == BuildingObserver::MINE) {
2246+ if (bo.type == BuildingObserver::Type::kMine) {
2247 continue;
2248 }
2249
2250 // here we do an exemption for lumberjacks, mainly in early stages of game
2251 // sometimes the first one is not built and AI waits too long for second attempt
2252- if (gametime - bo.construction_decision_time_ < kBuildingMinInterval && !bo.need_trees_) {
2253+ if (gametime - bo.construction_decision_time < kBuildingMinInterval && !bo.need_trees) {
2254 continue;
2255 }
2256
2257- if (!(bo.type == BuildingObserver::MILITARYSITE) && bo.cnt_under_construction_ >= 2) {
2258+ if (!(bo.type == BuildingObserver::Type::kMilitarysite) && bo.cnt_under_construction >= 2) {
2259 continue;
2260 }
2261
2262 int32_t prio = 0; // score of a bulding on a field
2263
2264- if (bo.type == BuildingObserver::PRODUCTIONSITE) {
2265+ if (bo.type == BuildingObserver::Type::kProductionsite) {
2266
2267 // this can be only a well (as by now)
2268- if (bo.mines_water_) {
2269+ if (bo.mines_water) {
2270
2271- if (bo.new_building_ == BuildingNecessity::kForced) {
2272- assert (bo.total_count() - bo.unconnected_count_ == 0);
2273+ if (bo.new_building == BuildingNecessity::kForced) {
2274+ assert (bo.total_count() - bo.unconnected_count == 0);
2275 }
2276
2277- if (bf->ground_water_ < 2) {
2278+ if (bf->ground_water < 2) {
2279 continue;
2280 }
2281
2282- prio = bo.primary_priority_;
2283+ prio = bo.primary_priority;
2284
2285 // keep wells more distant
2286- if (bf->producers_nearby_.at(bo.outputs_.at(0)) > 2) {
2287+ if (bf->producers_nearby.at(bo.outputs.at(0)) > 2) {
2288 continue;
2289 }
2290
2291 // one well is forced
2292- if (bo.new_building_ == BuildingNecessity::kForced) {
2293+ if (bo.new_building == BuildingNecessity::kForced) {
2294 prio += 200;
2295 }
2296
2297- prio += bf->ground_water_ - 2;
2298-
2299- } else if (bo.need_trees_) { // LUMBERJACS
2300-
2301- prio = bo.primary_priority_;
2302+ prio += bf->ground_water - 2;
2303+
2304+ } else if (bo.need_trees) { // LUMBERJACS
2305+
2306+ prio = bo.primary_priority;
2307
2308 prio += -20 + 200 / (bo.total_count() + 1);
2309
2310- if (bo.new_building_ == BuildingNecessity::kForced) {
2311+ if (bo.new_building == BuildingNecessity::kForced) {
2312 prio *= 2;
2313- } else if (bf->trees_nearby_ < 2 && bf->supporters_nearby_.at(bo.outputs_.at(0) == 0)) {
2314+ } else if (bf->trees_nearby < 2 && bf->supporters_nearby.at(bo.outputs.at(0) == 0)) {
2315 continue;
2316 }
2317
2318 // consider cutters and rangers nearby
2319- prio -= bf->producers_nearby_.at(bo.outputs_.at(0)) * 20;
2320- prio += bf->supporters_nearby_.at(bo.outputs_.at(0)) * 5;
2321-
2322- prio += 2 * bf->trees_nearby_;
2323-
2324- } else if (bo.need_rocks_) {
2325+ prio -= bf->producers_nearby.at(bo.outputs.at(0)) * 20;
2326+ prio += bf->supporters_nearby.at(bo.outputs.at(0)) * 5;
2327+
2328+ prio += 2 * bf->trees_nearby;
2329+
2330+ } else if (bo.need_rocks) {
2331
2332 // Quarries are generally to be built everywhere where rocks are
2333 // no matter the need for granite, as rocks are considered an obstacle
2334 // to expansion
2335- prio = 2 * bf->rocks_nearby_;
2336+ prio = 2 * bf->rocks_nearby;
2337
2338 // value is initialized with 1 but minimal value that can be
2339 // calculated is 11
2340@@ -1905,75 +1894,75 @@
2341 continue;
2342 }
2343
2344- if (bo.total_count() - bo.unconnected_count_ == 0) {
2345+ if (bo.total_count() - bo.unconnected_count == 0) {
2346 prio += 150;
2347 }
2348
2349 if (bo.stocklevel_time < game().get_gametime() - 5 * 1000) {
2350- bo.stocklevel_ = get_stocklevel(static_cast<size_t>(bo.production_hint_));
2351+ bo.stocklevel = get_stocklevel(static_cast<size_t>(bo.production_hint));
2352 bo.stocklevel_time = game().get_gametime();
2353 }
2354
2355- if (bo.stocklevel_ == 0) {
2356+ if (bo.stocklevel == 0) {
2357 prio *= 2;
2358 }
2359
2360 // to prevent to many quaries on one spot
2361- prio = prio - 50 * bf->producers_nearby_.at(bo.outputs_.at(0));
2362-
2363- } else if (bo.is_hunter_) {
2364-
2365- if (bf->critters_nearby_ < 5) {
2366+ prio = prio - 50 * bf->producers_nearby.at(bo.outputs.at(0));
2367+
2368+ } else if (bo.is_hunter) {
2369+
2370+ if (bf->critters_nearby < 5) {
2371 continue;
2372 }
2373
2374- if (bo.new_building_ == BuildingNecessity::kForced) {
2375+ if (bo.new_building == BuildingNecessity::kForced) {
2376 prio += 20;
2377 }
2378
2379 // Overdue priority here
2380- prio += bo.primary_priority_;
2381+ prio += bo.primary_priority;
2382
2383- prio += bf->supporters_nearby_.at(bo.outputs_.at(0)) * 5;
2384+ prio += bf->supporters_nearby.at(bo.outputs.at(0)) * 5;
2385
2386 prio +=
2387- (bf->critters_nearby_ * 3) - 8 - 5 * bf->producers_nearby_.at(bo.outputs_.at(0));
2388-
2389- } else if (bo.is_fisher_) { // fisher
2390-
2391- if (bf->water_nearby_ < 2 || bf->fish_nearby_ < 2) {
2392+ (bf->critters_nearby * 3) - 8 - 5 * bf->producers_nearby.at(bo.outputs.at(0));
2393+
2394+ } else if (bo.is_fisher) { // fisher
2395+
2396+ if (bf->water_nearby < 2 || bf->fish_nearby < 2) {
2397 continue;
2398 }
2399
2400- if (bo.new_building_ == BuildingNecessity::kForced) {
2401+ if (bo.new_building == BuildingNecessity::kForced) {
2402 prio += 20;
2403 }
2404
2405 // Overdue priority here
2406- prio += bo.primary_priority_;
2407-
2408- prio -= bf->producers_nearby_.at(bo.outputs_.at(0)) * 20;
2409- prio += bf->supporters_nearby_.at(bo.outputs_.at(0)) * 10;
2410-
2411- prio += -5 + bf->fish_nearby_;
2412-
2413- } else if (bo.production_hint_ >= 0) {
2414- if (bo.plants_trees_) {
2415- assert (bo.cnt_target_ > 0);
2416+ prio += bo.primary_priority;
2417+
2418+ prio -= bf->producers_nearby.at(bo.outputs.at(0)) * 20;
2419+ prio += bf->supporters_nearby.at(bo.outputs.at(0)) * 10;
2420+
2421+ prio += -5 + bf->fish_nearby;
2422+
2423+ } else if (bo.production_hint >= 0) {
2424+ if (bo.plants_trees) {
2425+ assert (bo.cnt_target > 0);
2426 } else {
2427- bo.cnt_target_ =
2428+ bo.cnt_target =
2429 1 + static_cast<int32_t>(mines_.size() + productionsites.size()) / 50;
2430 }
2431
2432 // They have no own primary priority
2433- assert(bo.primary_priority_ == 0);
2434-
2435- if (bo.plants_trees_) { // RANGERS
2436-
2437- assert(bo.new_building_ == BuildingNecessity::kNeeded);
2438+ assert(bo.primary_priority == 0);
2439+
2440+ if (bo.plants_trees) { // RANGERS
2441+
2442+ assert(bo.new_building == BuildingNecessity::kNeeded);
2443
2444 // if there are too many trees nearby
2445- if (bf->trees_nearby_ > 25 && bo.total_count() >= 1) {
2446+ if (bf->trees_nearby > 25 && bo.total_count() >= 1) {
2447 continue;
2448 }
2449
2450@@ -1989,107 +1978,107 @@
2451 }
2452
2453 // considering producers
2454- prio += std::min<uint8_t>(bf->producers_nearby_.at(bo.production_hint_), 4) * 5 -
2455+ prio += std::min<uint8_t>(bf->producers_nearby.at(bo.production_hint), 4) * 5 -
2456 new_buildings_stop_ * 15 -
2457- bf->space_consumers_nearby_ * 5 -
2458- bf->rocks_nearby_ / 3 +
2459- bf->trees_nearby_ / 2 +
2460- std::min<uint8_t>(bf->supporters_nearby_.at(bo.production_hint_), 4) * 3;
2461+ bf->space_consumers_nearby * 5 -
2462+ bf->rocks_nearby / 3 +
2463+ bf->trees_nearby / 2 +
2464+ std::min<uint8_t>(bf->supporters_nearby.at(bo.production_hint), 4) * 3;
2465
2466 } else { // FISH BREEDERS and GAME KEEPERS
2467
2468 // especially for fish breeders
2469- if (bo.need_water_ && (bf->water_nearby_ < 6 || bf->fish_nearby_ < 6)) {
2470+ if (bo.need_water && (bf->water_nearby < 6 || bf->fish_nearby < 6)) {
2471 continue;
2472 }
2473- if (bo.need_water_) {
2474- prio += (-6 + bf->water_nearby_) / 3;
2475- prio += (-6 + bf->fish_nearby_) / 3;
2476+ if (bo.need_water) {
2477+ prio += (-6 + bf->water_nearby) / 3;
2478+ prio += (-6 + bf->fish_nearby) / 3;
2479 }
2480
2481- if ((bo.total_count() - bo.unconnected_count_) > bo.cnt_target_) {
2482+ if ((bo.total_count() - bo.unconnected_count) > bo.cnt_target) {
2483 continue;
2484 }
2485
2486 if (bo.stocklevel_time < game().get_gametime() - 5 * 1000) {
2487- bo.stocklevel_ =
2488- get_stocklevel_by_hint(static_cast<size_t>(bo.production_hint_));
2489+ bo.stocklevel =
2490+ get_stocklevel_by_hint(static_cast<size_t>(bo.production_hint));
2491 bo.stocklevel_time = game().get_gametime();
2492 }
2493- if (bo.stocklevel_ > 50) {
2494+ if (bo.stocklevel > 50) {
2495 continue;
2496 }
2497
2498 if (bo.total_count() == 0) {
2499 prio += 100;
2500- } else if (!bo.need_water_) {
2501+ } else if (!bo.need_water) {
2502 prio += 10 / bo.total_count();
2503 }
2504
2505- prio += bf->producers_nearby_.at(bo.production_hint_) * 10;
2506- prio -= bf->supporters_nearby_.at(bo.production_hint_) * 20;
2507+ prio += bf->producers_nearby.at(bo.production_hint) * 10;
2508+ prio -= bf->supporters_nearby.at(bo.production_hint) * 20;
2509
2510- if (bf->enemy_nearby_) {
2511+ if (bf->enemy_nearby) {
2512 prio -= 5;
2513 }
2514 }
2515
2516- } else if (bo.recruitment_ && !new_buildings_stop_) {
2517+ } else if (bo.recruitment && !new_buildings_stop_) {
2518 // this will depend on number of mines_ and productionsites
2519 if (static_cast<int32_t>((productionsites.size() + mines_.size()) / 30) >
2520 bo.total_count() &&
2521- (bo.cnt_under_construction_ + bo.unoccupied_count_) == 0 &&
2522+ (bo.cnt_under_construction + bo.unoccupied_count) == 0 &&
2523 // but only if current buildings are utilized enough
2524- (bo.total_count() == 0 || bo.current_stats_ > 60)) {
2525+ (bo.total_count() == 0 || bo.current_stats > 60)) {
2526 prio = 10;
2527 }
2528 } else { // finally normal productionsites
2529- assert (bo.production_hint_ < 0);
2530+ assert (bo.production_hint < 0);
2531
2532- if (bo.new_building_ == BuildingNecessity::kForced) {
2533+ if (bo.new_building == BuildingNecessity::kForced) {
2534 prio += 150;
2535- } else if (bo.is_shipyard_) {
2536- assert (bo.new_building_ == BuildingNecessity::kAllowed);
2537+ } else if (bo.is_shipyard) {
2538+ assert (bo.new_building == BuildingNecessity::kAllowed);
2539 if (!seafaring_economy) {
2540 continue;
2541 }
2542 } else {
2543- assert (bo.new_building_ == BuildingNecessity::kNeeded);
2544+ assert (bo.new_building == BuildingNecessity::kNeeded);
2545 }
2546
2547 // Overdue priority here
2548- prio += bo.primary_priority_;
2549+ prio += bo.primary_priority;
2550
2551 // we check separatelly buildings with no inputs and some inputs
2552- if (bo.inputs_.empty()) {
2553+ if (bo.inputs.empty()) {
2554
2555- if (bo.space_consumer_) {
2556+ if (bo.space_consumer) {
2557 // we dont like trees nearby
2558- prio += 1 - bf->trees_nearby_ / 15;
2559+ prio += 1 - bf->trees_nearby / 15;
2560 // we attempt to cluster space consumers together
2561- prio += bf->space_consumers_nearby_ * 2;
2562+ prio += bf->space_consumers_nearby * 2;
2563 // and be far from rangers
2564- prio += 1 - bf->rangers_nearby_ * 3;
2565+ prio += 1 - bf->rangers_nearby * 3;
2566 } else {
2567 // leave some free space between them
2568- prio -= bf->producers_nearby_.at(bo.outputs_.at(0)) * 5;
2569+ prio -= bf->producers_nearby.at(bo.outputs.at(0)) * 5;
2570 }
2571
2572- if (bo.space_consumer_ && !bf->water_nearby_) { // not close to water
2573+ if (bo.space_consumer && !bf->water_nearby) { // not close to water
2574 prio += 1;
2575 }
2576
2577- if (bo.space_consumer_ &&
2578- !bf->unowned_mines_spots_nearby_) { // not close to mountains
2579+ if (bo.space_consumer &&
2580+ !bf->unowned_mines_spots_nearby) { // not close to mountains
2581 prio += 1;
2582 }
2583 }
2584
2585- else if (bo.is_shipyard_) {
2586+ else if (bo.is_shipyard) {
2587 // for now AI builds only one shipyard
2588- if (bf->water_nearby_ > 3 && (bo.total_count() - bo.unconnected_count_) == 0 &&
2589+ if (bf->water_nearby > 3 && (bo.total_count() - bo.unconnected_count) == 0 &&
2590 seafaring_economy) {
2591- prio += productionsites.size() * 5 + bf->water_nearby_;
2592+ prio += productionsites.size() * 5 + bf->water_nearby;
2593 }
2594 }
2595
2596@@ -2109,8 +2098,8 @@
2597 //+1 if any consumers_ are nearby
2598 consumers_nearby_count = 0;
2599
2600- for (size_t k = 0; k < bo.outputs_.size(); ++k)
2601- consumers_nearby_count += bf->consumers_nearby_.at(bo.outputs_.at(k));
2602+ for (size_t k = 0; k < bo.outputs.size(); ++k)
2603+ consumers_nearby_count += bf->consumers_nearby.at(bo.outputs.at(k));
2604
2605 if (consumers_nearby_count > 0) {
2606 prio += 1;
2607@@ -2118,18 +2107,18 @@
2608 }
2609
2610 // Consider border with exemption of some huts
2611- if (! (bo.need_trees_ || bo.need_water_ || bo.is_fisher_)) {
2612+ if (! (bo.need_trees || bo.need_water || bo.is_fisher)) {
2613 prio = recalc_with_border_range(*bf, prio);
2614- } else if (bf->near_border_
2615+ } else if (bf->near_border
2616 &&
2617- (bo.need_trees_ || bo.need_water_)) {
2618+ (bo.need_trees || bo.need_water)) {
2619 prio /= 2;
2620 }
2621
2622 } // production sites done
2623- else if (bo.type == BuildingObserver::MILITARYSITE) {
2624+ else if (bo.type == BuildingObserver::Type::kMilitarysite) {
2625
2626- if (!bf->unowned_land_nearby_) {
2627+ if (!(bf->unowned_land_nearby || bf->enemy_nearby)) {
2628 continue;
2629 }
2630
2631@@ -2138,14 +2127,14 @@
2632 }
2633
2634 // This is another restriction of military building - but general
2635- if (bf->enemy_nearby_ && bo.fighting_type_) {
2636- ;
2637- } // it is ok, go on
2638- else if (bf->unowned_mines_spots_nearby_ > 2 &&
2639- (bo.mountain_conqueror_ || bo.expansion_type_)) {
2640- ;
2641- } // it is ok, go on
2642- else if (bo.expansion_type_) {
2643+ if (bf->enemy_nearby && bo.fighting_type) {
2644+ ;
2645+ } // it is ok, go on
2646+ else if (bf->unowned_mines_spots_nearby > 2 &&
2647+ (bo.mountain_conqueror || bo.expansion_type)) {
2648+ ;
2649+ } // it is ok, go on
2650+ else if (bo.expansion_type) {
2651 if (bo.desc->get_size() == 2 && gametime % 2 >= 1) {
2652 continue;
2653 }
2654@@ -2159,35 +2148,48 @@
2655 // score here is a compound of various input values
2656 // usually resources in vicinity, but when enemy is nearby
2657 // additional bonus is added
2658- if (bf->enemy_nearby_) {
2659- prio += bf->military_loneliness_ / 3;
2660- prio += (20 - bf->area_military_capacity_) * 10;
2661- prio -= bo.build_material_shortage_ * 50;
2662- prio -= (bf->military_in_constr_nearby_ + bf->military_unstationed_) * 50;
2663+ if (bf->enemy_nearby) {
2664+ prio += bf->military_loneliness / 3;
2665+ prio += (20 - bf->area_military_capacity) * 10;
2666+ prio -= bo.build_material_shortage * 50;
2667+ prio -= (bf->military_in_constr_nearby + bf->military_unstationed) * 50;
2668 } else {
2669- if (bf->near_border_) {
2670+ if (bf->near_border) {
2671 prio += 50;
2672- prio -= bo.build_material_shortage_ * 150;
2673+ prio -= bo.build_material_shortage * 150;
2674 } else {
2675- prio -= bo.build_material_shortage_ * 500; // prohibitive
2676+ prio -= bo.build_material_shortage * 500; // prohibitive
2677 }
2678- prio -= (bf->military_in_constr_nearby_ + bf->military_unstationed_) * 150;
2679+ prio -= (bf->military_in_constr_nearby + bf->military_unstationed) * 150;
2680 prio += (5 - bf->own_military_sites_nearby_()) * 15;
2681 }
2682- prio += bf->unowned_land_nearby_ * resource_necessity_territory_ / 100;
2683- prio += bf->unowned_mines_spots_nearby_ * resource_necessity_mines_ / 100;
2684- prio += ((bf->unowned_mines_spots_nearby_ > 0) ? 35 : 0) *
2685+ prio += bf->unowned_land_nearby * resource_necessity_territory_ / 100;
2686+ prio += bf->unowned_mines_spots_nearby * resource_necessity_mines_ / 100;
2687+ prio += ((bf->unowned_mines_spots_nearby > 0) ? 35 : 0) *
2688 resource_necessity_mines_ / 100;
2689- prio += bf->rocks_nearby_ / 2;
2690- prio += bf->water_nearby_;
2691- prio += bf->distant_water_ * resource_necessity_water_needed_ / 100;
2692- prio += bf->military_loneliness_ / 10;
2693- prio += bf->trees_nearby_ / 3;
2694- if (bf->portspace_nearby_ == ExtendedBool::kTrue) prio += 25;
2695+ prio += bf->rocks_nearby / 2;
2696+ prio += bf->water_nearby;
2697+ prio += bf->distant_water * resource_necessity_water_needed_ / 100;
2698+ prio += bf->military_loneliness / 10;
2699+ prio += bf->trees_nearby / 3;
2700+ if (bf->portspace_nearby == ExtendedBool::kTrue) {
2701+ if (num_ports == 0) {
2702+ prio += 100;
2703+ } else {
2704+ prio += 25;
2705+ }
2706+ }
2707+ // sometimes expansion is stalled and this is to help boost it
2708+ if (msites_in_constr() == 0 && vacant_mil_positions_ <= 2) {
2709+ prio += 10;
2710+ if (bf->enemy_nearby) {
2711+ prio += 20;
2712+ }
2713+ }
2714
2715 // additional score for bigger buildings
2716 int32_t prio_for_size = bo.desc->get_size() - 1;
2717- if (bf->enemy_nearby_) {
2718+ if (bf->enemy_nearby) {
2719 prio_for_size *= 30;
2720 } else {
2721 prio_for_size *= 5;
2722@@ -2198,18 +2200,18 @@
2723 if (prio <= persistent_data->target_military_score) {
2724 continue;
2725 }
2726- } else if (bo.type == BuildingObserver::WAREHOUSE) {
2727+ } else if (bo.type == BuildingObserver::Type::kWarehouse) {
2728
2729 // exclude spots on border
2730- if (bf->near_border_ && !bo.is_port_) {
2731- continue;
2732- }
2733-
2734- if (!bf->is_portspace_ && bo.is_port_) {
2735- continue;
2736- }
2737-
2738- if (bo.cnt_under_construction_ > 0) {
2739+ if (bf->near_border && !bo.is_port) {
2740+ continue;
2741+ }
2742+
2743+ if (!bf->is_portspace && bo.is_port) {
2744+ continue;
2745+ }
2746+
2747+ if (bo.cnt_under_construction > 0) {
2748 continue;
2749 }
2750
2751@@ -2229,8 +2231,8 @@
2752 }
2753
2754 // But we still can built a port if it is first one
2755- if (bo.is_port_ && bo.total_count() == 0 && productionsites.size() > 5 &&
2756- !bf->enemy_nearby_ && bf->is_portspace_ && seafaring_economy) {
2757+ if (bo.is_port && bo.total_count() == 0 && productionsites.size() > 5 &&
2758+ !bf->enemy_nearby && bf->is_portspace && seafaring_economy) {
2759 prio += productionsites.size();
2760 warehouse_needed = true;
2761 }
2762@@ -2240,7 +2242,7 @@
2763 }
2764
2765 // we prefer ports to a normal warehouse
2766- if (bo.is_port_) {
2767+ if (bo.is_port) {
2768 prio += 15;
2769 }
2770
2771@@ -2263,25 +2265,25 @@
2772 prio += nearest_distance - 30;
2773
2774 // dont be close to enemies
2775- if (bf->enemy_nearby_) {
2776+ if (bf->enemy_nearby) {
2777 prio -= 40;
2778 }
2779
2780 // being too close to a border is not good either
2781- if (bf->unowned_land_nearby_ && !bo.is_port_ && prio > 0) {
2782+ if (bf->unowned_land_nearby && !bo.is_port && prio > 0) {
2783 prio /= 2;
2784 prio -= 10;
2785 }
2786
2787- } else if (bo.type == BuildingObserver::TRAININGSITE) {
2788+ } else if (bo.type == BuildingObserver::Type::kTrainingsite) {
2789
2790 // Even if a site is forced it has kNeeded necessity now
2791- assert(bo.primary_priority_ > 0 && bo.new_building_ == BuildingNecessity::kNeeded);
2792+ assert(bo.primary_priority > 0 && bo.new_building == BuildingNecessity::kNeeded);
2793
2794- prio = bo.primary_priority_;
2795+ prio = bo.primary_priority;
2796
2797 // for spots close to a border
2798- if (bf->near_border_) {
2799+ if (bf->near_border) {
2800 prio -= 5;
2801 }
2802
2803@@ -2291,18 +2293,18 @@
2804 }
2805
2806 // take care about borders and enemies
2807- if (bf->enemy_nearby_) {
2808+ if (bf->enemy_nearby) {
2809 prio -= 20;
2810 }
2811
2812- if (bf->unowned_land_nearby_) {
2813+ if (bf->unowned_land_nearby) {
2814 prio -= 15;
2815 }
2816 }
2817
2818 // think of space consuming buildings nearby like farms or vineyards
2819- if (bo.type != BuildingObserver::MILITARYSITE) {
2820- prio -= bf->space_consumers_nearby_ * 10;
2821+ if (bo.type != BuildingObserver::Type::kMilitarysite) {
2822+ prio -= bf->space_consumers_nearby * 10;
2823 }
2824
2825 // Stop here, if priority is 0 or less.
2826@@ -2311,14 +2313,14 @@
2827 }
2828
2829 // testing also vicinity
2830- if (!bo.is_port_) {
2831- if (port_reserved_coords.count(coords_hash(bf->coords)) > 0) {
2832+ if (!bo.is_port) {
2833+ if (port_reserved_coords.count(bf->coords.hash()) > 0) {
2834 continue;
2835 }
2836 }
2837
2838 // Prefer road side fields
2839- prio += bf->preferred_ ? 5 : 0;
2840+ prio += bf->preferred ? 5 : 0;
2841
2842 // don't waste good land for small huts
2843 const bool space_stress =
2844@@ -2326,20 +2328,20 @@
2845 ||
2846 spots_avail.at(BUILDCAPS_BIG) < 5);
2847
2848- if (space_stress && bo.type == BuildingObserver::MILITARYSITE) {
2849- prio -= (bf->max_buildcap_nearby_ - bo.desc->get_size()) * 3;
2850+ if (space_stress && bo.type == BuildingObserver::Type::kMilitarysite) {
2851+ prio -= (bf->max_buildcap_nearby - bo.desc->get_size()) * 3;
2852 } else if (space_stress) {
2853- prio -= (bf->max_buildcap_nearby_ - bo.desc->get_size()) * 10;
2854+ prio -= (bf->max_buildcap_nearby - bo.desc->get_size()) * 10;
2855 } else {
2856- prio -= (bf->max_buildcap_nearby_ - bo.desc->get_size()) * 3;
2857+ prio -= (bf->max_buildcap_nearby - bo.desc->get_size()) * 3;
2858 }
2859
2860 // prefer vicinity of ports (with exemption of warehouses)
2861- if (bf->port_nearby_ && bo.type == BuildingObserver::MILITARYSITE) {
2862+ if (bf->port_nearby && bo.type == BuildingObserver::Type::kMilitarysite) {
2863 prio *= 2;
2864 }
2865
2866- if (bo.type != BuildingObserver::MILITARYSITE && highest_nonmil_prio_ < prio) {
2867+ if (bo.type != BuildingObserver::Type::kMilitarysite && highest_nonmil_prio_ < prio) {
2868 highest_nonmil_prio_ = prio;
2869 }
2870
2871@@ -2363,26 +2365,26 @@
2872 for (BuildingObserver& bo : buildings_) {
2873 if (productionsites.size() <= 8) break;
2874
2875- if (bo.type != BuildingObserver::MINE) {
2876- continue;
2877- }
2878-
2879- if (gametime - bo.construction_decision_time_ < kBuildingMinInterval) {
2880- continue;
2881- }
2882-
2883- assert(bo.new_building_ != BuildingNecessity::kAllowed);
2884+ if (bo.type != BuildingObserver::Type::kMine) {
2885+ continue;
2886+ }
2887+
2888+ if (gametime - bo.construction_decision_time < kBuildingMinInterval) {
2889+ continue;
2890+ }
2891+
2892+ assert(bo.new_building != BuildingNecessity::kAllowed);
2893
2894 // skip if a mine is not required
2895- if (!(bo.new_building_ == BuildingNecessity::kNeeded ||
2896- bo.new_building_ == BuildingNecessity::kForced)) {
2897+ if (!(bo.new_building == BuildingNecessity::kNeeded ||
2898+ bo.new_building == BuildingNecessity::kForced)) {
2899 continue;
2900 }
2901
2902 // this is penalty if there are existing mines too close
2903 // it is treated as multiplicator for count of near mines
2904 uint32_t nearness_penalty = 0;
2905- if ((mines_per_type[bo.mines_].in_construction + mines_per_type[bo.mines_].finished) ==
2906+ if ((mines_per_type[bo.mines].in_construction + mines_per_type[bo.mines].finished) ==
2907 0) {
2908 nearness_penalty = 0;
2909 } else {
2910@@ -2391,9 +2393,9 @@
2911
2912 // bonus score to prefer if too few mines
2913 uint32_t bonus_score = 0;
2914- if ((mines_per_type[bo.mines_].in_construction + mines_per_type[bo.mines_].finished) ==
2915+ if ((mines_per_type[bo.mines].in_construction + mines_per_type[bo.mines].finished) ==
2916 0) {
2917- bonus_score = 2 * bo.primary_priority_;
2918+ bonus_score = 2 * bo.primary_priority;
2919 }
2920
2921 // iterating over fields
2922@@ -2403,18 +2405,18 @@
2923
2924 MineableField* const mf = *j;
2925
2926- if (mf->field_info_expiration_ <= gametime) {
2927+ if (mf->field_info_expiration <= gametime) {
2928 continue;
2929 }
2930
2931- if (mf->coords.field->get_resources() != bo.mines_) {
2932+ if (mf->coords.field->get_resources() != bo.mines) {
2933 continue;
2934 }
2935
2936 int32_t prio = 0;
2937 MapRegion<Area<FCoords>> mr(map, Area<FCoords>(mf->coords, 2));
2938 do {
2939- if (bo.mines_ == mr.location().field->get_resources()) {
2940+ if (bo.mines == mr.location().field->get_resources()) {
2941 prio += mr.location().field->get_resources_amount();
2942 }
2943 } while (mr.advance(map));
2944@@ -2427,41 +2429,30 @@
2945 }
2946
2947 // applying nearnes penalty
2948- prio -= mf->mines_nearby_ * nearness_penalty;
2949+ prio -= mf->mines_nearby * nearness_penalty;
2950
2951 // applying bonus score
2952 prio += bonus_score;
2953
2954 // applying max needed
2955- prio += bo.primary_priority_;
2956+ prio += bo.primary_priority;
2957
2958 // prefer mines in the middle of mine fields of the
2959 // same type, so we add a small bonus here
2960 // depending on count of same mines nearby,
2961 // though this does not reflects how many resources
2962 // are (left) in nearby mines
2963- prio += mf->same_mine_fields_nearby_;
2964+ prio += mf->same_mine_fields_nearby;
2965
2966 // Continue if field is blocked at the moment
2967- bool blocked = false;
2968-
2969- for (std::list<BlockedField>::iterator k = blocked_fields.begin();
2970- k != blocked_fields.end();
2971- ++k)
2972- if ((*j)->coords == k->coords) {
2973- blocked = true;
2974- break;
2975- }
2976-
2977- if (blocked) {
2978-
2979+ if (blocked_fields.is_blocked(mf->coords)) {
2980 continue;
2981 }
2982
2983 // Prefer road side fields
2984- prio += mf->preferred_ ? 1 : 0;
2985+ prio += mf->preferred ? 1 : 0;
2986
2987- prio += bo.primary_priority_;
2988+ prio += bo.primary_priority;
2989
2990 if (prio > proposed_priority) {
2991 best_building = &bo;
2992@@ -2484,28 +2475,30 @@
2993 return false;
2994 }
2995
2996- if (best_building->type == BuildingObserver::MILITARYSITE) {
2997+ if (best_building->type == BuildingObserver::Type::kMilitarysite) {
2998 persistent_data->target_military_score = proposed_priority;
2999 }
3000
3001 // send the command to construct a new building
3002 game().send_player_build(player_number(), proposed_coords, best_building->id);
3003- BlockedField blocked(
3004- game().map().get_fcoords(proposed_coords), game().get_gametime() + 120000); // two minutes
3005- blocked_fields.push_back(blocked);
3006+ blocked_fields.add(proposed_coords, game().get_gametime() + 2 * 60 * 1000);
3007
3008- // resetting new_building_overdue_
3009- best_building->new_building_overdue_ = 0;
3010+ // resetting new_building_overdue
3011+ best_building->new_building_overdue = 0;
3012
3013 // we block also nearby fields
3014 // if farms and so on, for quite a long time
3015 // if military sites only for short time for AI can update information on near buildable fields
3016- if ((best_building->space_consumer_ && !best_building->plants_trees_) ||
3017- best_building->type == BuildingObserver::MILITARYSITE) {
3018+ if ((best_building->space_consumer && !best_building->plants_trees) ||
3019+ best_building->type == BuildingObserver::Type::kMilitarysite) {
3020 uint32_t block_time = 0;
3021 uint32_t block_area = 0;
3022- if (best_building->space_consumer_) {
3023- block_time = 45 * 60 * 1000;
3024+ if (best_building->space_consumer) {
3025+ if (spots_ > kSpotsEnough) {
3026+ block_time = 45 * 60 * 1000;
3027+ } else {
3028+ block_time = 10 * 60 * 1000;
3029+ }
3030 block_area = 3;
3031 } else { // militray buildings for a very short time
3032 block_time = 25 * 1000;
3033@@ -2514,17 +2507,15 @@
3034
3035 MapRegion<Area<FCoords>> mr(map, Area<FCoords>(map.get_fcoords(proposed_coords), block_area));
3036 do {
3037- BlockedField blocked2(
3038- map.get_fcoords(*(mr.location().field)), game().get_gametime() + block_time);
3039- blocked_fields.push_back(blocked2);
3040+ blocked_fields.add(mr.location(), game().get_gametime() + block_time);
3041 } while (mr.advance(map));
3042 }
3043
3044- if (!(best_building->type == BuildingObserver::MILITARYSITE)) {
3045- best_building->construction_decision_time_ = gametime;
3046+ if (!(best_building->type == BuildingObserver::Type::kMilitarysite)) {
3047+ best_building->construction_decision_time = gametime;
3048 } else { // very ugly hack here
3049 military_last_build_ = gametime;
3050- best_building->construction_decision_time_ = gametime - kBuildingMinInterval / 2;
3051+ best_building->construction_decision_time = gametime - kBuildingMinInterval / 2;
3052 }
3053
3054 // set the type of update that is needed
3055@@ -2538,12 +2529,11 @@
3056 // improves current road system
3057 bool DefaultAI::improve_roads(uint32_t gametime) {
3058
3059- // first force a split on roads that are longer than 3 parts
3060- // with exemption when there is too few building spots
3061- if (spots_ > 20 && !roads.empty()) {
3062+ if (!roads.empty()) {
3063 const Path& path = roads.front()->get_path();
3064
3065- if (path.get_nsteps() > 3) {
3066+ // first force a split on roads that are longer than 3 parts
3067+ if (path.get_nsteps() > 3 && spots_ > kSpotsEnough) {
3068 const Map& map = game().map();
3069 CoordPath cp(map, path);
3070 // try to split after two steps
3071@@ -2570,13 +2560,15 @@
3072
3073 // Unable to set a flag - perhaps the road was build stupid
3074 game().send_player_bulldoze(*const_cast<Road*>(roads.front()));
3075+ return true;
3076 }
3077
3078 roads.push_back(roads.front());
3079 roads.pop_front();
3080
3081 // occasionaly we test if the road can be dismounted
3082- if (gametime % 5 == 0) {
3083+ // if there is shortage of spots we do it always
3084+ if (gametime % 5 == 0 || spots_ < kSpotsTooLittle) {
3085 const Road& road = *roads.front();
3086 if (dispensable_road_test(*const_cast<Road*>(&road))) {
3087 game().send_player_bulldoze(*const_cast<Road*>(&road));
3088@@ -2622,21 +2614,38 @@
3089 bool is_warehouse = false;
3090 if (Building* b = flag.get_building()) {
3091 BuildingObserver& bo = get_building_observer(b->descr().name().c_str());
3092- if (bo.type == BuildingObserver::WAREHOUSE) {
3093+ if (bo.type == BuildingObserver::Type::kWarehouse) {
3094 is_warehouse = true;
3095 }
3096 }
3097
3098- // if this is end flag (or sole building) or just randomly
3099- if (flag.nr_of_roads() <= 1 || gametime % 10 == 0) {
3100+ // is connected to a warehouse?
3101+ const bool needs_warehouse = flag.get_economy()->warehouses().empty();
3102+
3103+ // needs to be connected
3104+ if (flag.nr_of_roads() == 0 || needs_warehouse) {
3105 create_shortcut_road(flag, 13, 22, gametime);
3106 inhibit_road_building_ = gametime + 800;
3107+ } else if (flag.nr_of_roads() == 1 || gametime % 10 == 0) {
3108+ if (spots_ > kSpotsEnough) {
3109+ // This is the normal situation
3110+ create_shortcut_road(flag, 13, 22, gametime);
3111+ inhibit_road_building_ = gametime + 800;
3112+ } else if (spots_ > kSpotsTooLittle) {
3113+ // We are short of spots so shortening must be significant
3114+ create_shortcut_road(flag, 13, 35, gametime);
3115+ inhibit_road_building_ = gametime + 800;
3116+ } else {
3117+ // We are very short of spots so shortening must be even bigger
3118+ create_shortcut_road(flag, 13, 50, gametime);
3119+ inhibit_road_building_ = gametime + 800;
3120+ }
3121 // a warehouse with 3 or less roads
3122 } else if (is_warehouse && flag.nr_of_roads() <= 3) {
3123 create_shortcut_road(flag, 9, -1, gametime);
3124 inhibit_road_building_ = gametime + 400;
3125 // and when a flag is full with wares
3126- } else if (flag.current_wares() > 5) {
3127+ } else if (spots_ > kSpotsEnough && flag.current_wares() > 5) {
3128 create_shortcut_road(flag, 9, -2, gametime);
3129 inhibit_road_building_ = gametime + 400;
3130 } else {
3131@@ -2655,7 +2664,9 @@
3132 Flag& roadstartflag = road.get_flag(Road::FlagStart);
3133 Flag& roadendflag = road.get_flag(Road::FlagEnd);
3134
3135- if (roadstartflag.current_wares() > 0 || roadendflag.current_wares() > 0) {
3136+ // We do not dismantle (even consider it) if the road is busy (some wares on flags), unless there
3137+ // is shortage of build spots
3138+ if (spots_ > kSpotsTooLittle && roadstartflag.current_wares() + roadendflag.current_wares() > 0) {
3139 return false;
3140 }
3141
3142@@ -2664,7 +2675,14 @@
3143 std::vector<NearFlag> reachableflags;
3144 queue.push(NearFlag(roadstartflag, 0, 0));
3145 uint8_t pathcounts = 0;
3146- uint8_t checkradius = 8;
3147+ uint8_t checkradius = 0;
3148+ if (spots_ > kSpotsEnough) {
3149+ checkradius = 8;
3150+ } else if (spots_ > kSpotsTooLittle) {
3151+ checkradius = 12;
3152+ } else {
3153+ checkradius = 16;
3154+ }
3155 Map& map = game().map();
3156
3157 // algorithm to walk on roads
3158@@ -2738,8 +2756,8 @@
3159 // this should not happen, but if the economy has a warehouse and a dismantle
3160 // grace time set, we must 'zero' the dismantle grace time
3161 if (!flag.get_economy()->warehouses().empty() &&
3162- eco->dismantle_grace_time_ != std::numeric_limits<int32_t>::max()) {
3163- eco->dismantle_grace_time_ = std::numeric_limits<int32_t>::max();
3164+ eco->dismantle_grace_time != std::numeric_limits<int32_t>::max()) {
3165+ eco->dismantle_grace_time = std::numeric_limits<int32_t>::max();
3166 }
3167
3168 // first we deal with situations when this is economy with no warehouses
3169@@ -2759,13 +2777,13 @@
3170 }
3171
3172 // if we are within grace time, it is OK, just go on
3173- if (eco->dismantle_grace_time_ > gametime &&
3174- eco->dismantle_grace_time_ != std::numeric_limits<int32_t>::max()) {
3175+ if (eco->dismantle_grace_time > gametime &&
3176+ eco->dismantle_grace_time != std::numeric_limits<int32_t>::max()) {
3177 ;
3178
3179 // if grace time is not set, this is probably first time without a warehouse and we must
3180 // set it
3181- } else if (eco->dismantle_grace_time_ == std::numeric_limits<int32_t>::max()) {
3182+ } else if (eco->dismantle_grace_time == std::numeric_limits<int32_t>::max()) {
3183
3184 // constructionsites
3185 if (upcast(ConstructionSite const, constructionsite, flag.get_building())) {
3186@@ -2773,10 +2791,10 @@
3187 get_building_observer(constructionsite->building().name().c_str());
3188 // first very special case - a port (in the phase of constructionsite)
3189 // this might be a new colonization port
3190- if (bo.is_port_) {
3191- eco->dismantle_grace_time_ = gametime + 60 * 60 * 1000; // one hour should be enough
3192+ if (bo.is_port) {
3193+ eco->dismantle_grace_time = gametime + 60 * 60 * 1000; // one hour should be enough
3194 } else { // other constructionsites, usually new (standalone) constructionsites
3195- eco->dismantle_grace_time_ =
3196+ eco->dismantle_grace_time =
3197 gametime + 30 * 1000 + // very shot time is enough
3198 (eco->flags.size() * 30 * 1000); // + 30 seconds for every flag in economy
3199 }
3200@@ -2785,11 +2803,11 @@
3201 } else {
3202
3203 if (occupied_military_) {
3204- eco->dismantle_grace_time_ =
3205+ eco->dismantle_grace_time =
3206 (gametime + 90 * 60 * 1000) + (eco->flags.size() * 20 * 1000);
3207
3208 } else { // for other normal buildings
3209- eco->dismantle_grace_time_ =
3210+ eco->dismantle_grace_time =
3211 gametime + (45 * 60 * 1000) + (eco->flags.size() * 20 * 1000);
3212 }
3213 }
3214@@ -2850,7 +2868,7 @@
3215 }
3216
3217 // now make sure that this field has not been processed yet
3218- const uint32_t hash = coords_hash(reachable_coords);
3219+ const uint32_t hash = reachable_coords.hash();
3220 if (lookuptable.count(hash) == 0) {
3221 lookuptable.insert(hash);
3222
3223@@ -2922,7 +2940,7 @@
3224 continue;
3225 }
3226
3227- queue.push(NearFlag(*endflag, nf.cost_ + road->get_path().get_nsteps(), dist));
3228+ queue.push(NearFlag(*endflag, nf.cost + road->get_path().get_nsteps(), dist));
3229 }
3230 }
3231
3232@@ -2932,16 +2950,16 @@
3233 for (std::vector<NearFlag>::iterator nf_walk_it = nearflags_tmp.begin();
3234 nf_walk_it != nearflags_tmp.end();
3235 ++nf_walk_it) {
3236- uint32_t const hash_walk = coords_hash(nf_walk_it->flag->get_position());
3237+ uint32_t const hash_walk = nf_walk_it->flag->get_position().hash();
3238 if (lookuptable.count(hash_walk) > 0) {
3239 // iterating over nearflags
3240 for (std::vector<NearFlag>::iterator nf_it = nearflags.begin(); nf_it != nearflags.end();
3241 ++nf_it) {
3242- uint32_t const hash = coords_hash(nf_it->flag->get_position());
3243+ uint32_t const hash = nf_it->flag->get_position().hash();
3244 if (hash == hash_walk) {
3245 // decreasing "cost" (of walking via roads)
3246- if (nf_it->cost_ > nf_walk_it->cost_) {
3247- nf_it->cost_ = nf_walk_it->cost_;
3248+ if (nf_it->cost > nf_walk_it->cost) {
3249+ nf_it->cost = nf_walk_it->cost;
3250 }
3251 }
3252 }
3253@@ -2949,7 +2967,7 @@
3254 }
3255
3256 // ordering nearflags
3257- std::sort(nearflags.begin(), nearflags.end(), CompareShortening());
3258+ std::sort(nearflags.begin(), nearflags.end(), NearFlag::CompareShortening());
3259
3260 // this is just a random number, will be used later
3261 int32_t random_gametime = game().get_gametime();
3262@@ -2963,7 +2981,7 @@
3263 NearFlag& nf = nearflags.at(i);
3264
3265 // terminating looping if reduction is too low (nearflags are sorted by reduction)
3266- if ((nf.cost_ - nf.distance_) < min_reduction) {
3267+ if ((nf.cost - nf.distance) < min_reduction) {
3268 return false;
3269 }
3270
3271@@ -2971,8 +2989,8 @@
3272 // usually we allow connecting only if both flags are closer then 'checkradius-2'
3273 // with exeption the flag belongs to a small economy (typically a new building not connected
3274 // yet)
3275- if ((nf.cost_ - nf.distance_) >= min_reduction && nf.distance_ >= 2 &&
3276- nf.distance_ < checkradius - 2) {
3277+ if ((nf.cost - nf.distance) >= min_reduction && nf.distance >= 2 &&
3278+ nf.distance < checkradius - 2) {
3279
3280 // sometimes the shortest road is not the buildable, even if map.findpath claims so
3281 // best so we add some randomness
3282@@ -2988,7 +3006,7 @@
3283 map.findpath(flag.get_position(), nf.flag->get_position(), 0, path, check);
3284
3285 if (pathcost >= 0) {
3286- if (static_cast<int32_t>(nf.cost_ - path.get_nsteps()) > min_reduction) {
3287+ if (static_cast<int32_t>(nf.cost - path.get_nsteps()) > min_reduction) {
3288 game().send_player_build_road(player_number(), path);
3289 return true;
3290 }
3291@@ -3000,11 +3018,12 @@
3292 // if all possible roads skipped
3293 if (last_attempt_) {
3294 Building* bld = flag.get_building();
3295- // first we block the field for 15 minutes, probably it is not good place to build a
3296- // building on
3297- BlockedField blocked(
3298- game().map().get_fcoords(bld->get_position()), game().get_gametime() + 15 * 60 * 1000);
3299- blocked_fields.push_back(blocked);
3300+ // first we block the field and vicinity for 15 minutes, probably it is not a good place to build on
3301+ MapRegion<Area<FCoords>> mr(
3302+ game().map(), Area<FCoords>(map.get_fcoords(bld->get_position()), 2));
3303+ do {
3304+ blocked_fields.add(mr.location(), game().get_gametime() + 15 * 60 * 1000);
3305+ } while (mr.advance(map));
3306 eco->flags.remove(&flag);
3307 game().send_player_bulldoze(*const_cast<Flag*>(&flag));
3308 return true;
3309@@ -3072,7 +3091,7 @@
3310
3311 // first we werify if site is working yet (can be unoccupied since the start)
3312 if (!site.site->can_start_working()) {
3313- site.unoccupied_till_ = game().get_gametime();
3314+ site.unoccupied_till = game().get_gametime();
3315 }
3316
3317 // is it connected to wh at all?
3318@@ -3080,7 +3099,7 @@
3319
3320 // do not dismantle or upgrade the same type of building too soon - to give some time to update
3321 // statistics
3322- if (site.bo->last_dismantle_time_ > game().get_gametime() - 30 * 1000) {
3323+ if (site.bo->last_dismantle_time > game().get_gametime() - 30 * 1000) {
3324 return false;
3325 }
3326
3327@@ -3102,16 +3121,16 @@
3328 // b) if there are two buildings
3329 // statistics percents are decisive
3330 // c) yet there are buildings that might be upgraded, even when
3331- // there is no second buiding of the kind (flag upgrade_substitutes_)
3332+ // there is no second buiding of the kind (flag upgrade_substitutes)
3333
3334 const DescriptionIndex enhancement = site.site->descr().enhancement();
3335 if (connected_to_wh && enhancement != INVALID_INDEX &&
3336 // if upgrade does not subsitute, we need to have two buildings at least
3337- ((site.bo->cnt_built_ - site.bo->unoccupied_count_ > 1 && site.bo->upgrade_extends_)
3338+ ((site.bo->cnt_built - site.bo->unoccupied_count > 1 && site.bo->upgrade_extends)
3339 ||
3340- site.bo->upgrade_substitutes_) &&
3341+ site.bo->upgrade_substitutes) &&
3342 gametime > 45 * 60 * 1000 &&
3343- gametime > site.built_time_ + 20 * 60 * 1000) {
3344+ gametime > site.built_time + 20 * 60 * 1000) {
3345
3346 // Only enhance buildings that are allowed (scenario mode)
3347 // do not do decisions too fast
3348@@ -3121,8 +3140,8 @@
3349 BuildingObserver& en_bo = get_building_observer(bld.name().c_str());
3350 bool doing_upgrade = false;
3351
3352- if (gametime - en_bo.construction_decision_time_ >= 10 * 60 * 1000 &&
3353- (en_bo.cnt_under_construction_ + en_bo.unoccupied_count_) == 0) {
3354+ if (gametime - en_bo.construction_decision_time >= 10 * 60 * 1000 &&
3355+ (en_bo.cnt_under_construction + en_bo.unoccupied_count) == 0) {
3356
3357 // don't upgrade without workers
3358 if (site.site->has_workers(enhancement, game())) {
3359@@ -3134,23 +3153,23 @@
3360
3361 if (en_bo.total_count() == 1) {
3362 //if the upgrade itself can be upgraded futher, we are more willing to upgrade 2nd building
3363- if (en_bo.upgrade_extends_ || en_bo.upgrade_substitutes_) {
3364- if (en_bo.current_stats_ > 30) {
3365+ if (en_bo.upgrade_extends || en_bo.upgrade_substitutes) {
3366+ if (en_bo.current_stats > 30) {
3367 doing_upgrade = true;
3368 }
3369- } else if (en_bo.current_stats_ > 50) {
3370+ } else if (en_bo.current_stats > 50) {
3371 doing_upgrade = true;
3372 }
3373 }
3374
3375 if (en_bo.total_count() > 1) {
3376- if (en_bo.current_stats_ > 80) {
3377+ if (en_bo.current_stats > 80) {
3378 doing_upgrade = true;
3379 }
3380 }
3381
3382 // Dont forget about limitation of number of buildings
3383- if (en_bo.cnt_limit_by_aimode_ <= en_bo.total_count() - en_bo.unconnected_count_) {
3384+ if (en_bo.cnt_limit_by_aimode <= en_bo.total_count() - en_bo.unconnected_count) {
3385 doing_upgrade = false;
3386 }
3387 }
3388@@ -3160,14 +3179,19 @@
3389 // additional: we dont want to lose the old building
3390 if (doing_upgrade) {
3391 game().send_player_enhance_building(*site.site, enhancement);
3392- en_bo.construction_decision_time_ = gametime;
3393+ en_bo.construction_decision_time = gametime;
3394 return true;
3395 }
3396 }
3397 }
3398
3399 // Lumberjack / Woodcutter handling
3400- if (site.bo->need_trees_) {
3401+ if (site.bo->need_trees) {
3402+
3403+ // do not dismantle immediatelly
3404+ if ((game().get_gametime() - site.built_time) < 4 * 60 * 1000) {
3405+ return false;
3406+ }
3407
3408 const uint32_t remaining_trees =
3409 map.find_immovables(Area<FCoords>(map.get_fcoords(site.site->get_position()), radius),
3410@@ -3180,7 +3204,7 @@
3411 (remaining_trees * 10 + 9 * persistent_data->trees_around_cutters) / 10;
3412
3413 // Do not destruct the last few lumberjacks
3414- if (site.bo->cnt_built_ <= site.bo->cnt_target_) {
3415+ if (site.bo->cnt_built <= site.bo->cnt_target) {
3416 return false;
3417 }
3418
3419@@ -3188,25 +3212,23 @@
3420 return false;
3421 }
3422
3423-
3424-
3425 // do not dismantle if there are some trees remaining
3426 if (remaining_trees > 5) {
3427 return false;
3428 }
3429
3430 if (site.bo->stocklevel_time < game().get_gametime() - 10 * 1000) {
3431- site.bo->stocklevel_ = get_stocklevel(*site.bo);
3432+ site.bo->stocklevel = get_stocklevel(*site.bo);
3433 site.bo->stocklevel_time = game().get_gametime();
3434 }
3435
3436 // if we need wood badly
3437- if (remaining_trees > 0 && site.bo->stocklevel_ <= 50) {
3438+ if (remaining_trees > 0 && site.bo->stocklevel <= 50) {
3439 return false;
3440 }
3441
3442 // so finally we dismantle the lumberjac
3443- site.bo->last_dismantle_time_ = game().get_gametime();
3444+ site.bo->last_dismantle_time = game().get_gametime();
3445 flags_to_be_removed.push_back(site.site->base_flag().get_position());
3446 if (connected_to_wh) {
3447 game().send_player_dismantle(*site.site);
3448@@ -3218,10 +3240,10 @@
3449 }
3450
3451 // Wells handling
3452- if (site.bo->mines_water_) {
3453- if (site.unoccupied_till_ + 6 * 60 * 1000 < gametime &&
3454+ if (site.bo->mines_water) {
3455+ if (site.unoccupied_till + 6 * 60 * 1000 < gametime &&
3456 site.site->get_statistics_percent() == 0) {
3457- site.bo->last_dismantle_time_ = gametime;
3458+ site.bo->last_dismantle_time = gametime;
3459 flags_to_be_removed.push_back(site.site->base_flag().get_position());
3460 if (connected_to_wh) {
3461 game().send_player_dismantle(*site.site);
3462@@ -3233,7 +3255,7 @@
3463 }
3464
3465 // do not consider dismantling if we are under target
3466- if (site.bo->last_dismantle_time_ + 90 * 1000 > game().get_gametime()) {
3467+ if (site.bo->last_dismantle_time + 90 * 1000 > game().get_gametime()) {
3468 return false;
3469 }
3470
3471@@ -3241,11 +3263,11 @@
3472 // but first we make sure we do not dismantle a well too soon
3473 // after dismantling previous one
3474 if (site.bo->stocklevel_time < game().get_gametime() - 5 * 1000) {
3475- site.bo->stocklevel_ = get_stocklevel(*site.bo);
3476+ site.bo->stocklevel = get_stocklevel(*site.bo);
3477 site.bo->stocklevel_time = game().get_gametime();
3478 }
3479- if (site.bo->stocklevel_ > 250 + productionsites.size() * 5) { // dismantle
3480- site.bo->last_dismantle_time_ = game().get_gametime();
3481+ if (site.bo->stocklevel > 250 + productionsites.size() * 5) { // dismantle
3482+ site.bo->last_dismantle_time = game().get_gametime();
3483 flags_to_be_removed.push_back(site.site->base_flag().get_position());
3484 if (connected_to_wh) {
3485 game().send_player_dismantle(*site.site);
3486@@ -3259,7 +3281,7 @@
3487 }
3488
3489 // Quarry handling
3490- if (site.bo->need_rocks_) {
3491+ if (site.bo->need_rocks) {
3492
3493 if (map.find_immovables(
3494 Area<FCoords>(map.get_fcoords(site.site->get_position()), 6),
3495@@ -3278,10 +3300,10 @@
3496 return true;
3497 }
3498
3499- if (site.unoccupied_till_ + 6 * 60 * 1000 < gametime &&
3500+ if (site.unoccupied_till + 6 * 60 * 1000 < gametime &&
3501 site.site->get_statistics_percent() == 0) {
3502 // it is possible that there are rocks but quarry is not able to mine them
3503- site.bo->last_dismantle_time_ = game().get_gametime();
3504+ site.bo->last_dismantle_time = game().get_gametime();
3505 flags_to_be_removed.push_back(site.site->base_flag().get_position());
3506 if (connected_to_wh) {
3507 game().send_player_dismantle(*site.site);
3508@@ -3296,26 +3318,26 @@
3509 }
3510
3511 // All other SPACE_CONSUMERS without input and above target_count
3512- if (site.bo->inputs_.empty() // does not consume anything
3513- &&
3514- site.bo->production_hint_ == -1 // not a renewing building (forester...)
3515- &&
3516- site.unoccupied_till_ + 10 * 60 * 1000 < gametime // > 10 minutes old
3517+ if (site.bo->inputs.empty() // does not consume anything
3518+ &&
3519+ site.bo->production_hint == -1 // not a renewing building (forester...)
3520+ &&
3521+ site.unoccupied_till + 10 * 60 * 1000 < gametime // > 10 minutes old
3522 &&
3523 site.site->can_start_working() // building is occupied
3524 &&
3525- site.bo->space_consumer_ && !site.bo->plants_trees_) {
3526+ site.bo->space_consumer && !site.bo->plants_trees) {
3527
3528 // if we have more buildings then target
3529- if ((site.bo->cnt_built_ - site.bo->unconnected_count_) > site.bo->cnt_target_) {
3530+ if ((site.bo->cnt_built - site.bo->unconnected_count) > site.bo->cnt_target) {
3531 if (site.bo->stocklevel_time < game().get_gametime() - 5 * 1000) {
3532- site.bo->stocklevel_ = get_stocklevel(*site.bo);
3533+ site.bo->stocklevel = get_stocklevel(*site.bo);
3534 site.bo->stocklevel_time = game().get_gametime();
3535 }
3536
3537 if (site.site->get_statistics_percent() < 30 &&
3538- site.bo->stocklevel_ > 100) {
3539- site.bo->last_dismantle_time_ = game().get_gametime();
3540+ site.bo->stocklevel > 100) {
3541+ site.bo->last_dismantle_time = game().get_gametime();
3542 flags_to_be_removed.push_back(site.site->base_flag().get_position());
3543 if (connected_to_wh) {
3544 game().send_player_dismantle(*site.site);
3545@@ -3327,7 +3349,7 @@
3546 }
3547
3548 // a building can be dismanteld if it performs too bad, if it is not the last one
3549- if (site.site->get_statistics_percent() <= 10 && site.bo->cnt_built_ > 1) {
3550+ if (site.site->get_statistics_percent() <= 10 && site.bo->cnt_built > 1) {
3551
3552 flags_to_be_removed.push_back(site.site->base_flag().get_position());
3553 if (connected_to_wh) {
3554@@ -3341,18 +3363,18 @@
3555 return false;
3556 }
3557
3558- // buildings with inputs_, checking if we can a dismantle some due to low performance
3559- if (!site.bo->inputs_.empty() &&
3560- (site.bo->cnt_built_ - site.bo->unoccupied_count_) >= 3 &&
3561+ // buildings with inputs, checking if we can a dismantle some due to low performance
3562+ if (!site.bo->inputs.empty() &&
3563+ (site.bo->cnt_built - site.bo->unoccupied_count) >= 3 &&
3564 site.site->can_start_working() &&
3565 check_building_necessity(*site.bo, PerfEvaluation::kForDismantle, gametime)
3566 == BuildingNecessity::kNotNeeded &&
3567- gametime - site.bo->last_dismantle_time_ > 5 * 60 * 1000 &&
3568-
3569- site.bo->current_stats_ > site.site->get_statistics_percent() && // underperformer
3570- (game().get_gametime() - site.unoccupied_till_) > 10 * 60 * 1000) {
3571-
3572- site.bo->last_dismantle_time_ = game().get_gametime();
3573+ gametime - site.bo->last_dismantle_time > 5 * 60 * 1000 &&
3574+
3575+ site.bo->current_stats > site.site->get_statistics_percent() && // underperformer
3576+ (game().get_gametime() - site.unoccupied_till) > 10 * 60 * 1000) {
3577+
3578+ site.bo->last_dismantle_time = game().get_gametime();
3579
3580 flags_to_be_removed.push_back(site.site->base_flag().get_position());
3581 if (connected_to_wh) {
3582@@ -3365,12 +3387,12 @@
3583
3584 // remaining buildings without inputs and not supporting ones (fishers only left probably and
3585 // hunters)
3586- if (site.bo->inputs_.empty() && site.bo->production_hint_ < 0 &&
3587- site.site->can_start_working() && !site.bo->space_consumer_ &&
3588+ if (site.bo->inputs.empty() && site.bo->production_hint < 0 &&
3589+ site.site->can_start_working() && !site.bo->space_consumer &&
3590 site.site->get_statistics_percent() < 10 &&
3591- ((game().get_gametime() - site.built_time_) > 10 * 60 * 1000)) {
3592+ ((game().get_gametime() - site.built_time) > 10 * 60 * 1000)) {
3593
3594- site.bo->last_dismantle_time_ = game().get_gametime();
3595+ site.bo->last_dismantle_time = game().get_gametime();
3596 flags_to_be_removed.push_back(site.site->base_flag().get_position());
3597 if (connected_to_wh) {
3598 game().send_player_dismantle(*site.site);
3599@@ -3382,17 +3404,17 @@
3600
3601 // supporting productionsites (rangers)
3602 // stop/start them based on stock avaiable
3603- if (site.bo->production_hint_ >= 0) {
3604+ if (site.bo->production_hint >= 0) {
3605
3606- if (!site.bo->plants_trees_) {
3607+ if (!site.bo->plants_trees) {
3608 // other supporting sites, like fish breeders, gamekeepers are not dismantled at all
3609 return false;
3610 }
3611
3612 // dismantling the rangers hut, but only if we have them above a target
3613- if (wood_policy_ == WoodPolicy::kDismantleRangers && site.bo->cnt_built_ > site.bo->cnt_target_) {
3614+ if (wood_policy_ == WoodPolicy::kDismantleRangers && site.bo->cnt_built > site.bo->cnt_target) {
3615
3616- site.bo->last_dismantle_time_ = game().get_gametime();
3617+ site.bo->last_dismantle_time = game().get_gametime();
3618 flags_to_be_removed.push_back(site.site->base_flag().get_position());
3619 if (connected_to_wh) {
3620 game().send_player_dismantle(*site.site);
3621@@ -3456,7 +3478,7 @@
3622
3623 // goes over all warehouses (these includes ports)
3624 for (const WarehouseSiteObserver& wh_obs : warehousesites) {
3625- if (wh_obs.bo->is_port_) {
3626+ if (wh_obs.bo->is_port) {
3627 ports_count += 1;
3628 if (Widelands::PortDock* pd = wh_obs.site->get_portdock()) {
3629 if (pd->expedition_started()) {
3630@@ -3468,7 +3490,7 @@
3631
3632 // goes over productionsites and gets status of shipyards
3633 for (const ProductionSiteObserver& ps_obs : productionsites) {
3634- if (ps_obs.bo->is_shipyard_) {
3635+ if (ps_obs.bo->is_shipyard) {
3636 shipyards_count += 1;
3637
3638 // counting stocks
3639@@ -3514,7 +3536,7 @@
3640 if (enough_ships == FleetStatus::kNeedShip) {
3641
3642 for (const ProductionSiteObserver& ps_obs : productionsites) {
3643- if (ps_obs.bo->is_shipyard_ && ps_obs.site->can_start_working() &&
3644+ if (ps_obs.bo->is_shipyard && ps_obs.site->can_start_working() &&
3645 ps_obs.site->is_stopped()) {
3646 // make sure it is fully stocked
3647 // counting stocks
3648@@ -3543,7 +3565,7 @@
3649 expeditions_in_progress == 0) {
3650 // we need to find a port
3651 for (const WarehouseSiteObserver& wh_obs : warehousesites) {
3652- if (wh_obs.bo->is_port_) {
3653+ if (wh_obs.bo->is_port) {
3654 game().send_player_start_or_cancel_expedition(*wh_obs.site);
3655 return true;
3656 }
3657@@ -3575,7 +3597,7 @@
3658
3659 // the function below will take care of variables like
3660 // - expedition_ship_
3661- // - expedition_start_time_
3662+ // - expedition_start_time
3663 // - expected_colony_scan
3664 // - no_more_expeditions_
3665 check_ship_in_expedition(*i, gametime);
3666@@ -3629,7 +3651,7 @@
3667 for (std::list<ProductionSiteObserver>::iterator site = productionsites.begin();
3668 site != productionsites.end();
3669 ++site) {
3670- if (site->bo->is_shipyard_) {
3671+ if (site->bo->is_shipyard) {
3672 if (!site->site->is_stopped()) {
3673 game().send_player_start_stop_building(*site->site);
3674 }
3675@@ -3641,10 +3663,10 @@
3676 for (std::list<ProductionSiteObserver>::iterator site = productionsites.begin();
3677 site != productionsites.end();
3678 ++site) {
3679- if (site->bo->is_shipyard_) {
3680- for (uint32_t k = 0; k < site->bo->inputs_.size(); ++k) {
3681+ if (site->bo->is_shipyard) {
3682+ for (uint32_t k = 0; k < site->bo->inputs.size(); ++k) {
3683 game().send_player_set_ware_priority(
3684- *site->site, wwWARE, site->bo->inputs_.at(k), HIGH_PRIORITY);
3685+ *site->site, wwWARE, site->bo->inputs.at(k), HIGH_PRIORITY);
3686 }
3687 }
3688 }
3689@@ -3695,7 +3717,7 @@
3690 persistent_data->colony_scan_area = expected_colony_scan;
3691 }
3692
3693- // Expedition overdue. Setting no_more_expeditions_=true
3694+ // Expedition overdue. Setting no_more_expeditions = true
3695 // But we do not cancel it, the code for cancellation does not work properly now
3696 // TODO(unknown): - expedition code for cancellation needs to be fixed and afterwareds
3697 // AI can be changed to cancel overdue expedition
3698@@ -3728,7 +3750,7 @@
3699
3700 // first get rid of mines that are missing workers for some time (6 minutes),
3701 // released worker (if any) can be usefull elsewhere !
3702- if (site.built_time_ + 6 * 60 * 1000 < gametime && !site.site->can_start_working()) {
3703+ if (site.built_time + 6 * 60 * 1000 < gametime && !site.site->can_start_working()) {
3704 flags_to_be_removed.push_back(site.site->base_flag().get_position());
3705 if (connected_to_wh) {
3706 game().send_player_dismantle(*site.site);
3707@@ -3744,7 +3766,7 @@
3708 }
3709
3710 // if mine is working, doing nothing
3711- if (site.no_resources_since_ > gametime - 5 * 60 * 1000) {
3712+ if (site.no_resources_since > gametime - 5 * 60 * 1000) {
3713 return false;
3714 }
3715
3716@@ -3761,9 +3783,9 @@
3717 // (we will not dismantle even if there are no mineable resources left for this level of mine
3718 // and output is not needed)
3719 bool forcing_upgrade = false;
3720- const uint16_t minimal_mines_count = (site.bo->built_mat_producer_) ? 2 : 1;
3721+ const uint16_t minimal_mines_count = (site.bo->produces_building_material) ? 2 : 1;
3722 if (has_upgrade &&
3723- mines_per_type[site.bo->mines_].total_count() <= minimal_mines_count) {
3724+ mines_per_type[site.bo->mines].total_count() <= minimal_mines_count) {
3725 forcing_upgrade = true;
3726 }
3727
3728@@ -3776,17 +3798,17 @@
3729 } else {
3730 game().send_player_bulldoze(*site.site);
3731 }
3732- site.bo->construction_decision_time_ = gametime;
3733+ site.bo->construction_decision_time = gametime;
3734 return true;
3735 // if having an upgrade, after half hour
3736- } else if (site.no_resources_since_ < gametime - 30 * 60 * 1000 && !forcing_upgrade) {
3737+ } else if (site.no_resources_since < gametime - 30 * 60 * 1000 && !forcing_upgrade) {
3738 flags_to_be_removed.push_back(site.site->base_flag().get_position());
3739 if (connected_to_wh) {
3740 game().send_player_dismantle(*site.site);
3741 } else {
3742 game().send_player_bulldoze(*site.site);
3743 }
3744- site.bo->construction_decision_time_ = gametime;
3745+ site.bo->construction_decision_time = gametime;
3746 return true;
3747 }
3748
3749@@ -3795,7 +3817,7 @@
3750 // if we don't need the output, and we have other buildings of the same type, the function returns
3751 // and building will be dismantled later.
3752 check_building_necessity(*site.bo, PerfEvaluation::kForDismantle, gametime);
3753- if (site.bo->max_needed_preciousness_ == 0 && !forcing_upgrade) {
3754+ if (site.bo->max_needed_preciousness == 0 && !forcing_upgrade) {
3755 return false;
3756 }
3757
3758@@ -3806,13 +3828,13 @@
3759 }
3760
3761 // don't upgrade now if other mines of the same type are right now in construction
3762- if (mines_per_type[site.bo->mines_].in_construction > 0) {
3763+ if (mines_per_type[site.bo->mines].in_construction > 0) {
3764 return false;
3765 }
3766
3767 bool changed = false;
3768
3769- // first exclude possibility there are enhancements in construction or unoccupied_count_
3770+ // first exclude possibility there are enhancements in construction or unoccupied_count
3771 const BuildingDescr& bld = *tribe_->get_building_descr(enhancement);
3772 BuildingObserver& en_bo = get_building_observer(bld.name().c_str());
3773
3774@@ -3820,17 +3842,17 @@
3775 if (en_bo.aimode_limit_status() == AiModeBuildings::kAnotherAllowed) {
3776
3777 // if it is too soon for enhancement
3778- if (gametime - en_bo.construction_decision_time_ >= kBuildingMinInterval) {
3779+ if (gametime - en_bo.construction_decision_time >= kBuildingMinInterval) {
3780 // now verify that there are enough workers
3781 if (site.site->has_workers(enhancement, game())) { // enhancing
3782 game().send_player_enhance_building(*site.site, enhancement);
3783- if (site.bo->max_needed_preciousness_ == 0) {
3784- assert (mines_per_type[site.bo->mines_].total_count() <= minimal_mines_count);
3785- }
3786- if (mines_per_type[site.bo->mines_].total_count() > minimal_mines_count) {
3787- assert(site.bo->max_needed_preciousness_ > 0);
3788- }
3789- en_bo.construction_decision_time_ = gametime;
3790+ if (site.bo->max_needed_preciousness == 0) {
3791+ assert (mines_per_type[site.bo->mines].total_count() <= minimal_mines_count);
3792+ }
3793+ if (mines_per_type[site.bo->mines].total_count() > minimal_mines_count) {
3794+ assert(site.bo->max_needed_preciousness > 0);
3795+ }
3796+ en_bo.construction_decision_time = gametime;
3797 changed = true;
3798 }
3799 }
3800@@ -3871,48 +3893,48 @@
3801 }
3802
3803 // First we deal with training sites, they are separate category
3804- if (bo.type == BuildingObserver::TRAININGSITE) {
3805+ if (bo.type == BuildingObserver::Type::kTrainingsite) {
3806
3807- bo.primary_priority_ = 0;
3808+ bo.primary_priority = 0;
3809 if (bo.aimode_limit_status() != AiModeBuildings::kAnotherAllowed) {
3810 return BuildingNecessity::kNotNeeded;
3811 } else if (ts_without_trainers_ || (ts_basic_const_count_ + ts_advanced_const_count_) > 0) {
3812 return BuildingNecessity::kNotNeeded;
3813- } else if (bo.prohibited_till_ > gametime) {
3814+ } else if (bo.prohibited_till > gametime) {
3815 return BuildingNecessity::kNotNeeded;
3816- } else if (bo.build_material_shortage_) {
3817+ } else if (bo.build_material_shortage) {
3818 return BuildingNecessity::kNotNeeded;
3819 }
3820
3821 // It seems we might need it after all
3822- bo.primary_priority_ = -30;
3823+ bo.primary_priority = -30;
3824
3825- if (bo.forced_after_ < gametime && bo.total_count() == 0) {
3826- bo.primary_priority_ += 50;
3827+ if (bo.forced_after < gametime && bo.total_count() == 0) {
3828+ bo.primary_priority += 50;
3829 }
3830
3831 //if we are close to enemy (was seen in last 15 minutes)
3832 if (enemy_last_seen_ < gametime && enemy_last_seen_ + 15 * 60 * 1000 > gametime) {
3833- bo.primary_priority_ += 10;
3834+ bo.primary_priority += 10;
3835 }
3836
3837 // We build one trainig site per X military sites
3838 // with some variations, of course
3839- bo.primary_priority_ += static_cast<int32_t>(militarysites.size() + productionsites.size())
3840+ bo.primary_priority += static_cast<int32_t>(militarysites.size() + productionsites.size())
3841 - 50 * (ts_basic_count_ + ts_advanced_count_);
3842
3843 // We prefer basic trainingsites and sites with lower count
3844- if (bo.trainingsite_type_ == TrainingSiteType::kBasic) {
3845- bo.primary_priority_ += 1;
3846+ if (bo.trainingsite_type == TrainingSiteType::kBasic) {
3847+ bo.primary_priority += 1;
3848 }
3849- bo.primary_priority_ -= 2 * bo.total_count();
3850+ bo.primary_priority -= 2 * bo.total_count();
3851
3852 // Special bonus for very first site of type
3853 if (bo.total_count() == 0) {
3854- bo.primary_priority_ += 30;
3855+ bo.primary_priority += 30;
3856 }
3857
3858- if (bo.primary_priority_ > 0) {
3859+ if (bo.primary_priority > 0) {
3860 return BuildingNecessity::kNeeded;
3861 } else {
3862 return BuildingNecessity::kNotNeeded;
3863@@ -3922,41 +3944,43 @@
3864 // Let deal with productionsites now
3865 // First we iterate over outputs of building, count warehoused stock
3866 // and deciding if we have enough on stock (in warehouses)
3867- bo.max_preciousness_ = 0;
3868- bo.max_needed_preciousness_ = 0;
3869+ bo.max_preciousness = 0;
3870+ bo.max_needed_preciousness = 0;
3871
3872- for (uint32_t m = 0; m < bo.outputs_.size(); ++m) {
3873- DescriptionIndex wt(static_cast<size_t>(bo.outputs_.at(m)));
3874+ for (uint32_t m = 0; m < bo.outputs.size(); ++m) {
3875+ DescriptionIndex wt(static_cast<size_t>(bo.outputs.at(m)));
3876
3877 uint16_t target = tribe_->get_ware_descr(wt)->default_target_quantity(tribe_->name()) / 3;
3878 // at least 1
3879 target = std::max<uint16_t>(target, 1);
3880
3881- uint16_t preciousness = wares.at(bo.outputs_.at(m)).preciousness_;
3882+ uint16_t preciousness = wares.at(bo.outputs.at(m)).preciousness;
3883 if (preciousness < 1) { // it seems there are wares with 0 preciousness
3884 preciousness = 1; // (no entry in conf files?). But we need positive value here
3885 }
3886
3887 if (get_warehoused_stock(wt) < target) {
3888- if (bo.max_needed_preciousness_ < preciousness) {
3889- bo.max_needed_preciousness_ = preciousness;
3890+ if (bo.max_needed_preciousness < preciousness) {
3891+ bo.max_needed_preciousness = preciousness;
3892 }
3893 }
3894
3895- if (bo.max_preciousness_ < preciousness) {
3896- bo.max_preciousness_ = preciousness;
3897+ if (bo.max_preciousness < preciousness) {
3898+ bo.max_preciousness = preciousness;
3899 }
3900 }
3901
3902- if (!bo.outputs_.empty()) {
3903- assert (bo.max_preciousness_ > 0);
3904+ if (!bo.outputs.empty()) {
3905+ assert (bo.max_preciousness > 0);
3906 }
3907
3908 // This flag is to be used when buildig is forced. AI will not build another building when
3909 // a substitution exists. F.e. mines or pairs like tavern-inn
3910 // To skip unnecessary calculation, we calculate this only if we have 0 count of the buildings
3911 bool has_substitution_building = false;
3912- if (bo.total_count() == 0 && bo.upgrade_substitutes_ && bo.type == BuildingObserver::PRODUCTIONSITE) {
3913+ if (bo.total_count() == 0 &&
3914+ bo.upgrade_substitutes &&
3915+ bo.type == BuildingObserver::Type::kProductionsite) {
3916 const DescriptionIndex enhancement = bo.desc->enhancement();
3917 BuildingObserver& en_bo
3918 = get_building_observer(tribe_->get_building_descr(enhancement)->name().c_str());
3919@@ -3964,8 +3988,8 @@
3920 has_substitution_building = true;
3921 }
3922 }
3923- if (bo.total_count() == 0 && bo.type == BuildingObserver::MINE) {
3924- if (mines_per_type[bo.mines_].in_construction + mines_per_type[bo.mines_].finished > 0) {
3925+ if (bo.total_count() == 0 && bo.type == BuildingObserver::Type::kMine) {
3926+ if (mines_per_type[bo.mines].in_construction + mines_per_type[bo.mines].finished > 0) {
3927 has_substitution_building = true;
3928 }
3929 }
3930@@ -3976,18 +4000,18 @@
3931 // and after 90th minute we want second building unconditionally
3932 bool needs_second_for_upgrade = false;
3933 if (gametime > 30 * 60 * 1000 &&
3934- bo.cnt_built_ == 1 &&
3935- bo.cnt_under_construction_ == 0 &&
3936- bo.upgrade_extends_ &&
3937- !bo.upgrade_substitutes_ &&
3938- bo.type == BuildingObserver::PRODUCTIONSITE) {
3939+ bo.cnt_built == 1 &&
3940+ bo.cnt_under_construction == 0 &&
3941+ bo.upgrade_extends &&
3942+ !bo.upgrade_substitutes &&
3943+ bo.type == BuildingObserver::Type::kProductionsite) {
3944 const DescriptionIndex enhancement = bo.desc->enhancement();
3945 BuildingObserver& en_bo
3946 = get_building_observer(tribe_->get_building_descr(enhancement)->name().c_str());
3947 if ((gametime > 30 * 60 * 1000 && en_bo.total_count() == 0) ||
3948 gametime > 90 * 60 * 1000) {
3949 // We fake this
3950- bo.max_needed_preciousness_ = bo.max_preciousness_;
3951+ bo.max_needed_preciousness = bo.max_preciousness;
3952 needs_second_for_upgrade = true;
3953 }
3954 }
3955@@ -4003,26 +4027,26 @@
3956 ; // no exemption here within first 15 minutes
3957 } else if (gametime < 25 * 60 * 1000) { // exemption after 15 minutes - 1 building allowed
3958
3959- if (bo.type == BuildingObserver::MINE) {
3960- if (mines_per_type[bo.mines_].in_construction + mines_per_type[bo.mines_].finished == 0) {
3961+ if (bo.type == BuildingObserver::Type::kMine) {
3962+ if (mines_per_type[bo.mines].in_construction + mines_per_type[bo.mines].finished == 0) {
3963 needed_type = BuildingNecessity::kNeeded;
3964 }
3965 }
3966- if (bo.type == BuildingObserver::PRODUCTIONSITE) {
3967- if (bo.built_mat_producer_ || bo.max_needed_preciousness_ >= 10) {
3968+ if (bo.type == BuildingObserver::Type::kProductionsite) {
3969+ if (bo.produces_building_material || bo.max_needed_preciousness >= 10) {
3970 if (bo.total_count() == 0) {
3971 needed_type = BuildingNecessity::kNeeded;
3972 }
3973 }
3974 }
3975 } else { // exemption after 25 minutes - 2 buildings allowed
3976- if (bo.type == BuildingObserver::MINE) {
3977- if (mines_per_type[bo.mines_].in_construction + mines_per_type[bo.mines_].finished <= 1) {
3978+ if (bo.type == BuildingObserver::Type::kMine) {
3979+ if (mines_per_type[bo.mines].in_construction + mines_per_type[bo.mines].finished <= 1) {
3980 needed_type = BuildingNecessity::kNeeded;
3981 }
3982 }
3983- if (bo.type == BuildingObserver::PRODUCTIONSITE) {
3984- if (bo.built_mat_producer_ || bo.max_needed_preciousness_ >= 10) {
3985+ if (bo.type == BuildingObserver::Type::kProductionsite) {
3986+ if (bo.produces_building_material || bo.max_needed_preciousness >= 10) {
3987 if (bo.total_count() <= 1) {
3988 needed_type = BuildingNecessity::kNeeded;
3989 }
3990@@ -4034,115 +4058,126 @@
3991 // And finally the 'core' of this function
3992 // First deal with construction of new sites
3993 if (purpose == PerfEvaluation::kForConstruction) {
3994- if (bo.forced_after_ < gametime && bo.total_count() == 0 && !has_substitution_building) {
3995- bo.max_needed_preciousness_ = bo.max_preciousness_;
3996+ if (bo.forced_after < gametime && bo.total_count() == 0 && !has_substitution_building) {
3997+ bo.max_needed_preciousness = bo.max_preciousness;
3998 return BuildingNecessity::kForced;
3999- } else if (bo.prohibited_till_ > gametime) {
4000+ } else if (bo.prohibited_till > gametime) {
4001 return BuildingNecessity::kForbidden;
4002- } else if (bo.is_hunter_ || bo.is_fisher_) {
4003+ } else if (bo.is_hunter || bo.is_fisher) {
4004
4005- if (bo.max_needed_preciousness_ == 0) {
4006+ if (bo.max_needed_preciousness == 0) {
4007 return BuildingNecessity::kNotNeeded;
4008- } else if (bo.cnt_under_construction_ + bo.unoccupied_count_ > 0) {
4009+ } else if (bo.cnt_under_construction + bo.unoccupied_count > 0) {
4010 return BuildingNecessity::kForbidden;
4011 } else if (bo.total_count() > 0 && new_buildings_stop_) {
4012 return BuildingNecessity::kForbidden;
4013 } else {
4014 return BuildingNecessity::kNeeded;
4015 }
4016- } else if (bo.need_trees_) {
4017- if (bo.total_count() > 1 && (bo.cnt_under_construction_ + bo.unoccupied_count_ > 0)) {
4018+ } else if (bo.need_trees) {
4019+ if (bo.total_count() > 1 && (bo.cnt_under_construction + bo.unoccupied_count > 0)) {
4020 return BuildingNecessity::kForbidden;
4021 }
4022- bo.cnt_target_ =
4023+ bo.cnt_target =
4024 3 + static_cast<int32_t>(mines_.size() + productionsites.size()) / 20;
4025
4026- // adjusting/decreasing based on cnt_limit_by_aimode_
4027- bo.cnt_target_ = limit_cnt_target(bo.cnt_target_, bo.cnt_limit_by_aimode_);
4028+ // adjusting/decreasing based on cnt_limit_by_aimode
4029+ bo.cnt_target = limit_cnt_target(bo.cnt_target, bo.cnt_limit_by_aimode);
4030
4031 // for case the wood is not needed yet, to avoid inconsistency later on
4032- bo.max_needed_preciousness_ = bo.max_preciousness_;
4033+ bo.max_needed_preciousness = bo.max_preciousness;
4034
4035- if (bo.total_count() < bo.cnt_target_) {
4036+ if (bo.total_count() < bo.cnt_target) {
4037 return BuildingNecessity::kNeeded;
4038 } else {
4039 return BuildingNecessity::kAllowed;
4040 }
4041- } else if (bo.plants_trees_) {
4042+ } else if (bo.plants_trees) {
4043
4044- bo.cnt_target_ =
4045+ bo.cnt_target =
4046 2 +
4047 static_cast<int32_t>(mines_.size() + productionsites.size()) / 40;
4048
4049- // adjusting/decreasing based on cnt_limit_by_aimode_
4050- bo.cnt_target_ = limit_cnt_target(bo.cnt_target_, bo.cnt_limit_by_aimode_);
4051+ // adjusting/decreasing based on cnt_limit_by_aimode
4052+ bo.cnt_target = limit_cnt_target(bo.cnt_target, bo.cnt_limit_by_aimode);
4053
4054 if (wood_policy_ != WoodPolicy::kAllowRangers) {
4055 return BuildingNecessity::kForbidden;
4056 }
4057 // 150 corresponds to 15 trees
4058 if (persistent_data->trees_around_cutters < 150) {
4059- bo.cnt_target_ *= 4;
4060+ bo.cnt_target *= 4;
4061 }
4062- if (bo.total_count() > 1 && (bo.cnt_under_construction_ + bo.unoccupied_count_ > 0)) {
4063+ if (bo.total_count() > 1 && (bo.cnt_under_construction + bo.unoccupied_count > 0)) {
4064 return BuildingNecessity::kForbidden;
4065- } else if (bo.total_count() > bo.cnt_target_) {
4066+ } else if (bo.total_count() > bo.cnt_target) {
4067 return BuildingNecessity::kForbidden;
4068 }
4069 return BuildingNecessity::kNeeded;
4070- } else if (bo.need_rocks_ && bo.cnt_under_construction_ + bo.unoccupied_count_ == 0) {
4071- bo.max_needed_preciousness_ = bo.max_preciousness_; // even when rocks are not needed
4072- return BuildingNecessity::kAllowed;
4073- } else if (bo.production_hint_ >= 0 && bo.cnt_under_construction_ + bo.unoccupied_count_ == 0) {
4074- return BuildingNecessity::kAllowed;
4075- } else if (bo.cnt_under_construction_ + bo.unoccupied_count_ > 0 && bo.max_needed_preciousness_ < 10) {
4076- return BuildingNecessity::kForbidden;
4077- } else if (bo.cnt_under_construction_ + bo.unoccupied_count_ > 0 && gametime < 30 * 60 * 1000) {
4078- return BuildingNecessity::kForbidden;
4079- } else if (bo.cnt_under_construction_ + bo.unoccupied_count_ > 1) {
4080+ } else if (bo.need_rocks && bo.cnt_under_construction + bo.unoccupied_count == 0) {
4081+ bo.max_needed_preciousness = bo.max_preciousness; // even when rocks are not needed
4082+ return BuildingNecessity::kAllowed;
4083+ } else if (bo.production_hint >= 0 && bo.cnt_under_construction + bo.unoccupied_count == 0) {
4084+ return BuildingNecessity::kAllowed;
4085+ } else if (bo.cnt_under_construction + bo.unoccupied_count > 0 && bo.max_needed_preciousness < 10) {
4086+ return BuildingNecessity::kForbidden;
4087+ } else if (bo.cnt_under_construction + bo.unoccupied_count > 0 && gametime < 30 * 60 * 1000) {
4088+ return BuildingNecessity::kForbidden;
4089+ } else if (bo.cnt_under_construction + bo.unoccupied_count > 1) {
4090 return BuildingNecessity::kForbidden; // for preciousness>=10 and after 30 min
4091- } else if (bo.type == BuildingObserver::MINE) {
4092- if ((mines_per_type[bo.mines_].in_construction + mines_per_type[bo.mines_].finished) == 0) {
4093+ } else if (bo.type == BuildingObserver::Type::kMine) {
4094+ if ((mines_per_type[bo.mines].in_construction + mines_per_type[bo.mines].finished) == 0) {
4095 // unless a mine is prohibited, we want to have at least one of the kind
4096- bo.max_needed_preciousness_ = bo.max_preciousness_;
4097+ bo.max_needed_preciousness = bo.max_preciousness;
4098 return BuildingNecessity::kNeeded;
4099- } else if (((mines_per_type[bo.mines_].in_construction + mines_per_type[bo.mines_].finished)
4100+ } else if (((mines_per_type[bo.mines].in_construction + mines_per_type[bo.mines].finished)
4101 ==
4102- 1) && bo.built_mat_producer_) {
4103- bo.max_needed_preciousness_ = bo.max_preciousness_;
4104+ 1) && bo.produces_building_material) {
4105+ bo.max_needed_preciousness = bo.max_preciousness;
4106 return BuildingNecessity::kNeeded;
4107 }
4108- if (bo.max_needed_preciousness_ == 0) {
4109+ if (bo.max_needed_preciousness == 0) {
4110 return BuildingNecessity::kNotNeeded;
4111 }
4112- if (bo.current_stats_ < 40) {
4113+ if (bo.current_stats < 40) {
4114+ return BuildingNecessity::kForbidden;
4115+ }
4116+ assert (bo.last_building_built != kNever);
4117+ if (gametime < bo.last_building_built + 3 * 60 * 1000) {
4118 return BuildingNecessity::kForbidden;
4119 }
4120 return needed_type;
4121- } if (bo.max_needed_preciousness_ > 0) {
4122- if (bo.cnt_under_construction_ + bo.unoccupied_count_ > 0) {
4123- assert (bo.cnt_under_construction_ + bo.unoccupied_count_ == 1);
4124- assert (bo.max_needed_preciousness_ >= 10 || bo.built_mat_producer_);
4125+ } if (bo.max_needed_preciousness > 0) {
4126+ if (bo.cnt_under_construction + bo.unoccupied_count > 0) {
4127+ assert (bo.cnt_under_construction + bo.unoccupied_count == 1);
4128+ assert (bo.max_needed_preciousness >= 10 || bo.produces_building_material);
4129 assert (gametime >= 25 * 60 * 1000);
4130 }
4131
4132 // First 'if' is special support for hardwood producers (to have 2 of them)
4133- if (bo.built_mat_producer_ && bo.total_count() <= 1 && bo.current_stats_ > 10) {
4134+ if (bo.produces_building_material && bo.total_count() <= 1 && bo.current_stats > 10) {
4135 return BuildingNecessity::kNeeded;
4136- } else if (bo.inputs_.empty()) {
4137+ } else if (bo.inputs.empty()) {
4138 return needed_type;
4139 } else if (bo.total_count() == 0) {
4140 return needed_type;
4141- } else if (bo.current_stats_ > 10 + 70 / bo.outputs_.size()) {
4142- return needed_type;
4143+ } else if (bo.current_stats > 10 + 70 / bo.outputs.size()) {
4144+ assert (bo.last_building_built != kNever);
4145+ if (gametime < bo.last_building_built + 10 * 60 * 1000) {
4146+ // Previous building built less then 10 minutes ago
4147+ // Wait a bit, perhaps average utilization will drop down in the meantime
4148+ return BuildingNecessity::kNeededPending;
4149+ } else {
4150+ return needed_type;
4151+ }
4152 } else if (needs_second_for_upgrade) {
4153 return needed_type;
4154 } else {
4155 return BuildingNecessity::kForbidden;
4156 }
4157- } else if (bo.is_shipyard_) {
4158+ } else if (bo.is_shipyard) {
4159 return BuildingNecessity::kAllowed;
4160- } else if (bo.max_needed_preciousness_ == 0) {
4161+ } else if (bo.max_needed_preciousness == 0) {
4162 return BuildingNecessity::kNotNeeded;
4163 } else {
4164 return BuildingNecessity::kForbidden;
4165@@ -4152,9 +4187,9 @@
4166 assert (bo.total_count() > 0);
4167 if (bo.total_count() == 1) {
4168 return BuildingNecessity::kNeeded;
4169- } else if (bo.max_preciousness_ >= 10 && bo.total_count() == 2) {
4170+ } else if (bo.max_preciousness >= 10 && bo.total_count() == 2) {
4171 return BuildingNecessity::kNeeded;
4172- } else if (bo.current_stats_ > (10 + 70 / bo.outputs_.size()) / 2) {
4173+ } else if (bo.current_stats > (10 + 70 / bo.outputs.size()) / 2) {
4174 return BuildingNecessity::kNeeded;
4175 } else {
4176 return BuildingNecessity::kNotNeeded;
4177@@ -4218,15 +4253,15 @@
4178 uint32_t DefaultAI::get_stocklevel(BuildingObserver& bo) {
4179 uint32_t count = std::numeric_limits<uint32_t>::max();
4180
4181- if (!bo.outputs_.empty()) {
4182+ if (!bo.outputs.empty()) {
4183 for (EconomyObserver* observer : economies) {
4184 // Don't check if the economy has no warehouse.
4185 if (observer->economy.warehouses().empty()) {
4186 continue;
4187 }
4188
4189- for (uint32_t m = 0; m < bo.outputs_.size(); ++m) {
4190- DescriptionIndex wt(static_cast<size_t>(bo.outputs_.at(m)));
4191+ for (uint32_t m = 0; m < bo.outputs.size(); ++m) {
4192+ DescriptionIndex wt(static_cast<size_t>(bo.outputs.at(m)));
4193 if (count > observer->economy.stock_ware(wt)) {
4194 count = observer->economy.stock_ware(wt);
4195 }
4196@@ -4336,10 +4371,10 @@
4197 }
4198
4199 // changing priority if basic
4200- if (tso.bo->trainingsite_type_ == TrainingSiteType::kBasic) {
4201- for (uint32_t k = 0; k < tso.bo->inputs_.size(); ++k) {
4202+ if (tso.bo->trainingsite_type == TrainingSiteType::kBasic) {
4203+ for (uint32_t k = 0; k < tso.bo->inputs.size(); ++k) {
4204 game().send_player_set_ware_priority(
4205- *ts, wwWARE, tso.bo->inputs_.at(k), HIGH_PRIORITY);
4206+ *ts, wwWARE, tso.bo->inputs.at(k), HIGH_PRIORITY);
4207 }
4208 }
4209
4210@@ -4356,7 +4391,7 @@
4211 std::vector<WaresQueue*> const warequeues2 = tso.site->warequeues();
4212 nr_warequeues = warequeues2.size();
4213 for (size_t i = 0; i < nr_warequeues; ++i) {
4214- if (tso.bo->substitute_inputs_.count(warequeues2[i]->get_ware()) > 0) {
4215+ if (tso.bo->substitute_inputs.count(warequeues2[i]->get_ware()) > 0) {
4216 filled += warequeues2[i]->get_filled();
4217 }
4218 }
4219@@ -4366,7 +4401,7 @@
4220
4221 // checking non subsitutes
4222 for (size_t i = 0; i < nr_warequeues; ++i) {
4223- if (tso.bo->substitute_inputs_.count(warequeues2[i]->get_ware()) == 0) {
4224+ if (tso.bo->substitute_inputs.count(warequeues2[i]->get_ware()) == 0) {
4225 const uint32_t required_amount
4226 =
4227 (warequeues2[i]->get_max_fill() < 5) ? warequeues2[i]->get_max_fill() : 5;
4228@@ -4434,7 +4469,7 @@
4229 // first we make sure there is no enemy at all
4230 if (map.find_fields(Area<FCoords>(f, vision + 4), nullptr, find_enemy) == 0) {
4231
4232- mso.enemies_nearby_ = false;
4233+ mso.enemies_nearby = false;
4234
4235 // If no enemy in sight - decrease the number of stationed soldiers
4236 // as long as it is > 1 - BUT take care that there is a warehouse in the
4237@@ -4462,13 +4497,13 @@
4238 map.find_fields(Area<FCoords>(f, vision), nullptr, find_ally);
4239
4240 int16_t score = 0;
4241- score += (bf.area_military_capacity_ > 6);
4242- score += (bf.area_military_capacity_ > 22);
4243- score += (bf.area_military_presence_ > 4);
4244- score += (bf.military_loneliness_ < (180 + persistent_data->ai_personality_military_loneliness));
4245- score += (bf.military_stationed_ > 2);
4246+ score += (bf.area_military_capacity > 6);
4247+ score += (bf.area_military_capacity > 22);
4248+ score += (bf.area_military_presence > 4);
4249+ score += (bf.military_loneliness < (180 + persistent_data->ai_personality_military_loneliness));
4250+ score += (bf.military_stationed > 2);
4251 score -= size_penalty;
4252- score += ((bf.unowned_land_nearby_ + allyOwnedFields) < 10);
4253+ score += ((bf.unowned_land_nearby + allyOwnedFields) < 10);
4254
4255 if (score >= 4) {
4256 if (ms->get_playercaps() & Widelands::Building::PCap_Dismantle) {
4257@@ -4487,7 +4522,7 @@
4258 uint32_t unused1 = 0;
4259 uint16_t unused2 = 0;
4260
4261- mso.enemies_nearby_ = false;
4262+ mso.enemies_nearby = false;
4263
4264 // yes enemy is nearby, but still we must distinguish whether
4265 // he is accessible (over the land)
4266@@ -4507,7 +4542,7 @@
4267 changed = true;
4268 }
4269
4270- mso.enemies_nearby_ = true;
4271+ mso.enemies_nearby = true;
4272 enemy_last_seen_ = gametime;
4273 } else { // otherwise decrease soldiers
4274 uint32_t const j = ms->soldier_capacity();
4275@@ -4544,21 +4579,24 @@
4276 return prio;
4277 }
4278
4279- if (bf.enemy_nearby_ || bf.near_border_) {
4280+ if (bf.enemy_nearby || bf.near_border) {
4281 prio /= 2;
4282 }
4283
4284 // if unowned territory nearby
4285- prio -= bf.unowned_land_nearby_ / 4;
4286+ prio -= bf.unowned_land_nearby / 4;
4287
4288 // further decrease the score if enemy nearby
4289- if (bf.enemy_nearby_) {
4290+ if (bf.enemy_nearby) {
4291 prio -= 10;
4292 }
4293
4294 // and if close (up to 2 fields away) from border
4295- if (bf.near_border_) {
4296+ if (bf.near_border) {
4297 prio -= 10;
4298+ if (spots_ < kSpotsEnough) {
4299+ prio += 3 * (spots_ - kSpotsEnough);
4300+ }
4301 }
4302
4303 return prio;
4304@@ -4567,25 +4605,25 @@
4305 void DefaultAI::consider_productionsite_influence(BuildableField& field,
4306 Coords coords,
4307 const BuildingObserver& bo) {
4308- if (bo.space_consumer_ && !bo.plants_trees_ &&
4309+ if (bo.space_consumer && !bo.plants_trees &&
4310 game().map().calc_distance(coords, field.coords) < 8) {
4311- ++field.space_consumers_nearby_;
4312- }
4313-
4314- for (size_t i = 0; i < bo.inputs_.size(); ++i) {
4315- ++field.consumers_nearby_.at(bo.inputs_.at(i));
4316- }
4317-
4318- for (size_t i = 0; i < bo.outputs_.size(); ++i) {
4319- ++field.producers_nearby_.at(bo.outputs_.at(i));
4320- }
4321-
4322- if (bo.production_hint_ >= 0) {
4323- ++field.supporters_nearby_.at(bo.production_hint_);
4324- }
4325-
4326- if (bo.plants_trees_) {
4327- ++field.rangers_nearby_;
4328+ ++field.space_consumers_nearby;
4329+ }
4330+
4331+ for (size_t i = 0; i < bo.inputs.size(); ++i) {
4332+ ++field.consumers_nearby.at(bo.inputs.at(i));
4333+ }
4334+
4335+ for (size_t i = 0; i < bo.outputs.size(); ++i) {
4336+ ++field.producers_nearby.at(bo.outputs.at(i));
4337+ }
4338+
4339+ if (bo.production_hint >= 0) {
4340+ ++field.supporters_nearby.at(bo.production_hint);
4341+ }
4342+
4343+ if (bo.plants_trees) {
4344+ ++field.rangers_nearby;
4345 }
4346 }
4347
4348@@ -4693,8 +4731,8 @@
4349 // we must identify which mine matches the productionsite a note reffers to
4350 for (std::list<ProductionSiteObserver>::iterator i = mines_.begin(); i != mines_.end(); ++i)
4351 if (i->site == &site) {
4352- if (i->no_resources_since_ > gametime) {
4353- i->no_resources_since_ = gametime;
4354+ if (i->no_resources_since > gametime) {
4355+ i->no_resources_since = gametime;
4356 }
4357 break;
4358 }
4359@@ -4732,7 +4770,7 @@
4360 Map& map = game().map();
4361 std::list<uint32_t> queue;
4362 std::unordered_set<uint32_t> done;
4363- queue.push_front(coords_hash(starting_spot));
4364+ queue.push_front(starting_spot.hash());
4365 PlayerNumber const pn = player_->player_number();
4366
4367 while (!queue.empty()) {
4368@@ -4744,7 +4782,7 @@
4369
4370 done.insert(queue.front());
4371
4372- Coords tmp_coords = coords_unhash(queue.front());
4373+ Coords tmp_coords = Coords::unhash(queue.front());
4374
4375 // if beyond range
4376 if (map.calc_distance(starting_spot, tmp_coords) > max_distance) {
4377@@ -4777,7 +4815,7 @@
4378
4379 // if owned by enemy
4380 if (type == WalkSearch::kEnemy && f->get_owned_by() != pn) {
4381- // for case I am not member of a team
4382+ // in case I am not member of a team
4383 if (player_->team_number() == 0) {
4384 *tested_fields = done.size();
4385 return true;
4386@@ -4807,7 +4845,7 @@
4387 map.get_neighbour(tmp_coords, dir, &neigh_coords1);
4388 Coords neigh_coords2;
4389 map.get_neighbour(neigh_coords1, dir, &neigh_coords2);
4390- queue.push_front(coords_hash(neigh_coords2));
4391+ queue.push_front(neigh_coords2.hash());
4392 }
4393 }
4394 *tested_fields = done.size();
4395@@ -4889,11 +4927,11 @@
4396 Map& map = game().map();
4397 const int32_t gametime = game().get_gametime();
4398
4399- // second we put current spot into visited_spots_
4400+ // second we put current spot into visited_spots
4401 bool first_time_here = false;
4402- if (so.visited_spots_.count(coords_hash(so.ship->get_position())) == 0) {
4403+ if (so.visited_spots.count(so.ship->get_position().hash()) == 0) {
4404 first_time_here = true;
4405- so.visited_spots_.insert(coords_hash(so.ship->get_position()));
4406+ so.visited_spots.insert(so.ship->get_position().hash());
4407 }
4408
4409 // If we have portspace following options are avaiable:
4410@@ -4914,9 +4952,7 @@
4411 MapRegion<Area<FCoords>> mr(
4412 game().map(), Area<FCoords>(map.get_fcoords(so.ship->exp_port_spaces().front()), 8));
4413 do {
4414- BlockedField blocked2(
4415- map.get_fcoords(*(mr.location().field)), gametime + 5 * 60 * 1000);
4416- blocked_fields.push_back(blocked2);
4417+ blocked_fields.add(mr.location(), game().get_gametime() + 5 * 60 * 1000);
4418 } while (mr.advance(map));
4419
4420 return;
4421@@ -4980,24 +5016,24 @@
4422
4423 BuildingObserver& bo = get_building_observer(b.descr().name().c_str());
4424
4425- if (bo.type == BuildingObserver::CONSTRUCTIONSITE) {
4426+ if (bo.type == BuildingObserver::Type::kConstructionsite) {
4427 BuildingObserver& target_bo =
4428 get_building_observer(dynamic_cast<const ConstructionSite&>(b).building().name().c_str());
4429- ++target_bo.cnt_under_construction_;
4430- if (target_bo.type == BuildingObserver::PRODUCTIONSITE) {
4431+ ++target_bo.cnt_under_construction;
4432+ if (target_bo.type == BuildingObserver::Type::kProductionsite) {
4433 ++num_prod_constructionsites;
4434 }
4435- if (target_bo.type == BuildingObserver::MILITARYSITE) {
4436+ if (target_bo.type == BuildingObserver::Type::kMilitarysite) {
4437 msites_per_size[target_bo.desc->get_size()].in_construction += 1;
4438 }
4439- if (target_bo.type == BuildingObserver::MINE) {
4440- mines_per_type[target_bo.mines_].in_construction += 1;
4441+ if (target_bo.type == BuildingObserver::Type::kMine) {
4442+ mines_per_type[target_bo.mines].in_construction += 1;
4443 }
4444- if (target_bo.type == BuildingObserver::TRAININGSITE) {
4445- if (target_bo.trainingsite_type_ == TrainingSiteType::kBasic) {
4446+ if (target_bo.type == BuildingObserver::Type::kTrainingsite) {
4447+ if (target_bo.trainingsite_type == TrainingSiteType::kBasic) {
4448 ts_basic_const_count_ += 1;
4449 }
4450- if (target_bo.trainingsite_type_ == TrainingSiteType::kAdvanced) {
4451+ if (target_bo.trainingsite_type == TrainingSiteType::kAdvanced) {
4452 ts_advanced_const_count_ += 1;
4453 }
4454 }
4455@@ -5005,72 +5041,74 @@
4456 set_taskpool_task_time(game().get_gametime(), SchedulerTaskId::kRoadCheck);
4457
4458 } else {
4459- ++bo.cnt_built_;
4460+ ++bo.cnt_built;
4461+ const uint32_t gametime = game().get_gametime();
4462+ bo.last_building_built = gametime;
4463
4464- if (bo.type == BuildingObserver::PRODUCTIONSITE) {
4465+ if (bo.type == BuildingObserver::Type::kProductionsite) {
4466 productionsites.push_back(ProductionSiteObserver());
4467 productionsites.back().site = &dynamic_cast<ProductionSite&>(b);
4468 productionsites.back().bo = &bo;
4469- productionsites.back().bo->new_building_overdue_ = 0;
4470- productionsites.back().built_time_ = game().get_gametime();
4471- productionsites.back().unoccupied_till_ = game().get_gametime();
4472- productionsites.back().stats_zero_ = 0;
4473- productionsites.back().no_resources_since_ = kNever;
4474- productionsites.back().bo->unoccupied_count_ += 1;
4475- if (bo.is_shipyard_) {
4476+ productionsites.back().bo->new_building_overdue = 0;
4477+ productionsites.back().built_time = gametime;
4478+ productionsites.back().unoccupied_till = gametime;
4479+ productionsites.back().stats_zero = 0;
4480+ productionsites.back().no_resources_since = kNever;
4481+ productionsites.back().bo->unoccupied_count += 1;
4482+ if (bo.is_shipyard) {
4483 marine_task_queue.push_back(kStopShipyard);
4484 marine_task_queue.push_back(kReprioritize);
4485 }
4486
4487- for (uint32_t i = 0; i < bo.outputs_.size(); ++i)
4488- ++wares.at(bo.outputs_.at(i)).producers_;
4489+ for (uint32_t i = 0; i < bo.outputs.size(); ++i)
4490+ ++wares.at(bo.outputs.at(i)).producers;
4491
4492- for (uint32_t i = 0; i < bo.inputs_.size(); ++i)
4493- ++wares.at(bo.inputs_.at(i)).consumers_;
4494- } else if (bo.type == BuildingObserver::MINE) {
4495+ for (uint32_t i = 0; i < bo.inputs.size(); ++i)
4496+ ++wares.at(bo.inputs.at(i)).consumers;
4497+ } else if (bo.type == BuildingObserver::Type::kMine) {
4498 mines_.push_back(ProductionSiteObserver());
4499 mines_.back().site = &dynamic_cast<ProductionSite&>(b);
4500 mines_.back().bo = &bo;
4501- mines_.back().built_time_ = game().get_gametime();
4502- mines_.back().no_resources_since_ = kNever;
4503- mines_.back().bo->unoccupied_count_ += 1;
4504-
4505- for (uint32_t i = 0; i < bo.outputs_.size(); ++i)
4506- ++wares.at(bo.outputs_.at(i)).producers_;
4507-
4508- for (uint32_t i = 0; i < bo.inputs_.size(); ++i)
4509- ++wares.at(bo.inputs_.at(i)).consumers_;
4510-
4511- mines_per_type[bo.mines_].finished += 1;
4512-
4513- } else if (bo.type == BuildingObserver::MILITARYSITE) {
4514+ mines_.back().built_time = gametime;
4515+ mines_.back().no_resources_since = kNever;
4516+ mines_.back().bo->unoccupied_count += 1;
4517+
4518+ for (uint32_t i = 0; i < bo.outputs.size(); ++i)
4519+ ++wares.at(bo.outputs.at(i)).producers;
4520+
4521+ for (uint32_t i = 0; i < bo.inputs.size(); ++i)
4522+ ++wares.at(bo.inputs.at(i)).consumers;
4523+
4524+ mines_per_type[bo.mines].finished += 1;
4525+
4526+ } else if (bo.type == BuildingObserver::Type::kMilitarysite) {
4527 militarysites.push_back(MilitarySiteObserver());
4528 militarysites.back().site = &dynamic_cast<MilitarySite&>(b);
4529 militarysites.back().bo = &bo;
4530 militarysites.back().checks = bo.desc->get_size();
4531- militarysites.back().enemies_nearby_ = true;
4532+ militarysites.back().enemies_nearby = true;
4533 msites_per_size[bo.desc->get_size()].finished += 1;
4534 vacant_mil_positions_ += 2; // at least some indication that there are vacant positions
4535
4536- } else if (bo.type == BuildingObserver::TRAININGSITE) {
4537+ } else if (bo.type == BuildingObserver::Type::kTrainingsite) {
4538 ts_without_trainers_ += 1;
4539 trainingsites.push_back(TrainingSiteObserver());
4540 trainingsites.back().site = &dynamic_cast<TrainingSite&>(b);
4541 trainingsites.back().bo = &bo;
4542- if (bo.trainingsite_type_ == TrainingSiteType::kBasic) {
4543+ if (bo.trainingsite_type == TrainingSiteType::kBasic) {
4544 ts_basic_count_ += 1;
4545 }
4546- if (bo.trainingsite_type_ == TrainingSiteType::kAdvanced) {
4547+ if (bo.trainingsite_type == TrainingSiteType::kAdvanced) {
4548 ts_advanced_count_ += 1;
4549 }
4550 vacant_mil_positions_ += 8; // at least some indication that there are vacant positions
4551
4552- } else if (bo.type == BuildingObserver::WAREHOUSE) {
4553+ } else if (bo.type == BuildingObserver::Type::kWarehouse) {
4554 ++numof_warehouses_;
4555 warehousesites.push_back(WarehouseSiteObserver());
4556 warehousesites.back().site = &dynamic_cast<Warehouse&>(b);
4557 warehousesites.back().bo = &bo;
4558- if (bo.is_port_) {
4559+ if (bo.is_port) {
4560 ++num_ports;
4561 seafaring_economy = true;
4562 // unblock nearby fields, might be used for other buildings...
4563@@ -5078,7 +5116,7 @@
4564 MapRegion<Area<FCoords>> mr(
4565 map, Area<FCoords>(map.get_fcoords(warehousesites.back().site->get_position()), 3));
4566 do {
4567- const int32_t hash = coords_hash(map.get_fcoords(*(mr.location().field)));
4568+ const int32_t hash = map.get_fcoords(*(mr.location().field)).hash();
4569 if (port_reserved_coords.count(hash) > 0)
4570 port_reserved_coords.erase(hash);
4571 } while (mr.advance(map));
4572@@ -5092,46 +5130,46 @@
4573
4574 BuildingObserver& bo = get_building_observer(b.descr().name().c_str());
4575
4576- if (bo.type == BuildingObserver::CONSTRUCTIONSITE) {
4577+ if (bo.type == BuildingObserver::Type::kConstructionsite) {
4578 BuildingObserver& target_bo =
4579 get_building_observer(dynamic_cast<const ConstructionSite&>(b).building().name().c_str());
4580- --target_bo.cnt_under_construction_;
4581- if (target_bo.type == BuildingObserver::PRODUCTIONSITE) {
4582+ --target_bo.cnt_under_construction;
4583+ if (target_bo.type == BuildingObserver::Type::kProductionsite) {
4584 --num_prod_constructionsites;
4585 }
4586- if (target_bo.type == BuildingObserver::MILITARYSITE) {
4587+ if (target_bo.type == BuildingObserver::Type::kMilitarysite) {
4588 msites_per_size[target_bo.desc->get_size()].in_construction -= 1;
4589 }
4590- if (target_bo.type == BuildingObserver::MINE) {
4591- mines_per_type[target_bo.mines_].in_construction -= 1;
4592+ if (target_bo.type == BuildingObserver::Type::kMine) {
4593+ mines_per_type[target_bo.mines].in_construction -= 1;
4594 }
4595- if (target_bo.type == BuildingObserver::TRAININGSITE) {
4596- if (target_bo.trainingsite_type_ == TrainingSiteType::kBasic) {
4597+ if (target_bo.type == BuildingObserver::Type::kTrainingsite) {
4598+ if (target_bo.trainingsite_type == TrainingSiteType::kBasic) {
4599 ts_basic_const_count_ -= 1;
4600 assert(ts_basic_const_count_ >= 0);
4601 }
4602- if (target_bo.trainingsite_type_ == TrainingSiteType::kAdvanced) {
4603+ if (target_bo.trainingsite_type == TrainingSiteType::kAdvanced) {
4604 ts_advanced_const_count_ -= 1;
4605 assert(ts_advanced_const_count_ >= 0);
4606 }
4607 }
4608
4609 } else {
4610- --bo.cnt_built_;
4611+ --bo.cnt_built;
4612
4613 // we are not able to reliably identify if lost building is counted in
4614 // unconnected or unoccupied count, but we must adjust the value to
4615 // avoid inconsistency
4616- const uint32_t cnt_built = bo.cnt_built_;
4617- if (bo.unconnected_count_ > cnt_built) {
4618- bo.unconnected_count_ = cnt_built;
4619- }
4620- if (bo.unoccupied_count_ > cnt_built) {
4621- bo.unoccupied_count_ = cnt_built;
4622- }
4623-
4624-
4625- if (bo.type == BuildingObserver::PRODUCTIONSITE) {
4626+ const uint32_t cnt_built = bo.cnt_built;
4627+ if (bo.unconnected_count > cnt_built) {
4628+ bo.unconnected_count = cnt_built;
4629+ }
4630+ if (bo.unoccupied_count > cnt_built) {
4631+ bo.unoccupied_count = cnt_built;
4632+ }
4633+
4634+
4635+ if (bo.type == BuildingObserver::Type::kProductionsite) {
4636
4637 for (std::list<ProductionSiteObserver>::iterator i = productionsites.begin();
4638 i != productionsites.end();
4639@@ -5141,15 +5179,15 @@
4640 break;
4641 }
4642
4643- for (uint32_t i = 0; i < bo.outputs_.size(); ++i) {
4644- --wares.at(bo.outputs_.at(i)).producers_;
4645- }
4646-
4647- for (uint32_t i = 0; i < bo.inputs_.size(); ++i) {
4648- --wares.at(bo.inputs_.at(i)).consumers_;
4649- }
4650-
4651- } else if (bo.type == BuildingObserver::MINE) {
4652+ for (uint32_t i = 0; i < bo.outputs.size(); ++i) {
4653+ --wares.at(bo.outputs.at(i)).producers;
4654+ }
4655+
4656+ for (uint32_t i = 0; i < bo.inputs.size(); ++i) {
4657+ --wares.at(bo.inputs.at(i)).consumers;
4658+ }
4659+
4660+ } else if (bo.type == BuildingObserver::Type::kMine) {
4661 for (std::list<ProductionSiteObserver>::iterator i = mines_.begin(); i != mines_.end();
4662 ++i) {
4663 if (i->site == &b) {
4664@@ -5158,17 +5196,17 @@
4665 }
4666 }
4667
4668- for (uint32_t i = 0; i < bo.outputs_.size(); ++i) {
4669- --wares.at(bo.outputs_.at(i)).producers_;
4670- }
4671-
4672- for (uint32_t i = 0; i < bo.inputs_.size(); ++i) {
4673- --wares.at(bo.inputs_.at(i)).consumers_;
4674- }
4675-
4676- mines_per_type[bo.mines_].finished -= 1;
4677-
4678- } else if (bo.type == BuildingObserver::MILITARYSITE) {
4679+ for (uint32_t i = 0; i < bo.outputs.size(); ++i) {
4680+ --wares.at(bo.outputs.at(i)).producers;
4681+ }
4682+
4683+ for (uint32_t i = 0; i < bo.inputs.size(); ++i) {
4684+ --wares.at(bo.inputs.at(i)).consumers;
4685+ }
4686+
4687+ mines_per_type[bo.mines].finished -= 1;
4688+
4689+ } else if (bo.type == BuildingObserver::Type::kMilitarysite) {
4690 msites_per_size[bo.desc->get_size()].finished -= 1;
4691
4692 for (std::list<MilitarySiteObserver>::iterator i = militarysites.begin();
4693@@ -5179,28 +5217,28 @@
4694 break;
4695 }
4696 }
4697- } else if (bo.type == BuildingObserver::TRAININGSITE) {
4698+ } else if (bo.type == BuildingObserver::Type::kTrainingsite) {
4699
4700 for (std::list<TrainingSiteObserver>::iterator i = trainingsites.begin();
4701 i != trainingsites.end();
4702 ++i) {
4703 if (i->site == &b) {
4704 trainingsites.erase(i);
4705- if (bo.trainingsite_type_ == TrainingSiteType::kBasic) {
4706+ if (bo.trainingsite_type == TrainingSiteType::kBasic) {
4707 ts_basic_count_ -= 1;
4708 assert(ts_basic_count_ >= 0);
4709 }
4710- if (bo.trainingsite_type_ == TrainingSiteType::kAdvanced) {
4711+ if (bo.trainingsite_type == TrainingSiteType::kAdvanced) {
4712 ts_advanced_count_ -= 1;
4713 assert(ts_advanced_count_ >= 0);
4714 }
4715 break;
4716 }
4717 }
4718- } else if (bo.type == BuildingObserver::WAREHOUSE) {
4719+ } else if (bo.type == BuildingObserver::Type::kWarehouse) {
4720 assert(numof_warehouses_ > 0);
4721 --numof_warehouses_;
4722- if (bo.is_port_) {
4723+ if (bo.is_port) {
4724 --num_ports;
4725 }
4726
4727@@ -5217,17 +5255,17 @@
4728 }
4729
4730 // Checks that supply line exists for given building.
4731-// Recursively verify that all inputs_ have a producer.
4732+// Recursively verify that all inputs have a producer.
4733 // TODO(unknown): this function leads to periodic freezes of ~1 second on big games on my system.
4734 // TODO(unknown): It needs profiling and optimization.
4735 // NOTE: This is not needed anymore and it seems it is not missed neither
4736 bool DefaultAI::check_supply(const BuildingObserver& bo) {
4737 size_t supplied = 0;
4738- for (const int16_t& temp_inputs : bo.inputs_) {
4739+ for (const int16_t& temp_inputs : bo.inputs) {
4740 for (const BuildingObserver& temp_building : buildings_) {
4741- if (temp_building.cnt_built_ &&
4742- std::find(temp_building.outputs_.begin(), temp_building.outputs_.end(), temp_inputs) !=
4743- temp_building.outputs_.end() &&
4744+ if (temp_building.cnt_built &&
4745+ std::find(temp_building.outputs.begin(), temp_building.outputs.end(), temp_inputs) !=
4746+ temp_building.outputs.end() &&
4747 check_supply(temp_building)) {
4748 ++supplied;
4749 break;
4750@@ -5235,7 +5273,7 @@
4751 }
4752 }
4753
4754- return supplied == bo.inputs_.size();
4755+ return supplied == bo.inputs.size();
4756 }
4757
4758 // This calculates strength of vector of soldiers, f.e. soldiers in a building or
4759@@ -5301,40 +5339,34 @@
4760 Map& map = game().map();
4761
4762 // define which players are attackable
4763- std::vector<bool> player_attackable;
4764+ std::vector<Attackable> player_attackable;
4765 PlayerNumber const nr_players = map.get_nrplayers();
4766 player_attackable.resize(nr_players);
4767 uint32_t plr_in_game = 0;
4768- uint16_t const pn = player_number();
4769+ Widelands::PlayerNumber const pn = player_number();
4770
4771 iterate_players_existing_novar(p, nr_players, game())++ plr_in_game;
4772
4773 // receiving games statistics and parsing it (reading latest entry)
4774 const Game::GeneralStatsVector& genstats = game().get_general_statistics();
4775
4776- // summing team power, creating team_power std::map of team_number:strength
4777- std::map<TeamNumber, uint32_t> team_power;
4778- for (uint8_t j = 1; j <= plr_in_game; ++j) {
4779- const Player* other = game().get_player(j);
4780- const TeamNumber tm = other ? other->team_number() : 0;
4781- if (tm == 0) {
4782- continue;
4783- }
4784- // for case this is new team
4785- if (team_power.count(tm) == 0) {
4786- // adding this team (number) to vector
4787- team_power[tm] = 0;
4788- }
4789- try {
4790- team_power[tm] += genstats.at(j - 1).miltary_strength.back();
4791- } catch (const std::out_of_range&) {
4792- log("ComputerPlayer(%d): genstats entry missing - size :%d\n",
4793- player_number(),
4794- static_cast<unsigned int>(genstats.size()));
4795+ // Collecting statistics and saving them in player_statistics object
4796+ for (Widelands::TeamNumber j = 1; j <= plr_in_game; ++j) {
4797+ const Player* this_player = game().get_player(j);
4798+ if (this_player) {
4799+ try {
4800+ player_statistics.add(j, this_player->team_number(), genstats.at(j - 1).miltary_strength.back());
4801+ } catch (const std::out_of_range&) {
4802+ log("ComputerPlayer(%d): genstats entry missing - size :%d\n",
4803+ static_cast<unsigned int>(player_number()),
4804+ static_cast<unsigned int>(genstats.size()));
4805+ }
4806 }
4807 }
4808
4809- // defining treshold ratio of own_strength/enemy's_strength
4810+ player_statistics.recalculate_team_power();
4811+
4812+ // defining treshold ratio of own_strength/enemy's strength
4813 uint32_t treshold_ratio = 100;
4814 if (type_ == DefaultAI::Type::kNormal) {
4815 treshold_ratio = 80;
4816@@ -5348,7 +5380,7 @@
4817 // attack, then a campaign is over.
4818 // To start new campaign (=attack again), our strenth must exceed
4819 // target values (calculated above) by some treshold =
4820- // ai_personality_attack_margin_
4821+ // ai_personality_attack_margin
4822 // Once a new campaign started we will fight until
4823 // we get below above treshold or there will be 3
4824 // minutes gap since last attack
4825@@ -5358,65 +5390,37 @@
4826 treshold_ratio += persistent_data->ai_personality_attack_margin;
4827 }
4828
4829- uint32_t my_power = 0;
4830- try {
4831- my_power = genstats.at(pn - 1).miltary_strength.back();
4832- } catch (const std::out_of_range&) {
4833- log("ComputerPlayer(%d): genstats entry missing - size :%d\n",
4834- player_number(),
4835- static_cast<unsigned int>(genstats.size()));
4836- }
4837- // adding power of team (minus my power) divided by 2
4838- // (if I am a part of a team of course)
4839- const TeamNumber team_number = player_->team_number();
4840- if (team_number > 0) {
4841- my_power += (team_power[team_number] - my_power) / 2;
4842- }
4843+ const uint32_t my_power = player_statistics.get_modified_player_power(pn);
4844+
4845
4846 // now we test all players to identify 'attackable' ones
4847- for (uint8_t j = 1; j <= plr_in_game; ++j) {
4848- // if it's me
4849- if (pn == j) {
4850- player_attackable[j - 1] = false;
4851- continue;
4852- }
4853- // if we are the same team
4854- const Player* other = game().get_player(j);
4855- const TeamNumber tm = other ? other->team_number() : 0;
4856- if (team_number > 0 && team_number == tm) {
4857- player_attackable[j - 1] = false;
4858+ for (Widelands::PlayerNumber j = 1; j <= plr_in_game; ++j) {
4859+ // if we are the same team, or it is just me
4860+ if (player_statistics.players_in_same_team(pn, j) || pn == j) {
4861+ player_attackable[j - 1] = Attackable::kNotAttackable;
4862 continue;
4863 }
4864
4865 // now we compare strength
4866- try {
4867- // strength of the other player
4868- uint32_t players_power = 0;
4869- if (!genstats.at(j - 1).miltary_strength.empty()) {
4870- players_power += genstats.at(j - 1).miltary_strength.back();
4871- }
4872- // +power of team (if member of a team)
4873- if (tm > 0) {
4874- players_power += (team_power[tm] - players_power) / 2;
4875- }
4876+ // strength of the other player (considering his team)
4877+ uint32_t players_power = player_statistics.get_modified_player_power(j);
4878
4879- if (players_power == 0) {
4880- player_attackable.at(j - 1) = true;
4881- } else if (my_power * 100 / players_power > treshold_ratio) {
4882- player_attackable.at(j - 1) = true;
4883- } else {
4884- player_attackable.at(j - 1) = false;
4885- }
4886- } catch (const std::out_of_range&) {
4887- log("ComputerPlayer(%d): genstats entry missing - size :%d\n",
4888- player_number(),
4889- static_cast<unsigned int>(genstats.size()));
4890- player_attackable.at(j - 1) = false;
4891+ if (players_power == 0) {
4892+ player_attackable.at(j - 1) = Attackable::kAttackable;
4893+ } else if (my_power * 100 / players_power > treshold_ratio * 8) {
4894+ player_attackable.at(j - 1) = Attackable::kAttackableVeryWeak;
4895+ } else if (my_power * 100 / players_power > treshold_ratio * 4) {
4896+ player_attackable.at(j - 1) = Attackable::kAttackableAndWeak;
4897+ } else if (my_power * 100 / players_power > treshold_ratio) {
4898+ player_attackable.at(j - 1) = Attackable::kAttackable;
4899+ } else {
4900+ player_attackable.at(j - 1) = Attackable::kNotAttackable;
4901 }
4902+
4903 }
4904
4905 // first we scan vicitnity of couple of militarysites to get new enemy sites
4906- // militarysites rotate
4907+ // Militarysites rotate (see check_militarysites())
4908 int32_t i = 0;
4909 for (MilitarySiteObserver mso : militarysites) {
4910 i += 1;
4911@@ -5438,15 +5442,15 @@
4912 for (uint32_t j = 0; j < immovables.size(); ++j) {
4913 if (upcast(MilitarySite const, bld, immovables.at(j).object)) {
4914 if (player_->is_hostile(bld->owner())) {
4915- if (enemy_sites.count(coords_hash(bld->get_position())) == 0) {
4916- enemy_sites[coords_hash(bld->get_position())] = EnemySiteObserver();
4917+ if (enemy_sites.count(bld->get_position().hash()) == 0) {
4918+ enemy_sites[bld->get_position().hash()] = EnemySiteObserver();
4919 }
4920 }
4921 }
4922 if (upcast(Warehouse const, wh, immovables.at(j).object)) {
4923 if (player_->is_hostile(wh->owner())) {
4924- if (enemy_sites.count(coords_hash(wh->get_position())) == 0) {
4925- enemy_sites[coords_hash(wh->get_position())] = EnemySiteObserver();
4926+ if (enemy_sites.count(wh->get_position().hash()) == 0) {
4927+ enemy_sites[wh->get_position().hash()] = EnemySiteObserver();
4928 }
4929 }
4930 }
4931@@ -5506,6 +5510,8 @@
4932 ;
4933 }
4934
4935+ const bool strong_enough = player_statistics.strong_enough(pn);
4936+
4937 for (std::map<uint32_t, EnemySiteObserver>::iterator site = enemy_sites.begin();
4938 site != enemy_sites.end();
4939 ++site) {
4940@@ -5523,12 +5529,12 @@
4941 bool is_attackable = false;
4942 // we cannot attack unvisible site and there is no other way to find out
4943 const bool is_visible = (1 < player_->vision
4944- (Map::get_index(coords_unhash(site->first), map.get_width())));
4945+ (Map::get_index(Coords::unhash(site->first), map.get_width())));
4946 uint16_t owner_number = 100;
4947
4948 // testing if we can attack the building - result is a flag
4949 // if we dont get a flag, we remove the building from observers list
4950- FCoords f = map.get_fcoords(coords_unhash(site->first));
4951+ FCoords f = map.get_fcoords(Coords::unhash(site->first));
4952 uint32_t site_to_be_removed = std::numeric_limits<uint32_t>::max();
4953 Flag* flag = nullptr;
4954
4955@@ -5576,7 +5582,7 @@
4956 }
4957 }
4958
4959- site->second.warehouse_ = is_warehouse;
4960+ site->second.is_warehouse = is_warehouse;
4961
4962 // getting rid of default
4963 if (site->second.last_time_attackable == kNever) {
4964@@ -5598,7 +5604,9 @@
4965
4966 if (site->second.attack_soldiers_strength > 0
4967 &&
4968- player_attackable[owner_number - 1]) {
4969+ (player_attackable[owner_number - 1] == Attackable::kAttackable ||
4970+ player_attackable[owner_number - 1] == Attackable::kAttackableAndWeak ||
4971+ player_attackable[owner_number - 1] == Attackable::kAttackableVeryWeak)) {
4972 site->second.score = site->second.attack_soldiers_strength - site->second.defenders_strength / 2;
4973
4974 if (is_warehouse) {
4975@@ -5626,6 +5634,19 @@
4976 // Applying (decreasing score) if trainingsites are not working
4977 site->second.score += training_score;
4978
4979+ // We have an advantage over stongest opponent
4980+ if (strong_enough) {
4981+ site->second.score += 3;
4982+ }
4983+
4984+ // Enemy is too weak, be more aggressive attacking him
4985+ if (player_attackable[owner_number - 1] == Attackable::kAttackableAndWeak) {
4986+ site->second.score += 4;
4987+ }
4988+ if (player_attackable[owner_number - 1] == Attackable::kAttackableVeryWeak) {
4989+ site->second.score += 8;
4990+ }
4991+
4992 // treating no attack score
4993 if (site->second.no_attack_counter < 0) {
4994 // we cannot attack yet
4995@@ -5682,7 +5703,7 @@
4996 assert(enemy_sites.count(best_target) > 0);
4997
4998 // attacking
4999- FCoords f = map.get_fcoords(coords_unhash(best_target));
5000+ FCoords f = map.get_fcoords(Coords::unhash(best_target));
The diff has been truncated for viewing.

Subscribers

People subscribed via source and target branches

to status/vote changes: