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

Proposed by TiborB
Status: Merged
Merged at revision: 7567
Proposed branch: lp:~widelands-dev/widelands/ai_persistent_data
Merge into: lp:widelands
Diff against target: 3712 lines (+1264/-792)
50 files modified
src/ai/ai_help_structs.h (+47/-11)
src/ai/ai_hints.cc (+1/-1)
src/ai/defaultai.cc (+1042/-705)
src/ai/defaultai.h (+35/-23)
src/game_io/game_player_info_packet.cc (+11/-1)
src/logic/player.cc (+40/-5)
src/logic/player.h (+22/-0)
tribes/atlanteans/blackroot_farm/conf (+1/-0)
tribes/atlanteans/farm/conf (+2/-2)
tribes/atlanteans/fish_breeders_house/conf (+2/-1)
tribes/atlanteans/foresters_house/conf (+1/-1)
tribes/atlanteans/hunters_house/conf (+1/-1)
tribes/atlanteans/labyrinth/conf (+1/-0)
tribes/atlanteans/planks/conf (+1/-1)
tribes/atlanteans/quarry/conf (+2/-1)
tribes/atlanteans/sawmill/conf (+2/-2)
tribes/atlanteans/smokery/conf (+1/-1)
tribes/atlanteans/spiderfarm/conf (+2/-2)
tribes/atlanteans/toolsmithy/conf (+1/-1)
tribes/atlanteans/weaving-mill/conf (+2/-2)
tribes/atlanteans/well/conf (+2/-2)
tribes/atlanteans/woodcutters_house/conf (+2/-1)
tribes/barbarians/bakery/conf (+1/-1)
tribes/barbarians/farm/conf (+1/-1)
tribes/barbarians/hardener/conf (+2/-1)
tribes/barbarians/hunters_hut/conf (+1/-1)
tribes/barbarians/lime_kiln/conf (+3/-0)
tribes/barbarians/lumberjacks_hut/conf (+2/-1)
tribes/barbarians/metalworks/conf (+2/-2)
tribes/barbarians/quarry/conf (+1/-1)
tribes/barbarians/rangers_hut/conf (+1/-0)
tribes/barbarians/reed_yard/conf (+2/-1)
tribes/barbarians/smelting_works/conf (+1/-1)
tribes/barbarians/trainingcamp/conf (+1/-0)
tribes/barbarians/well/conf (+2/-1)
tribes/empire/armorsmithy/conf (+2/-1)
tribes/empire/bakery/conf (+1/-0)
tribes/empire/bread/conf (+1/-1)
tribes/empire/flour/conf (+1/-1)
tribes/empire/foresters_house/conf (+1/-0)
tribes/empire/lumberjacks_house/conf (+2/-1)
tribes/empire/piggery/conf (+1/-1)
tribes/empire/quarry/conf (+2/-1)
tribes/empire/sawmill/conf (+2/-2)
tribes/empire/stonemasons_house/conf (+2/-2)
tribes/empire/toolsmithy/conf (+2/-2)
tribes/empire/vineyard/conf (+1/-1)
tribes/empire/well/conf (+2/-1)
tribes/empire/winery/conf (+2/-2)
tribes/empire/wood/conf (+1/-1)
To merge this branch: bzr merge lp:~widelands-dev/widelands/ai_persistent_data
Reviewer Review Type Date Requested Status
GunChleoc Approve
TiborB Needs Resubmitting
Review via email: mp+271853@code.launchpad.net

Description of the change

This is extension of player class to keep some AI data. Not all, only handfull of them. So the savegame compatibility is broken.

This contains also redesign of placing of new buidings - both production and militarysites. I tried to simplify the code and improve performance.

I also added a "time aspect" - this means the score of a building reflects also how long the building has been needed.

There are two bugs attached, these issue should be fixed / significantly improved.

The change is really big, and I spent quite a lot of time on tweaking this. I know it will be near to imposible for anyone to properly review this and understand the code. But you can still test it in game :)

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

Please hold on, I will do some changes and resubmit...

Revision history for this message
TiborB (tiborb95) wrote :

should be again ready for review

review: Needs Resubmitting
Revision history for this message
GunChleoc (gunchleoc) wrote :

I have added 2 replays to https://bugs.launchpad.net/widelands/+bug/1499678 - seems like this still needs some tweaking.

Revision history for this message
TiborB (tiborb95) wrote :

I will look at replays, of course.

But do you want to say that AI for atlanteans is systematically weaker then for other tribes? There is only one AI, but there are some aspects that can make difference, of course. I have never tried to compare performance per tribe. But I will investigate...

Revision history for this message
TiborB (tiborb95) wrote :

But you replays are not good, both are too short and one even fails to load altogether

Revision history for this message
GunChleoc (gunchleoc) wrote :

I didn't know that there was a basic binary file to add in addition to the dir, which I have now accidentally deleted. So, I'll have to recreate them. I player Long, Long Way with the first 3 AIs set to Atlanteans and the rest to Barbarians and Empire.

Revision history for this message
GunChleoc (gunchleoc) wrote :

I can't say anything about how good the heuristics are, but I have added some code style comments / ideas.

Revision history for this message
TiborB (tiborb95) wrote :

Thanks for review, I will incorporate comments (most of them at least :)). See also my comments to your comments in the diff.

Revision history for this message
GunChleoc (gunchleoc) wrote :

Added comments to your comments :)

Revision history for this message
TiborB (tiborb95) wrote :

my turn now, see my comments to your comments...

Revision history for this message
GunChleoc (gunchleoc) wrote :

Dito :)

I just noticed that you didn't increase the version number for the savegame packet where you made the changes. This is needed so that Widelands will show an error message instead of crashing when a user tries to load an older game.

Revision history for this message
TiborB (tiborb95) wrote :

@GunChleoc - I incorporated you comments (most of them). Also see one comment in the diff.

Revision history for this message
TiborB (tiborb95) wrote :

Oh, I forget about that packet - I will look at it...

Revision history for this message
TiborB (tiborb95) wrote :

packet increased, see question in diff.

Revision history for this message
GunChleoc (gunchleoc) wrote :

Increase it to 17 please.

Revision history for this message
TiborB (tiborb95) wrote :

done, trunk merged...

just another issue, when I tried to open some random older savegame - the game crashed with "pure virtual method called" - perhaps problem with conf files... Is not there a better way how to identify incompatible savegame?

Revision history for this message
TiborB (tiborb95) wrote :

Oh, this is bt I got:

#0 0xb7fdcd3c in __kernel_vsyscall ()
#1 0xb784b307 in __GI_raise (sig=sig@entry=6) at ../nptl/sysdeps/unix/sysv/linux/raise.c:56
#2 0xb784c9c3 in __GI_abort () at abort.c:89
#3 0xb7a77a25 in __gnu_cxx::__verbose_terminate_handler() () from /usr/lib/i386-linux-gnu/libstdc++.so.6
#4 0xb7a75733 in ?? () from /usr/lib/i386-linux-gnu/libstdc++.so.6
#5 0xb7a757ad in std::terminate() () from /usr/lib/i386-linux-gnu/libstdc++.so.6
#6 0xb7a76514 in __cxa_pure_virtual () from /usr/lib/i386-linux-gnu/libstdc++.so.6
#7 0x08c12013 in ChatOverlay::Impl::recompute (this=0x9cbd048) at /var/widelands/ai_persistent_data/src/wui/chatoverlay.cc:119
#8 0x08c11fcd in ChatOverlay::recompute (this=0x9cbcfd8) at /var/widelands/ai_persistent_data/src/wui/chatoverlay.cc:105
#9 0x08a77d7e in InteractiveBase::InteractiveBase(Widelands::EditorGameBase&, Section&)::{lambda(GraphicResolutionChanged const&)#1}::operator()(GraphicResolutionChanged const&) const () at /var/widelands/ai_persistent_data/src/wui/interactive_base.cc:115
#10 0x08a7bf01 in std::_Function_handler<void(const GraphicResolutionChanged&), InteractiveBase::InteractiveBase(Widelands::EditorGameBase&, Section&)::<lambda(const GraphicResolutionChanged&)> >::_M_invoke(const std::_Any_data &, const GraphicResolutionChanged &) (__functor=..., __args#0=...)
    at /usr/include/c++/4.9/functional:2039
#11 0x0885b94b in std::function<void (GraphicResolutionChanged const&)>::operator()(GraphicResolutionChanged const&) const (this=0x9a891bc, __args#0=...)
    at /usr/include/c++/4.9/functional:2439
#12 0x0885b753 in Notifications::NotificationsManager::publish<GraphicResolutionChanged> (this=0x917dd80 <Notifications::NotificationsManager::get()::instance>,
    message=...) at /var/widelands/ai_persistent_data/src/notifications/notifications_impl.h:75
#13 0x0885affb in Notifications::publish<GraphicResolutionChanged> (message=...) at /var/widelands/ai_persistent_data/src/notifications/notifications.h:51
#14 0x0885a48d in Graphic::resolution_changed (this=0x91ea080) at /var/widelands/ai_persistent_data/src/graphic/graphic.cc:193
#15 0x0885a3d5 in Graphic::change_resolution (this=0x91ea080, w=1200, h=900) at /var/widelands/ai_persistent_data/src/graphic/graphic.cc:182
#16 0x087be6fb in WLApplication::refresh_graphics (this=0x9181f38) at /var/widelands/ai_persistent_data/src/wlapplication.cc:709
#17 0x087c113e in WLApplication::mainmenu (this=0x9181f38) at /var/widelands/ai_persistent_data/src/wlapplication.cc:1042
#18 0x087bd8b4 in WLApplication::run (this=0x9181f38) at /var/widelands/ai_persistent_data/src/wlapplication.cc:456
#19 0x087bbfd5 in main (argc=1, argv=0xbffffa24) at /var/widelands/ai_persistent_data/src/main.cc:155

Is it related to notifications? Is it specific to this branch? I dont know...

Revision history for this message
TiborB (tiborb95) wrote :

sorry, I wanted to say chat, not notifications

Revision history for this message
GunChleoc (gunchleoc) wrote :

I am getting this error on trunk as well.

Revision history for this message
TiborB (tiborb95) wrote :

So it has nothing to do with savegame (in)compatibility probably...

Revision history for this message
GunChleoc (gunchleoc) wrote :

My guess is that it does - but not caused by this branch. So, this can go in now :)

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'src/ai/ai_help_structs.h'
2--- src/ai/ai_help_structs.h 2015-08-19 19:29:56 +0000
3+++ src/ai/ai_help_structs.h 2015-10-24 18:56:46 +0000
4@@ -42,6 +42,8 @@
5 class MilitarySite;
6
7 enum class ExtendedBool : uint8_t {kUnset, kTrue, kFalse};
8+enum class BuildingNecessity : uint8_t
9+ {kForced, kNeeded, kNotNeeded, kUnset, kNotBuildable, kAllowed, kNeededPending};
10
11 struct CheckStepRoadAI {
12 CheckStepRoadAI(Player* const pl, uint8_t const mc, bool const oe)
13@@ -239,7 +241,7 @@
14 uint8_t unowned_land_nearby_;
15 // to identify that field is too close to border and no production building should be built there
16 bool near_border_;
17- uint8_t unowned_mines_pots_nearby_;
18+ uint8_t unowned_mines_spots_nearby_;
19 uint8_t trees_nearby_;
20 uint8_t stones_nearby_;
21 int16_t water_nearby_;
22@@ -248,6 +250,7 @@
23 int8_t critters_nearby_;
24 int8_t ground_water_; // used by wells
25 uint8_t space_consumers_nearby_;
26+ uint8_t rangers_nearby_;
27 // to manage the military better following variables exists:
28 // capacity of nearby buildings:
29 int16_t area_military_capacity_;
30@@ -268,9 +271,15 @@
31 bool port_nearby_; // to increase priority if a port is nearby,
32 // especially for new colonies
33 Widelands::ExtendedBool portspace_nearby_; // prefer military buildings closer to the portspace
34+ int32_t max_buildcap_nearby_;
35+ // it is not necessary to check resources (stones, fish...) too frequently as they do not change fast
36+ // this stores time of last check
37+ uint32_t last_resources_check_time_;
38
39 std::vector<uint8_t> consumers_nearby_;
40 std::vector<uint8_t> producers_nearby_;
41+ // and for rangers, fishbreeders:
42+ std::vector<uint8_t> supporters_nearby_;
43
44 BuildableField(const Widelands::FCoords& fc)
45 : coords(fc),
46@@ -279,7 +288,7 @@
47 enemy_nearby_(0),
48 unowned_land_nearby_(0),
49 near_border_(false),
50- unowned_mines_pots_nearby_(0),
51+ unowned_mines_spots_nearby_(0),
52 trees_nearby_(0),
53 // explanation of starting values
54 // this is done to save some work for AI (CPU utilization)
55@@ -295,6 +304,7 @@
56 critters_nearby_(-1),
57 ground_water_(1),
58 space_consumers_nearby_(0),
59+ rangers_nearby_(0),
60 area_military_capacity_(0),
61 military_loneliness_(1000),
62 military_in_constr_nearby_(0),
63@@ -303,7 +313,13 @@
64 military_unstationed_(0),
65 is_portspace_(false),
66 port_nearby_(false),
67- portspace_nearby_(Widelands::ExtendedBool::kUnset) {
68+ portspace_nearby_(Widelands::ExtendedBool::kUnset),
69+ max_buildcap_nearby_(0),
70+ last_resources_check_time_(0) {
71+ }
72+
73+ int32_t own_military_sites_nearby_() {
74+ return military_stationed_ + military_unstationed_;
75 }
76 };
77
78@@ -352,9 +368,11 @@
79 MINE
80 } type;
81
82- bool prod_build_material_;
83 bool plants_trees_;
84 bool recruitment_; // is "producing" workers?
85+ Widelands::BuildingNecessity new_building_;
86+ uint32_t new_building_overdue_;
87+ int32_t primary_priority_;
88 bool is_buildable_;
89 bool need_trees_; // lumberjack = true
90 bool need_stones_; // quarry = true
91@@ -372,8 +390,7 @@
92 uint32_t forced_after_; // do not wait until ware is needed
93 TrainingSiteType trainingsite_type_;
94
95- bool unoccupied_;
96- uint16_t unconnected_; // to any warehouse (count of such buildings)
97+ uint16_t unconnected_count_; // to any warehouse (count of such buildings)
98
99 int32_t mines_; // type of resource it mines_
100 uint16_t mines_percent_; // % of res it can mine
101@@ -383,7 +400,13 @@
102 std::vector<int16_t> outputs_;
103 std::vector<Widelands::WareIndex> critical_built_mat_;
104
105+ bool built_mat_producer_;
106+
107+ // an enhancement to this building:
108+ // produces all wares as current building, and perhaps more
109 bool upgrade_substitutes_;
110+ // produces some additional wares
111+ bool upgrade_extends_;
112
113 // It seems that fish and meat are subsitutes (for trainingsites), so
114 // when testing if a trainingsite is supplied enough
115@@ -394,10 +417,7 @@
116 int16_t production_hint_;
117
118 // information needed for decision on new building construction
119- // these should be calculated only once during one run of construct_building()
120- // function
121- Widelands::ExtendedBool output_needed_;
122- int16_t max_preciousness;
123+ int16_t max_preciousness_;
124 int16_t max_needed_preciousness_;
125
126 int32_t cnt_built_;
127@@ -409,6 +429,9 @@
128 int32_t stocklevel_time; // time when stocklevel_ was last time recalculated
129 int32_t last_dismantle_time_;
130 int32_t construction_decision_time_;
131+
132+ uint32_t unoccupied_count_;
133+
134 bool build_material_shortage_;
135
136 int32_t total_count() const {
137@@ -424,7 +447,7 @@
138 uint32_t built_time_;
139 uint32_t unoccupied_till_;
140 uint8_t stats_zero_;
141- uint8_t no_resources_count;
142+ uint32_t no_resources_since_;
143 BuildingObserver* bo;
144 };
145
146@@ -501,8 +524,21 @@
147 uint16_t in_construction;
148 uint16_t finished;
149
150+ uint16_t total_count() const {
151+ return in_construction + finished;
152+ }
153+
154 MineTypesObserver() : in_construction(0), finished(0) {
155 }
156 };
157
158+// this is used to count militarysites by their size
159+struct MilitarySiteSizeObserver {
160+ uint16_t in_construction;
161+ uint16_t finished;
162+
163+ MilitarySiteSizeObserver() : in_construction(0), finished(0) {
164+ }
165+};
166+
167 #endif // end of include guard: WL_AI_AI_HELP_STRUCTS_H
168
169=== modified file 'src/ai/ai_hints.cc'
170--- src/ai/ai_hints.cc 2015-05-07 20:46:32 +0000
171+++ src/ai/ai_hints.cc 2015-10-24 18:56:46 +0000
172@@ -32,7 +32,7 @@
173 fighting_(section ? section->get_bool("fighting") : false),
174 mountain_conqueror_(section ? section->get_bool("mountain_conqueror") : false),
175 prohibited_till_(section ? section->get_natural("prohibited_till", 0) : 0),
176- forced_after_(section ? section->get_natural("forced_after", 864000) : 0), // 10 days default
177+ forced_after_(section ? section->get_natural("forced_after", 864000) : 864000), // 10 days default
178 mines_percent_(section ? section->get_int("mines_percent", 100) : 0),
179 trainingsite_type_(TrainingSiteType::kNoTS)
180
181
182=== modified file 'src/ai/defaultai.cc'
183--- src/ai/defaultai.cc 2015-08-28 19:09:59 +0000
184+++ src/ai/defaultai.cc 2015-10-24 18:56:46 +0000
185@@ -52,7 +52,6 @@
186 #include "profile/profile.h"
187
188 // following is in miliseconds (widelands counts time in ms)
189-// constexpr int kFieldUpdateInterval = 2000;
190 constexpr int kFieldInfoExpiration = 12 * 1000;
191 constexpr int kMineFieldInfoExpiration = 20 * 1000;
192 constexpr int kNewMineConstInterval = 19000;
193@@ -68,10 +67,21 @@
194 // this is intended for map developers, by default should be off
195 constexpr bool kPrintStats = false;
196
197-// Some buildings have to be built close to borders and their
198-// priority might be decreased below 0, so this is to
199-// compensate
200-constexpr int32_t kDefaultPrioBoost = 12;
201+constexpr int kPersistentData = 0; //int16_t
202+constexpr int kMilitLoneliness = 1;
203+constexpr int kAttacker = 2;
204+constexpr int kAttackMargin = 0; //uint32_t
205+constexpr int kLastAttack = 1;
206+constexpr int kProdRatio = 2;
207+constexpr int kColonyScan = 3;
208+constexpr int kTreesAround = 4;
209+constexpr int kEarlyMilitary = 5;
210+constexpr int kWoodDiff = 0; //int32_t
211+constexpr int kTargetMilit = 1;
212+constexpr int kLeastMilit = 2;
213+
214+// duration of military campaign
215+constexpr int kCampaignDuration = 15 * 60 * 1000;
216
217 using namespace Widelands;
218
219@@ -85,25 +95,26 @@
220 type_(t),
221 player_(nullptr),
222 tribe_(nullptr),
223- num_constructionsites_(0),
224- num_milit_constructionsites(0),
225 num_prod_constructionsites(0),
226 num_ports(0),
227 last_attacked_player_(std::numeric_limits<uint16_t>::max()),
228+ last_attack_time_(0),
229 enemysites_check_delay_(60),
230- wood_policy_(WoodPolicy::kStartRangers),
231+ target_military_score_(0),
232+ least_military_score_(100),
233+ wood_policy_(WoodPolicy::kAllowRangers),
234 next_ai_think_(0),
235 next_mine_construction_due_(0),
236 inhibit_road_building_(0),
237 time_of_last_construction_(0),
238- enemy_last_seen_(0),
239+ enemy_last_seen_(std::numeric_limits<uint32_t>::max()),
240 numof_warehouses_(0),
241 new_buildings_stop_(false),
242 resource_necessity_territory_(100),
243 resource_necessity_mines_(100),
244 resource_necessity_water_(0),
245 resource_necessity_water_needed_(false),
246- unstationed_milit_buildings_(0),
247+ trees_around_cutters_(0),
248 military_last_dismantle_(0),
249 military_last_build_(0),
250 seafaring_economy(false),
251@@ -115,7 +126,12 @@
252 ts_advanced_count_(0),
253 ts_advanced_const_count_(0),
254 ts_without_trainers_(0),
255- scheduler_delay_counter_(0) {
256+ scheduler_delay_counter_(0),
257+ ai_personality_military_loneliness_(0),
258+ ai_personality_attack_margin_(0),
259+ ai_personality_wood_difference_(0),
260+ ai_productionsites_ratio_(0),
261+ ai_personality_early_militarysites(0) {
262
263 // Subscribe to NoteFieldPossession.
264 field_possession_subscriber_ =
265@@ -296,7 +312,11 @@
266 if (check_economies()) { // economies must be consistent
267 return;
268 }
269- taskDue[ScheduleTasks::kConstructBuilding] = gametime + 6000;
270+ if (gametime < 15000) { //more frequent on the beginning of game
271+ taskDue[ScheduleTasks::kConstructBuilding] = gametime + 2000;
272+ } else {
273+ taskDue[ScheduleTasks::kConstructBuilding] = gametime + 6000;
274+ }
275 if (construct_building(gametime)) {
276 time_of_last_construction_ = gametime;
277 }
278@@ -349,7 +369,7 @@
279 break;
280 case ScheduleTasks::kCountMilitaryVacant :
281 count_military_vacant_positions();
282- taskDue[ScheduleTasks::kCountMilitaryVacant] = gametime + 60 * 1000;
283+ taskDue[ScheduleTasks::kCountMilitaryVacant] = gametime + 45 * 1000;
284 break;
285 case ScheduleTasks::kWareReview :
286 if (check_economies()) { // economies must be consistent
287@@ -420,8 +440,10 @@
288 bo.build_material_shortage_ = false;
289 bo.production_hint_ = -1;
290 bo.current_stats_ = 0;
291- bo.unoccupied_ = false;
292- bo.unconnected_ = 0;
293+ bo.unoccupied_count_ = 0;
294+ bo.unconnected_count_ = 0;
295+ bo.new_building_overdue_ = 0;
296+ bo.primary_priority_ = 0;
297 bo.is_buildable_ = bld.is_buildable();
298 bo.need_trees_ = bh.is_logproducer();
299 bo.need_stones_ = bh.is_stoneproducer();
300@@ -437,8 +459,9 @@
301 bo.is_port_ = bld.get_isport();
302 bo.trainingsite_type_ = TrainingSiteType::kNoTS;
303 bo.upgrade_substitutes_ = false;
304- bo.output_needed_ = ExtendedBool::kUnset;
305- bo.max_preciousness = 0;
306+ bo.upgrade_extends_ = false;
307+ bo.built_mat_producer_ = false;
308+ bo.max_preciousness_ = 0;
309 bo.max_needed_preciousness_ = 0;
310
311 if (bh.renews_map_resource()) {
312@@ -519,17 +542,33 @@
313 break;
314 }
315 }
316- }
317-
318- // plus some manually picked buildings,
319- // see preferred_upgrade list
320- for (const char* pb : preferred_upgrade) {
321- if (strcmp(bld.name().c_str(), pb) == 0) {
322- bo.upgrade_substitutes_ = true;
323- }
324- }
325-
326- continue;
327+
328+ std::unordered_set<WareIndex> cur_outputs;
329+ // collecting wares that are produced in enhanced building
330+ for (const WareIndex& ware : bo.outputs_) {
331+ cur_outputs.insert(ware);
332+ }
333+ bo.upgrade_extends_ = false;
334+ for (WareIndex ware : enh_outputs) {
335+ if (cur_outputs.count(ware) == 0) {
336+ bo.upgrade_extends_ = true;
337+ break;
338+ }
339+ }
340+ }
341+
342+ // now we identify producers of critical build materials
343+ // hardwood now
344+ for (WareIndex ware : bo.outputs_) {
345+ // iterating over wares subsitutes
346+ if (tribe_->ware_index("wood") == ware ||
347+ tribe_->ware_index("blackwood") == ware ||
348+ tribe_->ware_index("marble") == ware ||
349+ tribe_->ware_index("planks") == ware) {
350+ bo.built_mat_producer_ = true;
351+ }
352+ }
353+ continue;
354 }
355
356 // now for every military building, we fill critical_built_mat_ vector
357@@ -539,13 +578,11 @@
358 bo.type = BuildingObserver::MILITARYSITE;
359 const MilitarySiteDescr& milit = dynamic_cast<const MilitarySiteDescr&>(bld);
360 for (const std::pair<unsigned char, unsigned char>& temp_buildcosts : milit.buildcost()) {
361- // bellow are non-critical wares
362+ // bellow are non-critical wares (well, various types of wood)
363 if (tribe_->ware_index("log") == temp_buildcosts.first ||
364 tribe_->ware_index("blackwood") == temp_buildcosts.first ||
365 tribe_->ware_index("planks") == temp_buildcosts.first ||
366- tribe_->ware_index("wood") == temp_buildcosts.first ||
367- tribe_->ware_index("raw_stone") == temp_buildcosts.first ||
368- tribe_->ware_index("stone") == temp_buildcosts.first)
369+ tribe_->ware_index("wood") == temp_buildcosts.first)
370 continue;
371
372 bo.critical_built_mat_.push_back(temp_buildcosts.first);
373@@ -571,8 +608,16 @@
374 tribe_->ware_index("smoked_fish") == temp_input.first) {
375 bo.substitute_inputs_.insert(temp_input.first);
376 }
377+
378+ for (const std::pair<unsigned char, unsigned char>& temp_buildcosts : train.buildcost()) {
379+ // critical wares for trainingsites
380+ if (tribe_->ware_index("spidercloth") == temp_buildcosts.first ||
381+ tribe_->ware_index("gold") == temp_buildcosts.first ||
382+ tribe_->ware_index("grout") == temp_buildcosts.first) {
383+ bo.critical_built_mat_.push_back(temp_buildcosts.first);
384+ }
385+ }
386 }
387-
388 bo.trainingsite_type_ = bh.get_trainingsite_type();
389 // it would behave badly if no type was set
390 // make sure all TS have its type set properly in conf files
391@@ -586,8 +631,6 @@
392 }
393 }
394
395-
396-
397 // atlanteans they consider water as a resource
398 // (together with mines, stones and wood)
399 if (tribe_->name() == "atlanteans") {
400@@ -690,8 +733,73 @@
401 taskDue[ScheduleTasks::kUnbuildableFCheck] = 1000;
402 taskDue[ScheduleTasks::kWareReview] = 15 * 60 * 1000;
403 taskDue[ScheduleTasks::kPrintStats] = 30 * 60 * 1000;
404- taskDue[ScheduleTasks::kCountMilitaryVacant] = 10 * 60 * 1000;
405+ taskDue[ScheduleTasks::kCountMilitaryVacant] = 1 * 60 * 1000;
406 taskDue[ScheduleTasks::kCheckEnemySites] = 10 * 60 * 1000;
407+
408+ // Here the AI persistent data either exists - then they are read
409+ // or does not exist, then they are created and saved
410+ int16_t persistent_data_exists_ = 0;
411+ player_->get_ai_data(&persistent_data_exists_, kPersistentData);
412+
413+ // 0 implies no saved data exits yet
414+ if (persistent_data_exists_ == 0) {
415+ player_->set_ai_data(static_cast<int16_t>(1), kPersistentData);
416+
417+ // these random values to make some small differences between players
418+ // they are immediately saved
419+ // these values are never changed
420+ ai_personality_military_loneliness_ = std::rand() % 5 * 30 - 60;
421+ player_->set_ai_data(ai_personality_military_loneliness_, kMilitLoneliness);
422+
423+ ai_personality_attack_margin_ = std::max(std::rand() % 20 - 5, 0);
424+ player_->set_ai_data(ai_personality_attack_margin_, kAttackMargin);
425+
426+ ai_personality_wood_difference_ = std::rand() % 40 - 20;
427+ player_->set_ai_data(ai_personality_wood_difference_, kWoodDiff);
428+
429+ ai_productionsites_ratio_ = std::rand() % 5 + 7;
430+ player_->set_ai_data(ai_productionsites_ratio_, kProdRatio);
431+
432+ ai_personality_early_militarysites = std::rand() % 20 + 20;
433+ player_->set_ai_data(ai_personality_early_militarysites, kEarlyMilitary);
434+
435+ } else {
436+ log (" %d: restoring saved AI data...\n", player_number());
437+
438+ // Restoring data and doing some basic check
439+ player_->get_ai_data(&ai_personality_military_loneliness_, kMilitLoneliness);
440+ check_range<int16_t>
441+ (ai_personality_military_loneliness_, -60, 60, "ai_personality_military_loneliness_");
442+
443+ player_->get_ai_data(&ai_personality_attack_margin_, kAttackMargin);
444+ check_range<uint32_t>(ai_personality_attack_margin_, 15, "ai_personality_attack_margin_");
445+
446+ player_->get_ai_data(&ai_personality_wood_difference_, kWoodDiff);
447+ check_range<int32_t>(ai_personality_wood_difference_, -20, 19, "ai_personality_wood_difference_");
448+
449+ player_->get_ai_data(&ai_productionsites_ratio_, kProdRatio);
450+ check_range<uint32_t>(ai_productionsites_ratio_, 5, 15, "ai_productionsites_ratio_");
451+
452+ player_->get_ai_data(&ai_personality_early_militarysites, kEarlyMilitary);
453+ check_range<uint32_t>(ai_personality_early_militarysites, 20, 40, "ai_personality_early_militarysites");
454+
455+ // Now some runtime values that are generated and saved during course of game
456+ player_->get_ai_data(&last_attack_time_, kLastAttack);
457+
458+ player_->get_ai_data(&last_attacked_player_, kAttacker);
459+ check_range<int16_t>(last_attacked_player_, 0, 8, "last_attacked_player_");
460+
461+ player_->get_ai_data(&colony_scan_area_, kColonyScan);
462+ check_range<uint32_t>(colony_scan_area_, 50, "colony_scan_area_");
463+
464+ player_->get_ai_data(&trees_around_cutters_, kTreesAround);
465+
466+ player_->get_ai_data(&least_military_score_, kLeastMilit);
467+ check_range<uint32_t>(least_military_score_, 0, 1000, "least_military_score_");
468+
469+ player_->get_ai_data(&target_military_score_, kTargetMilit);
470+ check_range<uint32_t>(target_military_score_, least_military_score_, 1000, "target_military_score_");
471+ }
472 }
473
474 /**
475@@ -821,7 +929,7 @@
476 void DefaultAI::update_buildable_field(BuildableField& field, uint16_t range, bool military) {
477 // look if there is any unowned land nearby
478 Map& map = game().map();
479- const int32_t gametime = game().get_gametime();
480+ const uint32_t gametime = game().get_gametime();
481 FindNodeUnowned find_unowned(player_, game());
482 FindNodeUnownedMineable find_unowned_mines_pots(player_, game());
483 PlayerNumber const pn = player_->player_number();
484@@ -841,9 +949,19 @@
485 }
486 }
487
488+
489+ // are we going to count resources now?
490+ bool resource_count_now = false;
491+ // Testing in first 10 seconds or if last testing was more then 60 sec ago
492+ if (field.last_resources_check_time_ < 10000 ||
493+ field.last_resources_check_time_ - gametime > 60 * 1000) {
494+ resource_count_now = true;
495+ field.last_resources_check_time_ = gametime;
496+ }
497+
498 // to save some CPU
499- if ((mines_.size() > 8 && gametime % 3 > 0) || field.unowned_land_nearby_ == 0) {
500- field.unowned_mines_pots_nearby_ = 0;
501+ if (mines_.size() > 8 && !resource_count_now) {
502+ field.unowned_mines_spots_nearby_ = 0;
503 } else {
504 uint32_t close_mines =
505 map.find_fields(Area<FCoords>(field.coords, 4), nullptr, find_unowned_mines_pots);
506@@ -852,9 +970,9 @@
507 nullptr,
508 find_unowned_mines_pots);
509 distant_mines = distant_mines - close_mines;
510- field.unowned_mines_pots_nearby_ = 4 * close_mines + distant_mines / 2;
511+ field.unowned_mines_spots_nearby_ = 4 * close_mines + distant_mines / 2;
512 if (distant_mines > 0) {
513- field.unowned_mines_pots_nearby_ += 15;
514+ field.unowned_mines_spots_nearby_ += 15;
515 }
516 }
517
518@@ -889,6 +1007,19 @@
519 field.port_nearby_ = false;
520 }
521
522+ // testing fields in radius 1 to find biggest buildcaps.
523+ // This is to calculate capacity that will be lost if something is
524+ // built here
525+ field.max_buildcap_nearby_ = 0;
526+ MapRegion<Area<FCoords>> mr(map, Area<FCoords>(field.coords, 1));
527+ do {
528+ if ((player_->get_buildcaps(mr.location()) & BUILDCAPS_SIZEMASK) > field.max_buildcap_nearby_) {
529+ field.max_buildcap_nearby_ = player_->get_buildcaps(mr.location()) & BUILDCAPS_SIZEMASK;
530+ }
531+ } while (mr.advance(map));
532+
533+ assert ((player_->get_buildcaps(field.coords) & BUILDCAPS_SIZEMASK) <= field.max_buildcap_nearby_);
534+
535 // collect information about resources in the area
536 std::vector<ImmovableFound> immovables;
537 // Search in a radius of range
538@@ -906,10 +1037,13 @@
539 field.military_stationed_ = 0;
540 field.trees_nearby_ = 0;
541 field.space_consumers_nearby_ = 0;
542+ field.rangers_nearby_ = 0;
543 field.producers_nearby_.clear();
544 field.producers_nearby_.resize(wares.size());
545 field.consumers_nearby_.clear();
546 field.consumers_nearby_.resize(wares.size());
547+ field.supporters_nearby_.clear();
548+ field.supporters_nearby_.resize(wares.size());
549 std::vector<Coords> water_list;
550 std::vector<Coords> resource_list;
551 std::vector<Bob*> critters_list;
552@@ -927,7 +1061,7 @@
553 }
554
555 // counting fields with fish
556- if (field.water_nearby_ > 0 && (field.fish_nearby_ == -1 || gametime % 10 == 0)) {
557+ if (field.water_nearby_ > 0 && (field.fish_nearby_ == -1 || resource_count_now)) {
558 map.find_fields(Area<FCoords>(field.coords, 6),
559 &resource_list,
560 FindNodeResource(world.get_resource("fish")));
561@@ -936,7 +1070,7 @@
562
563 // counting fields with critters (game)
564 // not doing this always, this does not change fast
565- if (gametime % 10 == 0) {
566+ if (resource_count_now) {
567 map.find_bobs(Area<FCoords>(field.coords, 6), &critters_list, FindBobCritter());
568 field.critters_nearby_ = critters_list.size();
569 }
570@@ -965,25 +1099,16 @@
571
572 continue;
573 }
574- }
575-
576- if (upcast(Building const, building, &base_immovable)) {
577- if (upcast(ConstructionSite const, constructionsite, building)) {
578+ // here we identify the buiding (including expected building if constructionsite)
579+ // and calculate some statistics about nearby buildings
580+ if (upcast(ProductionSite const, productionsite, player_immovable)) {
581+ BuildingObserver& bo = get_building_observer(productionsite->descr().name().c_str());
582+ consider_productionsite_influence(field, immovables.at(i).coords, bo);
583+ }
584+ if (upcast(ConstructionSite const, constructionsite, player_immovable)) {
585 const BuildingDescr& target_descr = constructionsite->building();
586-
587- if (dynamic_cast<ProductionSiteDescr const*>(&target_descr)) {
588- consider_productionsite_influence(
589- field,
590- immovables.at(i).coords,
591- get_building_observer(constructionsite->descr().name().c_str()));
592- }
593- }
594-
595- if (dynamic_cast<const ProductionSite*>(building)) {
596- consider_productionsite_influence(
597- field,
598- immovables.at(i).coords,
599- get_building_observer(building->descr().name().c_str()));
600+ BuildingObserver& bo = get_building_observer(target_descr.name().c_str());
601+ consider_productionsite_influence(field, immovables.at(i).coords, bo);
602 }
603 }
604
605@@ -993,7 +1118,7 @@
606 }
607
608 // stones are not renewable, we will count them only if previous state is nonzero
609- if (field.stones_nearby_ > 0 && gametime % 3 == 0) {
610+ if (field.stones_nearby_ > 0 && resource_count_now) {
611
612 field.stones_nearby_ =
613 map.find_immovables(Area<FCoords>(map.get_fcoords(field.coords), 6),
614@@ -1037,7 +1162,6 @@
615 if (player_->is_hostile(player_immovable->owner())) {
616 field.enemy_nearby_ = true;
617 }
618-
619 continue;
620 }
621 }
622@@ -1142,8 +1266,8 @@
623 // Reset statistics for all buildings
624 for (uint32_t i = 0; i < buildings_.size(); ++i) {
625 buildings_.at(i).current_stats_ = 0;
626- buildings_.at(i).unoccupied_ = false;
627- buildings_.at(i).unconnected_ = 0;
628+ buildings_.at(i).unoccupied_count_ = 0;
629+ buildings_.at(i).unconnected_count_ = 0;
630 }
631
632 // Check all available productionsites
633@@ -1165,10 +1289,11 @@
634 }
635
636 // Check whether this building is completely occupied
637- productionsites.front().bo->unoccupied_ |=
638- !productionsites.front().site->can_start_working();
639+ if (!productionsites.front().site->can_start_working()) {
640+ productionsites.front().bo->unoccupied_count_ += 1;
641+ }
642 } else {
643- productionsites.front().bo->unconnected_ += 1;
644+ productionsites.front().bo->unconnected_count_ += 1;
645 }
646
647 // Now reorder the buildings
648@@ -1199,9 +1324,11 @@
649 // Add statistics value
650 mines_.front().bo->current_stats_ += mines_.front().site->get_statistics_percent();
651 // Check whether this building is completely occupied
652- mines_.front().bo->unoccupied_ |= !mines_.front().site->can_start_working();
653+ if (!mines_.front().site->can_start_working()) {
654+ mines_.front().bo->unoccupied_count_ += 1;
655+ }
656 } else {
657- mines_.front().bo->unconnected_ += 1;
658+ mines_.front().bo->unconnected_count_ += 1;
659 }
660
661 // Now reorder the buildings
662@@ -1211,9 +1338,9 @@
663
664 // Scale statistics down
665 for (uint32_t i = 0; i < buildings_.size(); ++i) {
666- if ((buildings_.at(i).cnt_built_ - buildings_.at(i).unconnected_) > 0) {
667+ if ((buildings_.at(i).cnt_built_ - buildings_.at(i).unconnected_count_) > 0) {
668 buildings_.at(i).current_stats_ /=
669- (buildings_.at(i).cnt_built_ - buildings_.at(i).unconnected_);
670+ (buildings_.at(i).cnt_built_ - buildings_.at(i).unconnected_count_);
671 }
672 }
673 }
674@@ -1261,7 +1388,6 @@
675
676 // here we possible stop building of new buildings
677 new_buildings_stop_ = false;
678- MilitaryStrategy expansion_mode = MilitaryStrategy::kResourcesOrDefense;
679
680 // helper variable - we need some proportion of free spots vs productionsites
681 // the proportion depends on size of economy
682@@ -1278,11 +1404,63 @@
683 needed_spots = 1300 + (productionsites.size() - 200) * 20;
684 }
685
686+ // *_military_scores are used as minimal score for a new military building
687+ // to be built. As AI does not traverse all building fields at once, these thresholds
688+ // are gradually going down until it finds a field&building that are above threshold
689+ // and this combination is used...
690+ // least_military_score_ is hardlimit, floating very slowly
691+ // target_military_score_ is always set according to latest best building (using the same
692+ // score) and quickly falling down until it reaches the least_military_score_
693+ // this one (=target_military_score_) is actually used to decide if building&field is allowed
694+ // candidate
695+ // least_military_score_ is allowed to get bellow 100 only if there is no military site in construction
696+ // right now in order to (try to) avoid expansion lockup
697+
698+ // this is just helpers to improve readability of code
699+ const bool too_many_ms_constructionsites =
700+ (pow(msites_in_constr(), 2) > militarysites.size());
701+ const bool too_many_vacant_mil =
702+ (vacant_mil_positions_ * 3 > static_cast<int32_t>(militarysites.size()));
703+ const int32_t kUpperLimit = 275;
704+ const int32_t kBottomLimit = 40; // to prevent too dense militarysites
705+ // modifying least_military_score_, down if more military sites are needed and vice versa
706+ if (too_many_ms_constructionsites || too_many_vacant_mil) {
707+ if (least_military_score_ < kUpperLimit) { //no sense to let it grow too hight
708+ least_military_score_ += 2;
709+ }
710+ } else {
711+ least_military_score_ -= 4;
712+ // do not get bellow 100 if there is at least one ms in construction
713+ if ((msites_in_constr() > 0 || too_many_vacant_mil) && least_military_score_ < kBottomLimit) {
714+ least_military_score_ = kBottomLimit;
715+ }
716+ if (least_military_score_ < 0) {
717+ least_military_score_ = 0;
718+ }
719+ }
720+
721+ // This is effective score, falling down very quickly
722+ if (target_military_score_ > 350) {
723+ target_military_score_ = 8 * target_military_score_ / 10;
724+ } else {
725+ target_military_score_ = 9 * target_military_score_ / 10;
726+ }
727+ if (target_military_score_ < least_military_score_) {
728+ target_military_score_ = least_military_score_;
729+ }
730+ player_->set_ai_data(target_military_score_, kTargetMilit);
731+ player_->set_ai_data(least_military_score_, kLeastMilit);
732+
733+
734 // there are many reasons why to stop building production buildings
735 // (note there are numerous exceptions)
736 // 1. to not have too many constructionsites
737- if (num_prod_constructionsites > productionsites.size() / 7 + 2) {
738- new_buildings_stop_ = true;
739+ if ((num_prod_constructionsites + mines_in_constr())
740+ >
741+ (productionsites.size() + mines_built())
742+ /
743+ ai_productionsites_ratio_ + 2) {
744+ new_buildings_stop_ = true;
745 }
746 // 2. to not exhaust all free spots
747 if (spots_ < needed_spots) {
748@@ -1290,16 +1468,12 @@
749 }
750 // 3. too keep some proportions production sites vs military sites
751 if ((num_prod_constructionsites + productionsites.size()) >
752- (num_milit_constructionsites + militarysites.size()) * 5) {
753- new_buildings_stop_ = true;
754- }
755- // 4. if we do not have 3 mines at least
756- if (mines_.size() < 3) {
757- new_buildings_stop_ = true;
758- }
759- // BUT if enemy is nearby, we cancel above stop
760- if (new_buildings_stop_ && enemy_last_seen_ + 10 * 60 * 1000 > gametime) {
761- new_buildings_stop_ = false;
762+ (msites_in_constr() + militarysites.size()) * 5) {
763+ new_buildings_stop_ = true;
764+ }
765+ // 4. if we do not have 2 mines at least
766+ if (mines_.size() < 2) {
767+ new_buildings_stop_ = true;
768 }
769
770 // we must calculate wood policy
771@@ -1309,15 +1483,16 @@
772 // it is proportion to the size of economy). Plus some positive 'margin'
773 const int32_t stocked_wood_margin = get_warehoused_stock(wood_index) -
774 productionsites.size() * 2 -
775- num_prod_constructionsites;
776- if (stocked_wood_margin > 80) {
777+ num_prod_constructionsites +
778+ ai_personality_wood_difference_;
779+ if (gametime < 15 * 60 * 1000) {
780+ wood_policy_ = WoodPolicy::kAllowRangers;
781+ } else if (stocked_wood_margin > 80) {
782 wood_policy_ = WoodPolicy::kDismantleRangers;
783 } else if (stocked_wood_margin > 25) {
784 wood_policy_ = WoodPolicy::kStopRangers;
785- } else if (stocked_wood_margin > 10) {
786- wood_policy_ = WoodPolicy::kStartRangers;
787 } else {
788- wood_policy_ = WoodPolicy::kBuildRangers;
789+ wood_policy_ = WoodPolicy::kAllowRangers;
790 }
791
792 // we must consider need for mines
793@@ -1325,7 +1500,7 @@
794 // we use 'virtual mines', because also mine spots can be changed
795 // to mines when AI decides so
796 const int32_t virtual_mines =
797- mines_.size() + mineable_fields.size() / 15 - productionsites.size() / 25;
798+ mines_.size() + mineable_fields.size() / 25;
799 resource_necessity_mines_ = 100 * (15 - virtual_mines) / 15;
800 resource_necessity_mines_ = (resource_necessity_mines_ > 100) ? 100 : resource_necessity_mines_;
801 resource_necessity_mines_ = (resource_necessity_mines_ < 20) ? 10 : resource_necessity_mines_;
802@@ -1349,27 +1524,6 @@
803 }
804 }
805
806- // this controls a speed and willingness to expand the teritorry
807- const int32_t vacant_plus_in_construction_minus_prod =
808- vacant_mil_positions_ + 2 * num_milit_constructionsites - productionsites.size() / 7;
809- if (vacant_plus_in_construction_minus_prod > 20) {
810- expansion_mode = MilitaryStrategy::kNoNewMilitary;
811- } else if (vacant_plus_in_construction_minus_prod > 13) {
812- expansion_mode = MilitaryStrategy::kDefenseOnly;
813- } else if (vacant_plus_in_construction_minus_prod > 6) {
814- expansion_mode = MilitaryStrategy::kResourcesOrDefense;
815- } else {
816- // this is intended for initial phase of game when the player still has enough soldiers
817- // but we still want to force it to follow resources instead for plain expansion
818- if (virtual_mines <= 2 && (unstationed_milit_buildings_ + num_milit_constructionsites) > 2) {
819- expansion_mode = MilitaryStrategy::kResourcesOrDefense;
820- } else if (unstationed_milit_buildings_ + num_milit_constructionsites >= 1) {
821- expansion_mode = MilitaryStrategy::kExpansion;
822- } else {
823- expansion_mode = MilitaryStrategy::kPushExpansion;
824- }
825- }
826-
827 BuildingObserver* best_building = nullptr;
828 int32_t proposed_priority = 0;
829 Coords proposed_coords;
830@@ -1393,11 +1547,11 @@
831 }
832
833 // not doing this for non-military buildins
834- if (!(bo.type == BuildingObserver::MILITARYSITE))
835+ if (!(bo.type == BuildingObserver::MILITARYSITE || bo.type == BuildingObserver::TRAININGSITE))
836 continue;
837
838 // and neither for small military buildings
839- if (bo.desc->get_size() == BaseImmovable::SMALL)
840+ if (bo.type == BuildingObserver::MILITARYSITE && bo.desc->get_size() == BaseImmovable::SMALL)
841 continue;
842
843 bo.build_material_shortage_ = false;
844@@ -1412,11 +1566,80 @@
845 }
846 }
847
848- //Resetting output_needed_ in building observer
849+ // Calculating actual needness
850 for (uint32_t j = 0; j < buildings_.size(); ++j) {
851 BuildingObserver& bo = buildings_.at(j);
852- if (bo.type == BuildingObserver::PRODUCTIONSITE || bo.type == BuildingObserver::MINE){
853- bo.output_needed_ = ExtendedBool::kUnset;
854+
855+ if (!bo.buildable(*player_)) {
856+ bo.new_building_ = BuildingNecessity::kNotNeeded;
857+ } else if (bo.type == BuildingObserver::PRODUCTIONSITE || bo.type == BuildingObserver::MINE) {
858+
859+ bo.new_building_ = check_building_necessity(bo, PerfEvaluation::kForConstruction, gametime);
860+
861+ if (bo.new_building_ == BuildingNecessity::kAllowed) {
862+ bo.new_building_overdue_ = 0;
863+ }
864+
865+ // Now verifying that all 'buildable' buildings has positive max_needed_preciousness_
866+ // if they have outputs, all other must have zero max_needed_preciousness_
867+ if ((bo.new_building_ == BuildingNecessity::kNeeded
868+ || bo.new_building_ == BuildingNecessity::kForced
869+ || bo.new_building_ == BuildingNecessity::kAllowed
870+ || bo.new_building_ == BuildingNecessity::kNeededPending) && !bo.outputs_.empty()) {
871+ assert (bo.max_needed_preciousness_ > 0);
872+ } else {
873+ // For other situations we set max_needed_preciousness_ to zero
874+ bo.max_needed_preciousness_ = 0;
875+ }
876+
877+
878+ // Here we consider a time how long a building needed
879+ // We calculate primary_priority used later in construct_building(),
880+ // it is basically max_needed_preciousness_ plus some 'bonus' for due time
881+ // Following scenarios are possible:
882+ // a) building is needed or forced: primary_priority_ grows with time
883+ // b) building is allowed: primary_priority_ = max_needed_preciousness_ (no time consideration)
884+ // c) all other cases: primary_priority_ = 0;
885+ if (bo.max_needed_preciousness_ > 0) {
886+ if (bo.new_building_ == BuildingNecessity::kAllowed) {
887+ bo.primary_priority_ = bo.max_needed_preciousness_;
888+ } else {
889+ bo.primary_priority_ = bo.max_needed_preciousness_ +
890+ bo.max_needed_preciousness_ * bo.new_building_overdue_ / 100 +
891+ bo.new_building_overdue_ / 20;
892+ }
893+ } else {
894+ bo.primary_priority_ = 0;
895+ }
896+
897+ // Generally we don't start another building if there is some of the same type in construction
898+ // Some types of building allow two buildings in construction though, but not more
899+ // Below checks are to guarantee that there is no logical error in previous steps, or
900+ // inconsistency in AI data
901+ if (bo.new_building_ == BuildingNecessity::kNeeded
902+ || bo.new_building_ == BuildingNecessity::kForced
903+ || bo.new_building_ == BuildingNecessity::kAllowed
904+ || bo.new_building_ == BuildingNecessity::kNeededPending) {
905+ if (bo.plants_trees_ || bo.need_trees_ || bo.max_needed_preciousness_ >= 10) {
906+ if (bo.cnt_under_construction_ + bo.unoccupied_count_ > 1) {
907+ throw wexception("AI inconsistency: %s: total_count %d > 1, unoccupied: %d",
908+ bo.name, bo.total_count(), bo.unoccupied_count_);
909+ }
910+ } else {
911+ if (bo.cnt_under_construction_ + bo.unoccupied_count_ > 0) {
912+ throw wexception("AI inconsistency: %s: total_count %d > 0, unoccupied: %d",
913+ bo.name, bo.total_count(), bo.unoccupied_count_);
914+ }
915+ }
916+ }
917+
918+ } else if (bo.type == BuildingObserver::MILITARYSITE) {
919+ bo.new_building_ = check_building_necessity(bo.desc->get_size(), gametime);
920+ } else if (bo.type == BuildingObserver::TRAININGSITE && bo.build_material_shortage_) {
921+ bo.new_building_ = BuildingNecessity::kNotNeeded;
922+ } else {
923+ bo.new_building_ = BuildingNecessity::kAllowed;
924+ bo.primary_priority_ = 0;
925 }
926 }
927
928@@ -1448,6 +1671,7 @@
929 assert(player_);
930 int32_t const maxsize = player_->get_buildcaps(bf->coords) & BUILDCAPS_SIZEMASK;
931
932+
933 // For every field test all buildings
934 for (uint32_t j = 0; j < buildings_.size(); ++j) {
935 BuildingObserver& bo = buildings_.at(j);
936@@ -1456,9 +1680,14 @@
937 continue;
938 }
939
940- if (bo.prohibited_till_ > gametime) {
941+ if (bo.new_building_ == BuildingNecessity::kNotNeeded ||
942+ bo.new_building_ == BuildingNecessity::kNeededPending) {
943 continue;
944- }
945+ }
946+
947+ assert (bo.new_building_ == BuildingNecessity::kForced ||
948+ bo.new_building_ == BuildingNecessity::kNeeded ||
949+ bo.new_building_ == BuildingNecessity::kAllowed);
950
951 // if current field is not big enough
952 if (bo.desc->get_size() > maxsize) {
953@@ -1486,10 +1715,6 @@
954 continue;
955 }
956
957- if (bo.unoccupied_) {
958- continue;
959- }
960-
961 if (!(bo.type == BuildingObserver::MILITARYSITE) && bo.cnt_under_construction_ >= 2) {
962 continue;
963 }
964@@ -1498,95 +1723,55 @@
965
966 if (bo.type == BuildingObserver::PRODUCTIONSITE) {
967
968- // exclude spots on border
969- if (bf->near_border_ && !bo.need_trees_ && !bo.need_stones_ && !bo.is_fisher_) {
970- continue;
971- }
972-
973- // this just indicates that values must be recalculated - if this building
974- // is to be considered later on in this function
975- if (bo.output_needed_ == ExtendedBool::kUnset) {
976- check_building_necessity(bo);
977- }
978-
979 // this can be only a well (as by now)
980 if (bo.mines_water_) {
981+
982+ if (bo.new_building_ == BuildingNecessity::kForced) {
983+ assert (bo.total_count() - bo.unconnected_count_ == 0);
984+ }
985+
986 if (bf->ground_water_ < 2) {
987 continue;
988 }
989
990- if (bo.cnt_under_construction_ + bo.unoccupied_ > 0) {
991+ prio = bo.primary_priority_;
992+
993+ // keep wells more distant
994+ if (bf->producers_nearby_.at(bo.outputs_.at(0)) > 2) {
995 continue;
996 }
997
998- prio = 0;
999 // one well is forced
1000- if (bo.total_count() == 0) {
1001- prio = 200;
1002- } // boost for first/only well
1003- else if (new_buildings_stop_) {
1004- continue;
1005- }
1006-
1007- bo.cnt_target_ = 1 + productionsites.size() / 50;
1008-
1009- if (bo.stocklevel_time < game().get_gametime() - 30 * 1000) {
1010- bo.stocklevel_ = get_stocklevel(bo);
1011- bo.stocklevel_time = game().get_gametime();
1012- }
1013- if (bo.stocklevel_ > 50 + productionsites.size() * 5) {
1014- continue;
1015- }
1016+ if (bo.new_building_ == BuildingNecessity::kForced) {
1017+ prio += 200;
1018+ }
1019+
1020 prio += bf->ground_water_ - 2;
1021- prio = recalc_with_border_range(*bf, prio);
1022
1023 } else if (bo.need_trees_) { // LUMBERJACS
1024
1025- bo.cnt_target_ =
1026- 3 + static_cast<int32_t>(mines_.size() + productionsites.size()) / 15;
1027-
1028- if (bo.total_count() == 0) {
1029- prio = 500 + bf->trees_nearby_;
1030- }
1031-
1032- else if (bo.total_count() == 1) {
1033- prio = 400 + bf->trees_nearby_;
1034- }
1035-
1036- else if (bf->trees_nearby_ < 2) {
1037+ prio = bo.primary_priority_;
1038+
1039+ prio += -20 + 200 / (bo.total_count() + 1);
1040+
1041+ if (bo.new_building_ == BuildingNecessity::kForced) {
1042+ prio *= 2;
1043+ } else if (bf->trees_nearby_ < 2 && bf->supporters_nearby_.at(bo.outputs_.at(0) == 0)) {
1044 continue;
1045 }
1046
1047- else {
1048-
1049- if (bo.total_count() < bo.cnt_target_) {
1050- prio = 75;
1051- } else {
1052- prio = 0;
1053- }
1054-
1055- if (bf->producers_nearby_.at(bo.outputs_.at(0)) > 1) {
1056- continue;
1057- }
1058-
1059- prio += 2 * bf->trees_nearby_ - 10 -
1060- bf->producers_nearby_.at(bo.outputs_.at(0)) * 5 -
1061- new_buildings_stop_ * 15;
1062-
1063- if (bf->near_border_) {
1064- prio = prio / 2;
1065- }
1066- }
1067+ // consider cutters and rangers nearby
1068+ prio -= bf->producers_nearby_.at(bo.outputs_.at(0)) * 20;
1069+ prio += bf->supporters_nearby_.at(bo.outputs_.at(0)) * 5;
1070+
1071+ prio += 2 * bf->trees_nearby_;
1072
1073 } else if (bo.need_stones_) {
1074
1075 // quaries are generally to be built everywhere where stones are
1076 // no matter the need for stones, as stones are considered an obstacle
1077 // to expansion
1078- if (bo.cnt_under_construction_ > 0) {
1079- continue;
1080- }
1081- prio = bf->stones_nearby_;
1082+ prio = 2 * bf->stones_nearby_;
1083
1084 // value is initialized with 1 but minimal value that can be
1085 // calculated is 11
1086@@ -1594,12 +1779,12 @@
1087 continue;
1088 }
1089
1090- if (bo.total_count() - bo.unconnected_ == 0) {
1091+ if (bo.total_count() - bo.unconnected_count_ == 0) {
1092 prio += 150;
1093 }
1094
1095 if (bo.stocklevel_time < game().get_gametime() - 5 * 1000) {
1096- bo.stocklevel_ = get_stocklevel_by_hint(static_cast<size_t>(bo.production_hint_));
1097+ bo.stocklevel_ = get_stocklevel(static_cast<size_t>(bo.production_hint_));
1098 bo.stocklevel_time = game().get_gametime();
1099 }
1100
1101@@ -1610,119 +1795,93 @@
1102 // to prevent to many quaries on one spot
1103 prio = prio - 50 * bf->producers_nearby_.at(bo.outputs_.at(0));
1104
1105- if (bf->near_border_) {
1106- prio = prio / 2;
1107- }
1108-
1109 } else if (bo.is_hunter_) {
1110+
1111 if (bf->critters_nearby_ < 5) {
1112 continue;
1113 }
1114
1115- if (gametime > 5 * 60 * 1000 &&
1116- (bo.total_count() - bo.unconnected_ == 0)) {
1117- prio += 10;
1118- } else if (new_buildings_stop_) {
1119- continue;
1120+ if (bo.new_building_ == BuildingNecessity::kForced) {
1121+ prio += 20;
1122 }
1123
1124+ // Overdue priority here
1125+ prio += bo.primary_priority_;
1126+
1127+ prio += bf->supporters_nearby_.at(bo.outputs_.at(0)) * 5;
1128+
1129 prio +=
1130 (bf->critters_nearby_ * 3) - 8 - 5 * bf->producers_nearby_.at(bo.outputs_.at(0));
1131
1132 } else if (bo.is_fisher_) { // fisher
1133
1134- // ~are fishes needed?
1135- if (bo.max_needed_preciousness_ == 0) {
1136- continue;
1137- }
1138-
1139- if (bo.cnt_under_construction_ + bo.unoccupied_ > 0) {
1140- continue;
1141- }
1142-
1143- if (bf->water_nearby_ < 2) {
1144- continue;
1145- }
1146-
1147- // we use preciousness to allow atlanteans to build the fishers huts
1148- // atlanteans have preciousness 4, other tribes 3
1149- if (bo.max_needed_preciousness_ < 4 && new_buildings_stop_) {
1150- continue;
1151- }
1152-
1153- if (bo.stocklevel_time < game().get_gametime() - 5 * 1000) {
1154- bo.stocklevel_ = get_stocklevel_by_hint(static_cast<size_t>(bo.production_hint_));
1155- bo.stocklevel_time = game().get_gametime();
1156- }
1157-
1158- if (bo.stocklevel_ > 50) {
1159- continue;
1160- }
1161-
1162- if (bf->producers_nearby_.at(bo.outputs_.at(0)) >= 1) {
1163- continue;
1164- }
1165-
1166- prio = bf->fish_nearby_ - new_buildings_stop_ * 15 * bo.total_count();
1167+ if (bf->water_nearby_ < 2 || bf->fish_nearby_ < 2) {
1168+ continue;
1169+ }
1170+
1171+ if (bo.new_building_ == BuildingNecessity::kForced) {
1172+ prio += 20;
1173+ }
1174+
1175+ // Overdue priority here
1176+ prio += bo.primary_priority_;
1177+
1178+ prio -= bf->producers_nearby_.at(bo.outputs_.at(0)) * 20;
1179+ prio += bf->supporters_nearby_.at(bo.outputs_.at(0)) * 10;
1180+
1181+ prio += -5 + bf->fish_nearby_;
1182
1183 } else if (bo.production_hint_ >= 0) {
1184- // first setting targets (needed also for dismantling)
1185 if (bo.plants_trees_) {
1186- bo.cnt_target_ =
1187- 2 + static_cast<int32_t>(mines_.size() + productionsites.size()) / 15;
1188+ assert (bo.cnt_target_ > 0);
1189 } else {
1190 bo.cnt_target_ =
1191- 1 + static_cast<int32_t>(mines_.size() + productionsites.size()) / 20;
1192+ 1 + static_cast<int32_t>(mines_.size() + productionsites.size()) / 50;
1193 }
1194
1195- if ((bo.cnt_under_construction_ + bo.unoccupied_) > 1) {
1196- continue;
1197- }
1198+ // They have no own primary priority
1199+ assert(bo.primary_priority_ == 0);
1200
1201 if (bo.plants_trees_) { // RANGERS
1202
1203+ assert(bo.new_building_ == BuildingNecessity::kNeeded);
1204+
1205 // if there are too many trees nearby
1206 if (bf->trees_nearby_ > 25 && bo.total_count() >= 1) {
1207 continue;
1208 }
1209
1210 // for small starting spots - to prevent crowding by rangers and trees
1211- if (spots_ < (10 * bo.total_count()) && bo.total_count() > 0) {
1212+ if (spots_ < (4 * bo.total_count()) && bo.total_count() > 0) {
1213 continue;
1214 }
1215
1216 if (bo.total_count() == 0) {
1217 prio = 200;
1218- }
1219- if (bo.total_count() > 2 * bo.cnt_target_) {
1220- continue;
1221- }
1222- // we can go above target if there is shortage of logs on stock
1223- else if (bo.total_count() >= bo.cnt_target_) {
1224- if (wood_policy_ != WoodPolicy::kBuildRangers) {
1225- continue;
1226- }
1227+ } else {
1228+ prio = 50 / bo.total_count();
1229 }
1230
1231- // considering near trees and producers
1232- prio += (30 - bf->trees_nearby_) * 2 +
1233- bf->producers_nearby_.at(bo.production_hint_) * 5 -
1234- new_buildings_stop_ * 15;
1235+ // considering producers
1236+ prio += std::min<uint8_t>(bf->producers_nearby_.at(bo.production_hint_), 4) * 5 -
1237+ new_buildings_stop_ * 15 -
1238+ bf->space_consumers_nearby_ * 5 -
1239+ bf->stones_nearby_ / 3 +
1240+ bf->trees_nearby_ / 2 +
1241+ std::min<uint8_t>(bf->supporters_nearby_.at(bo.production_hint_), 4) * 3;
1242
1243 } else { // FISH BREEDERS and GAME KEEPERS
1244- if (new_buildings_stop_ && (bo.total_count() - bo.unconnected_) > 0) {
1245- continue;
1246- }
1247
1248 // especially for fish breeders
1249- if (bo.need_water_ && bf->water_nearby_ < 2) {
1250+ if (bo.need_water_ && (bf->water_nearby_ < 6 || bf->fish_nearby_ < 6)) {
1251 continue;
1252 }
1253 if (bo.need_water_) {
1254- prio += bf->water_nearby_ / 5;
1255+ prio += (-6 + bf->water_nearby_) / 3;
1256+ prio += (-6 + bf->fish_nearby_) / 3;
1257 }
1258
1259- if ((bo.total_count() - bo.unconnected_) > bo.cnt_target_) {
1260+ if ((bo.total_count() - bo.unconnected_count_) > bo.cnt_target_) {
1261 continue;
1262 }
1263
1264@@ -1735,16 +1894,17 @@
1265 continue;
1266 }
1267
1268- if (bo.total_count() == 0 && gametime > 45 * 1000) {
1269- prio += 100 + bf->producers_nearby_.at(bo.production_hint_) * 10;
1270- } else if (bf->producers_nearby_.at(bo.production_hint_) == 0) {
1271- continue;
1272- } else {
1273- prio += bf->producers_nearby_.at(bo.production_hint_) * 10;
1274+ if (bo.total_count() == 0) {
1275+ prio += 100;
1276+ } else if (!bo.need_water_) {
1277+ prio += 10 / bo.total_count();
1278 }
1279
1280+ prio += bf->producers_nearby_.at(bo.production_hint_) * 10;
1281+ prio -= bf->supporters_nearby_.at(bo.production_hint_) * 20;
1282+
1283 if (bf->enemy_nearby_) {
1284- prio -= 10;
1285+ prio -= 5;
1286 }
1287 }
1288
1289@@ -1752,64 +1912,41 @@
1290 // this will depend on number of mines_ and productionsites
1291 if (static_cast<int32_t>((productionsites.size() + mines_.size()) / 30) >
1292 bo.total_count() &&
1293- (bo.cnt_under_construction_ + bo.unoccupied_) == 0 &&
1294+ (bo.cnt_under_construction_ + bo.unoccupied_count_) == 0 &&
1295 // but only if current buildings are utilized enough
1296 (bo.total_count() == 0 || bo.current_stats_ > 60)) {
1297- prio = 4 + kDefaultPrioBoost;
1298+ prio = 10;
1299 }
1300 } else { // finally normal productionsites
1301- if (bo.production_hint_ >= 0) {
1302- continue;
1303- }
1304-
1305- // generally we allow 1 building in construction, but if
1306- // preciousness of missing ware is >=10 and it is farm-like building
1307- // we allow 2 in construction
1308- if (bo.max_needed_preciousness_ >= 10
1309- && bo.inputs_.empty()
1310- && gametime > 30 * 60 * 1000) {
1311- if ((bo.cnt_under_construction_ + bo.unoccupied_) > 1) {
1312- continue;
1313- }
1314- } else {
1315- if ((bo.cnt_under_construction_ + bo.unoccupied_) > 0) {
1316- continue;
1317- }
1318- }
1319-
1320- if (bo.forced_after_ < gametime && (bo.total_count() - bo.unconnected_) == 0) {
1321+ assert (bo.production_hint_ < 0);
1322+
1323+ if (bo.new_building_ == BuildingNecessity::kForced) {
1324 prio += 150;
1325- } else if ((bo.cnt_built_ - bo.unconnected_) == 1 &&
1326- game().get_gametime() > 40 * 60 * 1000 &&
1327- bo.desc->enhancement() != INVALID_INDEX && !mines_.empty()) {
1328- prio += 10;
1329 } else if (bo.is_shipyard_) {
1330+ assert (bo.new_building_ == BuildingNecessity::kAllowed);
1331 if (!seafaring_economy) {
1332 continue;
1333 }
1334- } else if (bo.output_needed_ == ExtendedBool::kFalse) {
1335- continue;
1336- } else if ((bo.cnt_built_ - bo.unconnected_) == 0 &&
1337- game().get_gametime() > 40 * 60 * 1000) {
1338- prio += kDefaultPrioBoost;
1339- } else if ((bo.cnt_built_ - bo.unconnected_) > 1 && bo.current_stats_ > 97) {
1340- prio -= kDefaultPrioBoost * (new_buildings_stop_);
1341- } else if (new_buildings_stop_) {
1342- continue;
1343+ } else {
1344+ assert (bo.new_building_ == BuildingNecessity::kNeeded);
1345 }
1346+
1347+ // Overdue priority here
1348+ prio += bo.primary_priority_;
1349+
1350 // we check separatelly buildings with no inputs and some inputs
1351 if (bo.inputs_.empty()) {
1352
1353- prio += bo.max_needed_preciousness_ + kDefaultPrioBoost;
1354-
1355- if (bo.space_consumer_) { // need to consider trees nearby
1356- prio += 20 - (bf->trees_nearby_ / 3);
1357- }
1358-
1359- // we attempt to cluster space consumers together
1360- if (bo.space_consumer_) { // need to consider trees nearby
1361- prio += bf->space_consumers_nearby_ * 10;
1362- prio += (bf->space_consumers_nearby_ > 2) ? 2 : bf->space_consumers_nearby_ * 2;
1363+ if (bo.space_consumer_) {
1364+ // we dont like trees nearby
1365+ prio += 1 - bf->trees_nearby_ / 15;
1366+ // we attempt to cluster space consumers together
1367+ prio += bf->space_consumers_nearby_ * 2;
1368+ // and be far from rangers
1369+ prio += 1 - bf->rangers_nearby_ * 3;
1370+ } else {
1371+ // leave some free space between them
1372+ prio -= bf->producers_nearby_.at(bo.outputs_.at(0)) * 5;
1373 }
1374
1375 if (bo.space_consumer_ && !bf->water_nearby_) { // not close to water
1376@@ -1817,33 +1954,16 @@
1377 }
1378
1379 if (bo.space_consumer_ &&
1380- !bf->unowned_mines_pots_nearby_) { // not close to mountains
1381+ !bf->unowned_mines_spots_nearby_) { // not close to mountains
1382 prio += 1;
1383 }
1384-
1385- if (!bo.space_consumer_) {
1386- prio -= bf->producers_nearby_.at(bo.outputs_.at(0)) * 20;
1387- } // leave some free space between them
1388 }
1389
1390 else if (bo.is_shipyard_) {
1391 // for now AI builds only one shipyard
1392- if (bf->water_nearby_ > 3 && (bo.total_count() - bo.unconnected_) == 0 &&
1393+ if (bf->water_nearby_ > 3 && (bo.total_count() - bo.unconnected_count_) == 0 &&
1394 seafaring_economy) {
1395- prio += kDefaultPrioBoost + productionsites.size() * 5 + bf->water_nearby_;
1396- }
1397-
1398- } else if (!bo.inputs_.empty()) {
1399- if ((bo.total_count() - bo.unconnected_ == 0)) {
1400- prio += bo.max_needed_preciousness_ + kDefaultPrioBoost;
1401- }
1402- if ((bo.cnt_built_ - bo.unconnected_) > 0
1403- &&
1404- is_productionsite_needed(bo.outputs_.size(),
1405- bo.current_stats_,
1406- PerfEvaluation::kForConstruction)) {
1407- prio += bo.max_needed_preciousness_ + kDefaultPrioBoost - 3 +
1408- (bo.current_stats_ - 55) / 8;
1409+ prio += productionsites.size() * 5 + bf->water_nearby_;
1410 }
1411 }
1412
1413@@ -1871,19 +1991,14 @@
1414 }
1415 }
1416
1417- // consider borders (for medium + big buildings and ones with input)
1418- // =>decreasing the score
1419- // but only if we have enough free spots to built on
1420- // otherwise it will slow down the expansion - small buildings would be preferred
1421- if (spots_avail.at(BUILDCAPS_MEDIUM) > 40
1422- &&
1423- spots_avail.at(BUILDCAPS_BIG) > 20
1424- &&
1425- (bo.desc->get_size() == 2 ||
1426- bo.desc->get_size() == 3 ||
1427- !bo.inputs_.empty())) {
1428+ // Consider border with exemption of some huts
1429+ if (! (bo.need_trees_ || bo.need_water_ || bo.is_fisher_)) {
1430 prio = recalc_with_border_range(*bf, prio);
1431- }
1432+ } else if (bf->near_border_
1433+ &&
1434+ (bo.need_trees_ || bo.need_water_)) {
1435+ prio /= 2;
1436+ }
1437
1438 } // production sites done
1439 else if (bo.type == BuildingObserver::MILITARYSITE) {
1440@@ -1896,63 +2011,11 @@
1441 continue;
1442 }
1443
1444- prio = 0;
1445-
1446- // calculating some sub-scores, some of them are prohibitive
1447- // decreasing score if some critical materials are missing
1448- // (relevant for medium and big buildings)
1449- int32_t prio_for_mat_shortage = 0;
1450- prio_for_mat_shortage -= bo.cnt_under_construction_ * bo.build_material_shortage_;
1451- if (bf->enemy_nearby_) {
1452- prio_for_mat_shortage *= 50;
1453- } else {
1454- prio_for_mat_shortage *= 1000; // = prohibitive
1455- }
1456-
1457- // decreasing score if other militarysites constuctions
1458- // are nearby
1459- int32_t prio_for_in_constr = 0;
1460- prio_for_in_constr -= 700 * (((static_cast<int32_t>(num_milit_constructionsites) - 2) < 0) ?
1461- 0 :
1462- (num_milit_constructionsites - 2)) /
1463- (militarysites.size() + 2);
1464- if (!bf->enemy_nearby_) {
1465- prio_for_in_constr *= 3;
1466- }
1467-
1468- // similarly if unmanned militarysites are nearby
1469- int32_t prio_for_unmanned_nearby = 0;
1470- prio_for_unmanned_nearby -= bf->military_in_constr_nearby_ + bf->military_unstationed_;
1471- if (bf->enemy_nearby_) {
1472- prio_for_unmanned_nearby *= 20;
1473- } else {
1474- prio_for_unmanned_nearby *= 1000;
1475- }
1476-
1477- // not continuing if score too low
1478- if (prio_for_in_constr + prio_for_mat_shortage + prio_for_unmanned_nearby <= -1000) {
1479- continue;
1480- }
1481-
1482- // is the building suitable for the situation?
1483- if (expansion_mode == MilitaryStrategy::kNoNewMilitary) {
1484- continue;
1485- }
1486-
1487- if (expansion_mode == MilitaryStrategy::kDefenseOnly && !bf->enemy_nearby_) {
1488- continue;
1489- }
1490-
1491- if (expansion_mode == MilitaryStrategy::kResourcesOrDefense &&
1492- !(bf->unowned_mines_pots_nearby_ || bf->stones_nearby_ || bf->water_nearby_ ||
1493- (bf->distant_water_ && resource_necessity_water_needed_) || bf->enemy_nearby_)) {
1494- continue;
1495- }
1496-
1497+ // This is another restriction of military building - but general
1498 if (bf->enemy_nearby_ && bo.fighting_type_) {
1499 ;
1500 } // it is ok, go on
1501- else if (bf->unowned_mines_pots_nearby_ > 2 &&
1502+ else if (bf->unowned_mines_spots_nearby_ > 2 &&
1503 (bo.mountain_conqueror_ || bo.expansion_type_)) {
1504 ;
1505 } // it is ok, go on
1506@@ -1960,87 +2023,55 @@
1507 if (bo.desc->get_size() == 2 && gametime % 2 >= 1) {
1508 continue;
1509 }
1510- if (bo.desc->get_size() == 3 && gametime % 3 >= 1) {
1511+ if (bo.desc->get_size() == 3 && gametime % 4 >= 1) {
1512 continue;
1513 };
1514 } else {
1515 continue;
1516 } // the building is not suitable for situation
1517
1518-
1519- // calculating other sub scores
1520- // for resources (mines, water, stones)
1521- int32_t prio_for_resources = 0;
1522- prio_for_resources += 2 * (bf->unowned_mines_pots_nearby_ * resource_necessity_mines_) / 100 +
1523- bf->stones_nearby_ + (bf->water_nearby_ * resource_necessity_water_) / 100;
1524- // special bonus due to remote water for atlanteans
1525- if (resource_necessity_water_needed_) {
1526- prio_for_resources += (bf->distant_water_ * resource_necessity_water_) / 100 / 3;
1527- }
1528- // reducing score if too little unowned land
1529- if (bf->unowned_land_nearby_ < 10) {
1530- prio_for_resources = prio_for_resources * bf->unowned_land_nearby_ / 10;
1531- }
1532- if (bf->enemy_nearby_) { // not important when fighting enemies
1533- prio_for_resources /= 5;
1534- }
1535-
1536- // for unowned land nearby
1537- int32_t prio_for_unowned_land = 0;
1538- if (expansion_mode == MilitaryStrategy::kExpansion ||
1539- expansion_mode == MilitaryStrategy::kPushExpansion) {
1540- prio_for_unowned_land +=
1541- (bf->unowned_land_nearby_ * resource_necessity_territory_) / 100;
1542- }
1543-
1544- // for distance to nearest military sites
1545- int32_t prio_for_loneliness = bf->military_loneliness_;
1546- if (!bf->enemy_nearby_) {
1547- prio_for_loneliness /= 10;
1548- }
1549+ // score here is a compound of various input values
1550+ // usually resources in vicinity, but when enemy is nearby
1551+ // additional bonus is added
1552+ if (bf->enemy_nearby_) {
1553+ prio += bf->military_loneliness_ / 3;
1554+ prio += (20 - bf->area_military_capacity_) * 25;
1555+ prio -= bo.build_material_shortage_ * 50;
1556+ prio -= (bf->military_in_constr_nearby_ + bf->military_unstationed_) * 50;
1557+ } else {
1558+ if (bf->near_border_) {
1559+ prio += 50;
1560+ prio -= bo.build_material_shortage_ * 150;
1561+ } else {
1562+ prio -= bo.build_material_shortage_ * 500; // prohibitive
1563+ }
1564+ prio -= (bf->military_in_constr_nearby_ + bf->military_unstationed_) * 150;
1565+ prio += (5 - bf->own_military_sites_nearby_()) * 15;
1566+ }
1567+ prio += bf->unowned_land_nearby_ * resource_necessity_territory_ / 100;
1568+ prio += bf->unowned_mines_spots_nearby_ * resource_necessity_mines_ / 100;
1569+ prio += ((bf->unowned_mines_spots_nearby_ > 0) ? 20 : 0) *
1570+ resource_necessity_mines_ / 100;
1571+ prio += bf->stones_nearby_ / 2;
1572+ prio += bf->water_nearby_;
1573+ prio += bf->distant_water_ * resource_necessity_water_needed_ / 100;
1574+ prio += bf->military_loneliness_ / 10;
1575+ prio += bf->trees_nearby_ / 3;
1576+ if (bf->portspace_nearby_ == ExtendedBool::kTrue) prio += 25;
1577
1578 // additional score for bigger buildings
1579 int32_t prio_for_size = bo.desc->get_size() - 1;
1580 if (bf->enemy_nearby_) {
1581 prio_for_size *= 30;
1582 } else {
1583- prio_for_size *= 15;
1584- }
1585-
1586- // additional score if enemy is nearby
1587- int32_t prio_for_enemy = 0;
1588- if (bf->enemy_nearby_) {
1589- prio_for_enemy += 50;
1590- }
1591-
1592- // a boost to prevent an expansion halt
1593- int32_t local_boost = 0;
1594- if (expansion_mode == MilitaryStrategy::kPushExpansion) {
1595- local_boost = 200;
1596- }
1597-
1598- // summing
1599- prio += prio_for_mat_shortage + prio_for_in_constr + prio_for_unmanned_nearby +
1600- prio_for_resources + prio_for_unowned_land + prio_for_loneliness +
1601- prio_for_size + local_boost + prio_for_enemy;
1602-
1603- // special bonus if a portspace is close
1604- if (bf->portspace_nearby_ == ExtendedBool::kTrue) {
1605- if (num_ports == 0) {
1606- prio += 25;
1607- } else {
1608- prio += 5;
1609- }
1610- }
1611-
1612- // penalty if we build lesser than possible building
1613- if (bo.desc->get_size() < maxsize) {
1614- prio = prio - 5;
1615- }
1616-
1617- // just generally prevent too many buildings
1618- prio -= 40;
1619-
1620+ prio_for_size *= 5;
1621+ }
1622+ prio += prio_for_size;
1623+
1624+ // if place+building is not good enough
1625+ if (prio <= target_military_score_) {
1626+ continue;
1627+ }
1628 } else if (bo.type == BuildingObserver::WAREHOUSE) {
1629
1630 // exclude spots on border
1631@@ -2074,7 +2105,7 @@
1632 // But we still can built a port if it is first one
1633 if (bo.is_port_ && bo.total_count() == 0 && productionsites.size() > 5 &&
1634 !bf->enemy_nearby_ && bf->is_portspace_ && seafaring_economy) {
1635- prio += kDefaultPrioBoost + productionsites.size();
1636+ prio += productionsites.size();
1637 warehouse_needed = true;
1638 }
1639
1640@@ -2103,15 +2134,11 @@
1641 // but limit to 30
1642 const uint16_t max_distance_considered = 30;
1643 nearest_distance = std::min(nearest_distance, max_distance_considered);
1644- prio += nearest_distance - 10;
1645+ prio += nearest_distance - 30;
1646
1647 // dont be close to enemies
1648- if (bf->enemy_nearby_){
1649- if (bo.is_port_) {
1650- prio -= 10;
1651- } else {
1652- prio -= 40;
1653- }
1654+ if (bf->enemy_nearby_) {
1655+ prio -= 40;
1656 }
1657
1658 // being too close to a border is not good either
1659@@ -2122,6 +2149,8 @@
1660
1661 } else if (bo.type == BuildingObserver::TRAININGSITE) {
1662
1663+ assert(!bo.build_material_shortage_);
1664+
1665 // exclude spots on border
1666 if (bf->near_border_) {
1667 continue;
1668@@ -2158,7 +2187,7 @@
1669 continue;
1670 }
1671
1672- prio = 4 + kDefaultPrioBoost;
1673+ prio = 10;
1674
1675 // take care about borders and enemies
1676 if (bf->enemy_nearby_) {
1677@@ -2166,7 +2195,7 @@
1678 }
1679
1680 if (bf->unowned_land_nearby_) {
1681- prio /= 2;
1682+ prio -= bf->unowned_land_nearby_ / 10;
1683 }
1684 }
1685
1686@@ -2189,8 +2218,20 @@
1687
1688 // Prefer road side fields
1689 prio += bf->preferred_ ? 5 : 0;
1690+
1691 // don't waste good land for small huts
1692- prio -= (maxsize - bo.desc->get_size()) * 20;
1693+ const bool space_stress =
1694+ (spots_avail.at(BUILDCAPS_MEDIUM) < 5
1695+ ||
1696+ spots_avail.at(BUILDCAPS_BIG) < 5);
1697+
1698+ if (space_stress && bo.type == BuildingObserver::MILITARYSITE) {
1699+ prio -= (bf->max_buildcap_nearby_ - bo.desc->get_size()) * 3;
1700+ } else if (space_stress) {
1701+ prio -= (bf->max_buildcap_nearby_ - bo.desc->get_size()) * 10;
1702+ } else {
1703+ prio -= (bf->max_buildcap_nearby_ - bo.desc->get_size()) * 3;
1704+ }
1705
1706 // prefer vicinity of ports (with exemption of warehouses)
1707 if (bf->port_nearby_ && bo.type == BuildingObserver::MILITARYSITE) {
1708@@ -2217,11 +2258,7 @@
1709 for (uint32_t i = 0; i < buildings_.size() && productionsites.size() > 8; ++i) {
1710 BuildingObserver& bo = buildings_.at(i);
1711
1712- if (!bo.buildable(*player_) || bo.type != BuildingObserver::MINE) {
1713- continue;
1714- }
1715-
1716- if (bo.prohibited_till_ > gametime) {
1717+ if (bo.type != BuildingObserver::MINE) {
1718 continue;
1719 }
1720
1721@@ -2229,27 +2266,13 @@
1722 continue;
1723 }
1724
1725- // Don't build another building of this type, if there is already
1726- // one that is unoccupied_ at the moment
1727- // or under construction
1728- if ((bo.cnt_under_construction_ + bo.unoccupied_) > 0) {
1729- continue;
1730- }
1731-
1732- if (bo.output_needed_ == ExtendedBool::kUnset) {
1733- check_building_necessity(bo);
1734- }
1735-
1736- if (bo.output_needed_ == ExtendedBool::kFalse
1737- &&
1738- (bo.total_count() - bo.unconnected_) > 0) {
1739+ assert(bo.new_building_ != BuildingNecessity::kAllowed);
1740+
1741+ // skip if a mine is not required
1742+ if (!(bo.new_building_ == BuildingNecessity::kNeeded ||
1743+ bo.new_building_ == BuildingNecessity::kForced)) {
1744 continue;
1745- }
1746-
1747- // if current one(s) are performing badly
1748- if ((bo.total_count() - bo.unconnected_) >= 1 && bo.current_stats_ < 50) {
1749- continue;
1750- }
1751+ }
1752
1753 // this is penalty if there are existing mines too close
1754 // it is treated as multiplicator for count of near mines
1755@@ -2265,10 +2288,7 @@
1756 uint32_t bonus_score = 0;
1757 if ((mines_per_type[bo.mines_].in_construction + mines_per_type[bo.mines_].finished) ==
1758 0) {
1759- bonus_score = 15;
1760- } else if ((mines_per_type[bo.mines_].in_construction +
1761- mines_per_type[bo.mines_].finished) == 1) {
1762- bonus_score = 5;
1763+ bonus_score = 2 * bo.primary_priority_;
1764 }
1765
1766 // iterating over fields
1767@@ -2308,7 +2328,7 @@
1768 prio += bonus_score;
1769
1770 // applying max needed
1771- prio += bo.max_needed_preciousness_ * 3;
1772+ prio += bo.primary_priority_;
1773
1774 // prefer mines in the middle of mine fields of the
1775 // same type, so we add a small bonus here
1776@@ -2336,6 +2356,8 @@
1777 // Prefer road side fields
1778 prio += mf->preferred_ ? 1 : 0;
1779
1780+ prio += bo.primary_priority_;
1781+
1782 if (prio > proposed_priority) {
1783 best_building = &bo;
1784 proposed_priority = prio;
1785@@ -2353,12 +2375,21 @@
1786 return false;
1787 }
1788
1789+ if (best_building->type == BuildingObserver::MILITARYSITE) {
1790+ target_military_score_ = proposed_priority;
1791+ player_->set_ai_data(target_military_score_, kTargetMilit);
1792+ }
1793+
1794+
1795 // send the command to construct a new building
1796 game().send_player_build(player_number(), proposed_coords, best_building->id);
1797 BlockedField blocked(
1798 game().map().get_fcoords(proposed_coords), game().get_gametime() + 120000); // two minutes
1799 blocked_fields.push_back(blocked);
1800
1801+ // resetting new_building_overdue_
1802+ best_building->new_building_overdue_ = 0;
1803+
1804 // we block also nearby fields
1805 // if farms and so on, for quite a long time
1806 // if military sites only for short time for AI can update information on near buildable fields
1807@@ -2583,27 +2614,6 @@
1808 return false;
1809 }
1810
1811-// is productionsite needed
1812-// used for building new buildings or dismantle of old, intended for ones
1813-// that have inputs
1814-bool DefaultAI::is_productionsite_needed(int32_t outputs,
1815- int32_t performance,
1816- PerfEvaluation purpose) {
1817- int32_t expected_performance = 0;
1818- if (outputs > 0) {
1819- expected_performance = 10 + 70 / outputs;
1820- } else {
1821- expected_performance = 80;
1822- }
1823- if (purpose == PerfEvaluation::kForDismantle) {
1824- expected_performance /= 2;
1825- }
1826- if (performance > expected_performance) {
1827- return true;
1828- }
1829- return false;
1830-}
1831-
1832 // trying to connect the flag to another one, be it from own economy
1833 // or other economy
1834 bool DefaultAI::create_shortcut_road(const Flag& flag,
1835@@ -2989,8 +2999,10 @@
1836
1837 const BuildingIndex enhancement = site.site->descr().enhancement();
1838 if (connected_to_wh && enhancement != INVALID_INDEX &&
1839- ((site.bo->cnt_built_ - site.bo->unoccupied_) > 1 ||
1840- site.bo->upgrade_substitutes_)) {
1841+ (site.bo->cnt_built_ - site.bo->unoccupied_count_ > 1 ||
1842+ ((site.bo->upgrade_substitutes_ || site.bo->upgrade_extends_) &&
1843+ gametime > 45 * 60 * 1000 &&
1844+ gametime > site.built_time_ + 20 * 60 * 1000))) {
1845
1846 BuildingIndex enbld = INVALID_INDEX; // to get rid of this
1847
1848@@ -3003,13 +3015,13 @@
1849 BuildingObserver* bestbld = nullptr;
1850
1851 if (gametime - en_bo.construction_decision_time_ >= kBuildingMinInterval &&
1852- (en_bo.cnt_under_construction_ + en_bo.unoccupied_) == 0) {
1853+ (en_bo.cnt_under_construction_ + en_bo.unoccupied_count_) == 0) {
1854
1855 // don't upgrade without workers
1856 if (site.site->has_workers(enhancement, game())) {
1857
1858 // forcing first upgrade
1859- if (en_bo.cnt_built_ == 0) {
1860+ if (en_bo.total_count() == 0) {
1861 enbld = enhancement;
1862 bestbld = &en_bo;
1863 }
1864@@ -3051,6 +3063,16 @@
1865 // Lumberjack / Woodcutter handling
1866 if (site.bo->need_trees_) {
1867
1868+ const uint32_t remaining_trees =
1869+ map.find_immovables(Area<FCoords>(map.get_fcoords(site.site->get_position()), radius),
1870+ nullptr,
1871+ FindImmovableAttribute(MapObjectDescr::get_attribute_id("tree")));
1872+
1873+ // generally, trees_around_cutters_ = remaining_trees + 9 * trees_around_cutters_
1874+ // but keep in mind that trees_around_cutters_ is multiplied by 10
1875+ trees_around_cutters_ = (remaining_trees * 10 + 9 * trees_around_cutters_) / 10;
1876+ player_->set_ai_data(trees_around_cutters_, kTreesAround);
1877+
1878 // Do not destruct the last few lumberjacks
1879 if (site.bo->cnt_built_ <= site.bo->cnt_target_) {
1880 return false;
1881@@ -3060,10 +3082,7 @@
1882 return false;
1883 }
1884
1885- const uint32_t remaining_trees =
1886- map.find_immovables(Area<FCoords>(map.get_fcoords(site.site->get_position()), radius),
1887- nullptr,
1888- FindImmovableAttribute(MapObjectDescr::get_attribute_id("tree")));
1889+
1890
1891 // do not dismantle if there are some trees remaining
1892 if (remaining_trees > 5) {
1893@@ -3182,14 +3201,14 @@
1894 site.bo->space_consumer_ && !site.bo->plants_trees_) {
1895
1896 // if we have more buildings then target
1897- if ((site.bo->cnt_built_ - site.bo->unconnected_) > site.bo->cnt_target_) {
1898+ if ((site.bo->cnt_built_ - site.bo->unconnected_count_) > site.bo->cnt_target_) {
1899 if (site.bo->stocklevel_time < game().get_gametime() - 5 * 1000) {
1900 site.bo->stocklevel_ = get_stocklevel(*site.bo);
1901 site.bo->stocklevel_time = game().get_gametime();
1902 }
1903
1904 if (site.site->get_statistics_percent() < 30 &&
1905- site.bo->stocklevel_ > 100) { // production stats == 0%
1906+ site.bo->stocklevel_ > 100) {
1907 site.bo->last_dismantle_time_ = game().get_gametime();
1908 flags_to_be_removed.push_back(site.site->base_flag().get_position());
1909 if (connected_to_wh) {
1910@@ -3218,15 +3237,17 @@
1911
1912 // buildings with inputs_, checking if we can a dismantle some due to low performance
1913 if (!site.bo->inputs_.empty() &&
1914- (site.bo->cnt_built_ - site.bo->unoccupied_) >= 3 &&
1915+ (site.bo->cnt_built_ - site.bo->unoccupied_count_) >= 3 &&
1916 site.site->can_start_working() &&
1917- !is_productionsite_needed(site.bo->outputs_.size(),
1918- site.site->get_statistics_percent(),
1919- PerfEvaluation::kForDismantle) &&
1920- site.bo->current_stats_ < 30 && // overall statistics
1921+ check_building_necessity(*site.bo, PerfEvaluation::kForDismantle, gametime)
1922+ == BuildingNecessity::kNotNeeded &&
1923+ gametime - site.bo->last_dismantle_time_ > 5 * 60 * 1000 &&
1924+
1925+ site.bo->current_stats_ > site.site->get_statistics_percent() && // underperformer
1926 (game().get_gametime() - site.unoccupied_till_) > 10 * 60 * 1000) {
1927
1928 site.bo->last_dismantle_time_ = game().get_gametime();
1929+
1930 flags_to_be_removed.push_back(site.site->base_flag().get_position());
1931 if (connected_to_wh) {
1932 game().send_player_dismantle(*site.site);
1933@@ -3238,7 +3259,6 @@
1934
1935 // remaining buildings without inputs and not supporting ones (fishers only left probably and
1936 // hunters)
1937-
1938 if (site.bo->inputs_.empty() && site.bo->production_hint_ < 0 &&
1939 site.site->can_start_working() && !site.bo->space_consumer_ &&
1940 site.site->get_statistics_percent() < 10 &&
1941@@ -3258,6 +3278,11 @@
1942 // stop/start them based on stock avaiable
1943 if (site.bo->production_hint_ >= 0) {
1944
1945+ if (!site.bo->plants_trees_) {
1946+ // other supporting sites, like fish breeders, gamekeepers are not dismantled at all
1947+ return false;
1948+ }
1949+
1950 // dismantling the rangers hut, but only if we have them above a target
1951 if (wood_policy_ == WoodPolicy::kDismantleRangers && site.bo->cnt_built_ > site.bo->cnt_target_) {
1952
1953@@ -3294,8 +3319,7 @@
1954 game().send_player_start_stop_building(*site.site);
1955 }
1956 // if not enough trees nearby, we can start them if required
1957- } else if ((wood_policy_ == WoodPolicy::kStartRangers ||
1958- wood_policy_ == WoodPolicy::kBuildRangers)
1959+ } else if ((wood_policy_ == WoodPolicy::kAllowRangers)
1960 &&
1961 site.site->is_stopped()) {
1962 game().send_player_start_stop_building(*site.site);
1963@@ -3325,7 +3349,6 @@
1964 player_ = game().get_player(player_number());
1965 uint16_t ports_count = 0;
1966 uint16_t shipyards_count = 0;
1967- uint16_t working_shipyards_count = 0;
1968 uint16_t expeditions_in_prep = 0;
1969 uint16_t expeditions_in_progress = 0;
1970 bool idle_shipyard_stocked = false;
1971@@ -3346,9 +3369,7 @@
1972 for (const ProductionSiteObserver& ps_obs : productionsites) {
1973 if (ps_obs.bo->is_shipyard_) {
1974 shipyards_count += 1;
1975- if (!ps_obs.site->is_stopped()) {
1976- working_shipyards_count += 1;
1977- }
1978+
1979 // counting stocks
1980 uint8_t stocked_wares = 0;
1981 std::vector<WaresQueue*> const warequeues = ps_obs.site->warequeues();
1982@@ -3531,61 +3552,97 @@
1983 return true;
1984 }
1985
1986- // doing nothing when failed count is too low
1987- if (site.no_resources_count < 4) {
1988+ // to avoid problems with uint underflow, we discourage considerations below
1989+ if (gametime < 10 * 60 * 1000) {
1990 return false;
1991 }
1992
1993- // dismantling when the failed count is too high
1994- if (site.no_resources_count > 12) {
1995- flags_to_be_removed.push_back(site.site->base_flag().get_position());
1996- if (connected_to_wh) {
1997- game().send_player_dismantle(*site.site);
1998- } else {
1999- game().send_player_bulldoze(*site.site);
2000- }
2001- site.bo->construction_decision_time_ = gametime;
2002- return true;
2003- }
2004-
2005- // is output needed (compare stocked materials vs target values)
2006- check_building_necessity(*site.bo);
2007-
2008- // if we have enough of mined materials on stock - do not upgrade (yet)
2009- if (site.bo->output_needed_ == ExtendedBool::kFalse) {
2010+ // if mine is working, doing nothing
2011+ if (site.no_resources_since_ > gametime - 5 * 60 * 1000) {
2012 return false;
2013 }
2014
2015 // Check whether building is enhanceable. If yes consider an upgrade.
2016 const BuildingIndex enhancement = site.site->descr().enhancement();
2017-
2018- // if no enhancement is possible
2019- if (enhancement == INVALID_INDEX) {
2020- // will be destroyed when no_resource_count will overflow
2021+ bool has_upgrade = false;
2022+ if (enhancement != INVALID_INDEX) {
2023+ if (player_->is_building_type_allowed(enhancement)) {
2024+ has_upgrade = true;
2025+ }
2026+ }
2027+
2028+ // every type of mine has minimal number of mines that are to be preserved
2029+ // (we will not dismantle even if there are no mineable resources left for this level of mine
2030+ // and output is not needed)
2031+ bool forcing_upgrade = false;
2032+ const uint16_t minimal_mines_count = (site.bo->built_mat_producer_) ? 2 : 1;
2033+ if (has_upgrade &&
2034+ mines_per_type[site.bo->mines_].total_count() <= minimal_mines_count) {
2035+ forcing_upgrade = true;
2036+ }
2037+
2038+
2039+ // dismantling a mine
2040+ if (!has_upgrade) { // if no upgrade, now
2041+ flags_to_be_removed.push_back(site.site->base_flag().get_position());
2042+ if (connected_to_wh) {
2043+ game().send_player_dismantle(*site.site);
2044+ } else {
2045+ game().send_player_bulldoze(*site.site);
2046+ }
2047+ site.bo->construction_decision_time_ = gametime;
2048+ return true;
2049+ // if having an upgrade, after half hour
2050+ } else if (site.no_resources_since_ < gametime - 30 * 60 * 1000 && !forcing_upgrade) {
2051+ flags_to_be_removed.push_back(site.site->base_flag().get_position());
2052+ if (connected_to_wh) {
2053+ game().send_player_dismantle(*site.site);
2054+ } else {
2055+ game().send_player_bulldoze(*site.site);
2056+ }
2057+ site.bo->construction_decision_time_ = gametime;
2058+ return true;
2059+ }
2060+
2061+ // if we are here, a mine is upgradeable
2062+
2063+ // if we don't need the output, and we have other buildings of the same type, the function returns
2064+ // and building will be dismantled later.
2065+ check_building_necessity(*site.bo, PerfEvaluation::kForDismantle, gametime);
2066+ if (site.bo->max_needed_preciousness_ == 0 && !forcing_upgrade) {
2067 return false;
2068 }
2069
2070+ // again similarly, no upgrading if not connected, other parts of AI will dismantle it,
2071+ // or connect to a warehouse
2072 if (!connected_to_wh) {
2073- // no enhancement possible
2074+ return false;
2075+ }
2076+
2077+ // don't upgrade now if other mines of the same type are right now in construction
2078+ if (mines_per_type[site.bo->mines_].in_construction > 0) {
2079 return false;
2080 }
2081
2082 bool changed = false;
2083- if (player_->is_building_type_allowed(enhancement)) {
2084- // first exclude possibility there are enhancements in construction or unoccupied_
2085- const BuildingDescr& bld = *tribe_->get_building_descr(enhancement);
2086- BuildingObserver& en_bo = get_building_observer(bld.name().c_str());
2087-
2088- // if it is too soon for enhancement and making sure there are no unoccupied mines
2089- if (gametime - en_bo.construction_decision_time_ >= kBuildingMinInterval &&
2090- en_bo.unoccupied_ + en_bo.cnt_under_construction_ == 0) {
2091-
2092- // now verify that there are enough workers
2093- if (site.site->has_workers(enhancement, game())) { // enhancing
2094- game().send_player_enhance_building(*site.site, enhancement);
2095- en_bo.construction_decision_time_ = gametime;
2096- changed = true;
2097- }
2098+
2099+ // first exclude possibility there are enhancements in construction or unoccupied_count_
2100+ const BuildingDescr& bld = *tribe_->get_building_descr(enhancement);
2101+ BuildingObserver& en_bo = get_building_observer(bld.name().c_str());
2102+
2103+ // if it is too soon for enhancement
2104+ if (gametime - en_bo.construction_decision_time_ >= kBuildingMinInterval) {
2105+ // now verify that there are enough workers
2106+ if (site.site->has_workers(enhancement, game())) { // enhancing
2107+ game().send_player_enhance_building(*site.site, enhancement);
2108+ if (site.bo->max_needed_preciousness_ == 0) {
2109+ assert (mines_per_type[site.bo->mines_].total_count() <= minimal_mines_count);
2110+ }
2111+ if (mines_per_type[site.bo->mines_].total_count() > minimal_mines_count) {
2112+ assert(site.bo->max_needed_preciousness_ > 0);
2113+ }
2114+ en_bo.construction_decision_time_ = gametime;
2115+ changed = true;
2116 }
2117 }
2118
2119@@ -3608,12 +3665,18 @@
2120 return count;
2121 }
2122
2123-// goes over all outputs of a building and compare stocked material with
2124-// target values. The result is yes/no and some scores
2125-void DefaultAI::check_building_necessity(BuildingObserver& bo) {
2126- // iterate over outputs of building, counts warehoused stock
2127- // and deciding if enough
2128- bo.max_preciousness = 0;
2129+// this receives an building observer and have to decide if new/one of
2130+// current buildings of this type is needed
2131+// This is core of construct_building() function
2132+// This is run once when construct_building() is run, or when considering
2133+// dismantle
2134+BuildingNecessity DefaultAI::check_building_necessity(BuildingObserver& bo,
2135+ const PerfEvaluation purpose,
2136+ const uint32_t gametime) {
2137+
2138+ // First we iterate over outputs of building, count warehoused stock
2139+ // and deciding if we have enough on stock (in warehouses)
2140+ bo.max_preciousness_ = 0;
2141 bo.max_needed_preciousness_ = 0;
2142
2143 for (uint32_t m = 0; m < bo.outputs_.size(); ++m) {
2144@@ -3624,6 +3687,9 @@
2145 target = std::max<uint16_t>(target, 1);
2146
2147 uint16_t preciousness = wares.at(bo.outputs_.at(m)).preciousness_;
2148+ if (preciousness < 1) { // it seems there are wares with 0 preciousness
2149+ preciousness = 1; // (no entry in conf files?). But we need positive value here
2150+ }
2151
2152 if (get_warehoused_stock(wt) < target) {
2153 if (bo.max_needed_preciousness_ < preciousness) {
2154@@ -3631,16 +3697,253 @@
2155 }
2156 }
2157
2158- if (bo.max_preciousness < preciousness) {
2159- bo.max_preciousness = preciousness;
2160+ if (bo.max_preciousness_ < preciousness) {
2161+ bo.max_preciousness_ = preciousness;
2162 }
2163 }
2164
2165- // here we decide if the building is needed
2166+ if (!bo.outputs_.empty()) {
2167+ assert (bo.max_preciousness_ > 0);
2168+ }
2169+
2170+ // positive max_needed_preciousness_ says a building type is needed
2171+ // here we increase of reset the counter
2172+ // the counter is added to score when considering new building
2173 if (bo.max_needed_preciousness_ > 0) {
2174- bo.output_needed_ = ExtendedBool::kTrue;
2175- } else {
2176- bo.output_needed_ = ExtendedBool::kFalse;
2177+ bo.new_building_overdue_ += 1;
2178+ } else {
2179+ bo.new_building_overdue_ = 0;
2180+ }
2181+
2182+ // This flag is to be used when buildig is forced. AI will not build another building when
2183+ // a substitution exists. F.e. mines or pairs like tavern-inn
2184+ // To skip unnecessary calculation, we calculate this only if we have 0 count of the buildings
2185+ bool has_substitution_building = false;
2186+ if (bo.total_count() == 0 && bo.upgrade_substitutes_ && bo.type == BuildingObserver::PRODUCTIONSITE) {
2187+ const BuildingIndex enhancement = bo.desc->enhancement();
2188+ BuildingObserver& en_bo
2189+ = get_building_observer(tribe_->get_building_descr(enhancement)->name().c_str());
2190+ if (en_bo.total_count() > 0) {
2191+ has_substitution_building = true;
2192+ }
2193+ }
2194+ if (bo.total_count() == 0 && bo.type == BuildingObserver::MINE) {
2195+ if (mines_per_type[bo.mines_].in_construction + mines_per_type[bo.mines_].finished > 0) {
2196+ has_substitution_building = true;
2197+ }
2198+ }
2199+
2200+ // This function is going to say if a building is needed. But there is a 'new_buildings_stop_'
2201+ // flag that should be obeyed, but sometimes can be ignored.
2202+ // So we can have two types of needed: kNeeded and KNeededPending
2203+ // below we define which one will be returned if building is 'needed'
2204+ BuildingNecessity needed_type = BuildingNecessity::kNeeded;
2205+ if (new_buildings_stop_) {
2206+ needed_type = BuildingNecessity::kNeededPending;
2207+ if (gametime < 15 * 60 * 1000) {
2208+ ; // no exemption here within first 15 minutes
2209+ } else if (gametime < 25 * 60 * 1000) { // exemption after 15 minutes - 1 building allowed
2210+
2211+ if (bo.type == BuildingObserver::MINE) {
2212+ if (mines_per_type[bo.mines_].in_construction + mines_per_type[bo.mines_].finished == 0) {
2213+ needed_type = BuildingNecessity::kNeeded;
2214+ }
2215+ }
2216+ if (bo.type == BuildingObserver::PRODUCTIONSITE) {
2217+ if (bo.built_mat_producer_ || bo.max_needed_preciousness_ >= 10) {
2218+ if (bo.total_count() == 0) {
2219+ needed_type = BuildingNecessity::kNeeded;
2220+ }
2221+ }
2222+ }
2223+ } else { // exemption after 25 minutes - 2 buildings allowed
2224+ if (bo.type == BuildingObserver::MINE) {
2225+ if (mines_per_type[bo.mines_].in_construction + mines_per_type[bo.mines_].finished <= 1) {
2226+ needed_type = BuildingNecessity::kNeeded;
2227+ }
2228+ }
2229+ if (bo.type == BuildingObserver::PRODUCTIONSITE) {
2230+ if (bo.built_mat_producer_ || bo.max_needed_preciousness_ >= 10) {
2231+ if (bo.total_count() <= 1) {
2232+ needed_type = BuildingNecessity::kNeeded;
2233+ }
2234+ }
2235+ }
2236+ }
2237+ }
2238+
2239+ // And finally the 'core' of this function
2240+ // First deal with construction of new sites
2241+ if (purpose == PerfEvaluation::kForConstruction) {
2242+ if (bo.forced_after_ < gametime && bo.total_count() == 0 && !has_substitution_building) {
2243+ bo.max_needed_preciousness_ = bo.max_preciousness_;
2244+ return BuildingNecessity::kForced;
2245+ } else if (bo.prohibited_till_ > gametime) {
2246+ return BuildingNecessity::kNotNeeded;
2247+ } else if (bo.is_hunter_ || bo.is_fisher_) {
2248+
2249+ if (bo.max_needed_preciousness_ == 0) {
2250+ return BuildingNecessity::kNotNeeded;
2251+ } else if (bo.cnt_under_construction_ + bo.unoccupied_count_ > 0) {
2252+ return BuildingNecessity::kNotNeeded;
2253+ } else if (bo.total_count() > 0 && new_buildings_stop_) {
2254+ return BuildingNecessity::kNotNeeded;
2255+ } else {
2256+ return BuildingNecessity::kNeeded;
2257+ }
2258+ } else if (bo.need_trees_) {
2259+ if (bo.total_count() > 1 && (bo.cnt_under_construction_ + bo.unoccupied_count_ > 0)) {
2260+ return BuildingNecessity::kNotNeeded;
2261+ }
2262+ bo.cnt_target_ =
2263+ 3 + static_cast<int32_t>(mines_.size() + productionsites.size()) / 20;
2264+
2265+ // for case the wood is not needed yet, to avoid inconsistency later on
2266+ bo.max_needed_preciousness_ = bo.max_preciousness_;
2267+
2268+ if (bo.total_count() < bo.cnt_target_) {
2269+ return BuildingNecessity::kNeeded;
2270+ } else {
2271+ return BuildingNecessity::kAllowed;
2272+ }
2273+ } else if (bo.plants_trees_) {
2274+
2275+ bo.cnt_target_ =
2276+ 2 +
2277+ static_cast<int32_t>(mines_.size() + productionsites.size()) / 40;
2278+ if (wood_policy_ != WoodPolicy::kAllowRangers) {
2279+ return BuildingNecessity::kNotNeeded;
2280+ }
2281+ // 150 corresponds to 15 trees
2282+ if (trees_around_cutters_ < 150) {
2283+ bo.cnt_target_ *= 4;
2284+ }
2285+ if (bo.total_count() > 1 && (bo.cnt_under_construction_ + bo.unoccupied_count_ > 0)) {
2286+ return BuildingNecessity::kNotNeeded;
2287+ } else if (bo.total_count() > bo.cnt_target_) {
2288+ return BuildingNecessity::kNotNeeded;
2289+ }
2290+ return BuildingNecessity::kNeeded;
2291+ } else if (bo.need_stones_ && bo.cnt_under_construction_ + bo.unoccupied_count_ == 0) {
2292+ bo.max_needed_preciousness_ = bo.max_preciousness_; // even when stones are not needed
2293+ return BuildingNecessity::kAllowed;
2294+ } else if (bo.production_hint_ >= 0 && bo.cnt_under_construction_ + bo.unoccupied_count_ == 0) {
2295+ return BuildingNecessity::kAllowed;
2296+ } else if (bo.cnt_under_construction_ + bo.unoccupied_count_ > 0 && bo.max_needed_preciousness_ < 10) {
2297+ return BuildingNecessity::kNotNeeded;
2298+ } else if (bo.cnt_under_construction_ + bo.unoccupied_count_ > 0 && gametime < 30 * 60 * 1000) {
2299+ return BuildingNecessity::kNotNeeded;
2300+ } else if (bo.cnt_under_construction_ + bo.unoccupied_count_ > 1) {
2301+ return BuildingNecessity::kNotNeeded; // for preciousness>=10 and after 30 min
2302+ } else if (bo.type == BuildingObserver::MINE) {
2303+ if ((mines_per_type[bo.mines_].in_construction + mines_per_type[bo.mines_].finished) == 0) {
2304+ // unless a mine is prohibited, we want to have at least one of the kind
2305+ bo.max_needed_preciousness_ = bo.max_preciousness_;
2306+ return BuildingNecessity::kNeeded;
2307+ } else if (((mines_per_type[bo.mines_].in_construction + mines_per_type[bo.mines_].finished)
2308+ ==
2309+ 1) && bo.built_mat_producer_) {
2310+ bo.max_needed_preciousness_ = bo.max_preciousness_;
2311+ return BuildingNecessity::kNeeded;
2312+ }
2313+ if (bo.max_needed_preciousness_ == 0) {
2314+ return BuildingNecessity::kNotNeeded;
2315+ }
2316+ if (bo.total_count() - bo.unconnected_count_ >= 1 || bo.current_stats_ < 20) {
2317+ return BuildingNecessity::kNotNeeded;
2318+ }
2319+ return needed_type;
2320+ } if (bo.max_needed_preciousness_ > 0) {
2321+ if (bo.cnt_under_construction_ + bo.unoccupied_count_ > 0) {
2322+ assert (bo.cnt_under_construction_ + bo.unoccupied_count_ == 1);
2323+ assert (bo.max_needed_preciousness_ >= 10 || bo.built_mat_producer_);
2324+ assert (gametime >= 25 * 60 * 1000);
2325+ }
2326+
2327+ // First 'if' is special support for hardwood producers (to have 2 of them)
2328+ if (bo.built_mat_producer_ && bo.total_count() <= 1 && bo.current_stats_ > 10) {
2329+ return BuildingNecessity::kNeeded;
2330+ } else if (bo.inputs_.empty()) {
2331+ return needed_type;
2332+ } else if (bo.total_count() == 0) {
2333+ return needed_type;
2334+ } else if (bo.current_stats_ > 10 + 70 / bo.outputs_.size()) {
2335+ return needed_type;
2336+ } else {
2337+ return BuildingNecessity::kNotNeeded;
2338+ }
2339+ } else if (bo.is_shipyard_) {
2340+ return BuildingNecessity::kAllowed;
2341+ } else if (bo.max_needed_preciousness_ == 0) {
2342+ return BuildingNecessity::kNotNeeded;
2343+ } else {
2344+ return BuildingNecessity::kNotNeeded;
2345+ }
2346+ } else if (purpose == PerfEvaluation::kForDismantle) { // now for dismantling
2347+ // never dismantle last building (a care should be taken elsewhere)
2348+ assert (bo.total_count() > 0);
2349+ if (bo.total_count() == 1) {
2350+ return BuildingNecessity::kNeeded;
2351+ } else if (bo.max_preciousness_ >= 10 && bo.total_count() == 2) {
2352+ return BuildingNecessity::kNeeded;
2353+ } else if (bo.current_stats_ > (10 + 70 / bo.outputs_.size()) / 2) {
2354+ return BuildingNecessity::kNeeded;
2355+ } else {
2356+ return BuildingNecessity::kNotNeeded;
2357+ }
2358+ } else {
2359+ // impossible but still
2360+ assert(false);
2361+ }
2362+}
2363+
2364+// Now we can prohibit some militarysites, based on size, the goal is not to
2365+// exhaust AI resources on the beginning of the game
2366+// We count bigger buildings, medium ones get 1 points, big ones 2 points
2367+// and we force some proportion to the number of military sites
2368+// sidenote: function can return kNotNeeded, but it means 'not allowed'
2369+BuildingNecessity DefaultAI::check_building_necessity(const uint8_t size,
2370+ const uint32_t gametime) {
2371+
2372+ assert (militarysites.size() == msites_built());
2373+ // logically size of militarysite must in between 1 and 3 (including)
2374+ assert (size >= BaseImmovable::SMALL && size <= BaseImmovable::BIG);
2375+
2376+ if (size == BaseImmovable::SMALL) { // this function is intended for medium and bigger sites
2377+ return BuildingNecessity::kAllowed;
2378+ }
2379+
2380+ uint32_t const big_buildings_score
2381+ = msites_per_size[2].in_construction
2382+ + msites_per_size[2].finished
2383+ + msites_per_size[3].in_construction * 2
2384+ + msites_per_size[3].finished * 2;
2385+
2386+ const uint32_t msites_total = msites_built() + msites_in_constr();
2387+
2388+ // this is final proportion of big_buildings_score / msites_total
2389+ // two exeptions:
2390+ // if enemy nearby - can be higher
2391+ // for early game - must be lower
2392+ uint32_t limit = (msites_built() + msites_in_constr()) * 2 / 3;
2393+
2394+ // exemption first
2395+ if (militarysites.size() > 3 && vacant_mil_positions_ == 0 && msites_in_constr() == 0) {
2396+ return BuildingNecessity::kAllowed; // it seems the expansion is stuck so we allow big buildings
2397+ } else if (gametime > enemy_last_seen_ &&
2398+ gametime < enemy_last_seen_ + 30 * 60 * 1000 &&
2399+ mines_.size() > 2) { // if enemies were nearby in last 30 minutes
2400+ // we allow more big buidings
2401+ limit *= 2;
2402+ } else if (msites_total < ai_personality_early_militarysites) {
2403+ // for the beginning of the game (first 30 military sites)
2404+ limit = limit * msites_total / ai_personality_early_militarysites;
2405+ }
2406+
2407+ if (big_buildings_score + size - 1 > limit) {
2408+ return BuildingNecessity::kNotNeeded;
2409+ } else {
2410+ return BuildingNecessity::kAllowed;
2411 }
2412 }
2413
2414@@ -3838,17 +4141,6 @@
2415
2416 // just to be sure the value is reset
2417 taskDue[ScheduleTasks::kCheckMilitarysites] = gametime + 4 * 1000; // 4 seconds is really fine
2418- // even if there are no finished & attended military sites, probably there are ones just in
2419- // construction
2420- unstationed_milit_buildings_ = 0;
2421-
2422- for (std::list<MilitarySiteObserver>::iterator it = militarysites.begin();
2423- it != militarysites.end();
2424- ++it) {
2425- if (it->site->stationed_soldiers().size() == 0) {
2426- unstationed_milit_buildings_ += 1;
2427- }
2428- }
2429
2430 // Only useable, if defaultAI owns at least one militarysite
2431 if (militarysites.empty()) {
2432@@ -3899,7 +4191,7 @@
2433 score += (bf.area_military_capacity_ > 6);
2434 score += (bf.area_military_capacity_ > 22);
2435 score += (bf.area_military_presence_ > 4);
2436- score += (bf.military_loneliness_ < 180);
2437+ score += (bf.military_loneliness_ < (180 + ai_personality_military_loneliness_));
2438 score += (bf.military_stationed_ > 2);
2439 score -= size_penalty;
2440 score += ((bf.unowned_land_nearby_ + allyOwnedFields) < 10);
2441@@ -3965,7 +4257,7 @@
2442 /**
2443 * This function takes care about the unowned and opposing territory and
2444 * recalculates the priority for non-military buildings
2445- * The goal is to minimize losses when teritory is lost
2446+ * The goal is to minimize losses when territory is lost
2447 *
2448 * \arg bf = BuildableField to be checked
2449 * \arg prio = priority until now.
2450@@ -3979,85 +4271,26 @@
2451 return prio;
2452 }
2453
2454- // in unowned teritory, decreasing to 2/3
2455- if (bf.unowned_land_nearby_ > 15) {
2456- prio *= 2;
2457- prio /= 3;
2458- }
2459-
2460- // to preserve positive score
2461- if (prio == 0) {
2462- prio = 1;
2463- }
2464-
2465- // Further decrease the score if enemy nearby
2466+ if (bf.enemy_nearby_ || bf.near_border_) {
2467+ prio /= 2;
2468+ }
2469+
2470+ // if unowned territory nearby
2471+ prio -= bf.unowned_land_nearby_ / 4;
2472+
2473+ // further decrease the score if enemy nearby
2474 if (bf.enemy_nearby_) {
2475- prio /= 2;
2476- }
2477-
2478- return prio;
2479-}
2480-
2481-/**
2482- * calculates how much a productionsite of type \arg bo is needed inside it's
2483- * economy. \arg prio is initial value for this calculation
2484- *
2485- * \returns the calculated priority
2486- */
2487-int32_t DefaultAI::calculate_need_for_ps(BuildingObserver& bo, int32_t prio) {
2488- // some randomness to avoid that defaultAI is building always
2489- // the same (always == another game but same map with
2490- // defaultAI on same coords)
2491- prio += time(nullptr) % 3 - 1;
2492-
2493- // check if current economy can supply enough material for
2494- // production.
2495- for (uint32_t k = 0; k < bo.inputs_.size(); ++k) {
2496- prio += 2 * wares.at(bo.inputs_.at(k)).producers_;
2497- prio -= wares.at(bo.inputs_.at(k)).consumers_;
2498- }
2499-
2500- if (bo.inputs_.empty()) {
2501- prio += 4;
2502- }
2503-
2504- int32_t output_prio = 0;
2505-
2506- for (uint32_t k = 0; k < bo.outputs_.size(); ++k) {
2507- WareObserver& wo = wares.at(bo.outputs_.at(k));
2508-
2509- if (wo.consumers_ > 0) {
2510- output_prio += wo.preciousness_;
2511- output_prio += wo.consumers_ * 2;
2512- output_prio -= wo.producers_ * 2;
2513-
2514- if (bo.total_count() == 0) {
2515- output_prio += 10; // add a big bonus
2516- }
2517- }
2518- }
2519-
2520- if (bo.outputs_.size() > 1) {
2521- output_prio =
2522- static_cast<int32_t>(ceil(output_prio / sqrt(static_cast<double>(bo.outputs_.size()))));
2523- }
2524-
2525- prio += 2 * output_prio;
2526-
2527- // If building consumes some wares, multiply with current statistics of all
2528- // other buildings of this type to avoid constructing buildings where already
2529- // some are running on low resources.
2530- // Else at least add a part of the stats t the calculation.
2531- if (!bo.inputs_.empty()) {
2532- prio *= bo.current_stats_;
2533- prio /= 100;
2534- } else {
2535- prio = ((prio * bo.current_stats_) / 100) + (prio / 2);
2536- }
2537-
2538- return prio;
2539-}
2540-
2541+ prio -= 10;
2542+ }
2543+
2544+ // and if close (up to 2 fields away) from border
2545+ if (bf.near_border_) {
2546+ prio -= 10;
2547+ }
2548+
2549+ return prio;
2550+}
2551+// for buildable field, it considers effect of building of type bo on position coords
2552 void DefaultAI::consider_productionsite_influence(BuildableField& field,
2553 Coords coords,
2554 const BuildingObserver& bo) {
2555@@ -4073,6 +4306,14 @@
2556 for (size_t i = 0; i < bo.outputs_.size(); ++i) {
2557 ++field.producers_nearby_.at(bo.outputs_.at(i));
2558 }
2559+
2560+ if (bo.production_hint_ >= 0) {
2561+ ++field.supporters_nearby_.at(bo.production_hint_);
2562+ }
2563+
2564+ if (bo.plants_trees_ >= 0) {
2565+ ++field.rangers_nearby_;
2566+ }
2567 }
2568
2569 /// \returns the economy observer containing \arg economy
2570@@ -4163,10 +4404,14 @@
2571 // this is called when a mine reports "out of resources"
2572 void DefaultAI::out_of_resources_site(const ProductionSite& site) {
2573
2574+ const uint32_t gametime = game().get_gametime();
2575+
2576 // we must identify which mine matches the productionsite a note reffers to
2577 for (std::list<ProductionSiteObserver>::iterator i = mines_.begin(); i != mines_.end(); ++i)
2578 if (i->site == &site) {
2579- i->no_resources_count += 1;
2580+ if (i->no_resources_since_ > gametime) {
2581+ i->no_resources_since_ = gametime;
2582+ }
2583 break;
2584 }
2585 }
2586@@ -4190,9 +4435,9 @@
2587 player_number());
2588 }
2589
2590-// walk and search for teritorry controlled by other player
2591+// walk and search for territory controlled by other player
2592 // usually scanning radius is enough but sometimes we must walk to
2593-// verify that an enemy teritory is really accessible by land
2594+// verify that an enemy territory is really accessible by land
2595 bool DefaultAI::other_player_accessible(const uint32_t max_distance,
2596 int32_t* tested_fields,
2597 uint16_t* mineable_fields_count,
2598@@ -4227,9 +4472,9 @@
2599 continue;
2600 }
2601
2602- // sometimes we search for any owned teritory (f.e. when considering
2603+ // sometimes we search for any owned territory (f.e. when considering
2604 // a port location), but when testing (starting from) own military building
2605- // we must ignore own teritory, of course
2606+ // we must ignore own territory, of course
2607 if (f->get_owned_by() > 0) {
2608
2609 // if field is owned by anybody
2610@@ -4385,8 +4630,9 @@
2611 }
2612
2613 // decreasing colony_scan_area_
2614- if (colony_scan_area_ > 15 && gametime % 10 == 0) {
2615+ if (colony_scan_area_ > 10 && gametime % 10 == 0) {
2616 colony_scan_area_ -= 1;
2617+ player_->set_ai_data(colony_scan_area_, kColonyScan);
2618 }
2619 }
2620
2621@@ -4452,12 +4698,11 @@
2622 BuildingObserver& target_bo =
2623 get_building_observer(dynamic_cast<const ConstructionSite&>(b).building().name().c_str());
2624 ++target_bo.cnt_under_construction_;
2625- ++num_constructionsites_;
2626 if (target_bo.type == BuildingObserver::PRODUCTIONSITE) {
2627 ++num_prod_constructionsites;
2628 }
2629 if (target_bo.type == BuildingObserver::MILITARYSITE) {
2630- ++num_milit_constructionsites;
2631+ msites_per_size[target_bo.desc->get_size()].in_construction += 1;
2632 }
2633 if (target_bo.type == BuildingObserver::MINE) {
2634 mines_per_type[target_bo.mines_].in_construction += 1;
2635@@ -4480,10 +4725,12 @@
2636 productionsites.push_back(ProductionSiteObserver());
2637 productionsites.back().site = &dynamic_cast<ProductionSite&>(b);
2638 productionsites.back().bo = &bo;
2639+ productionsites.back().bo->new_building_overdue_ = 0;
2640 productionsites.back().built_time_ = game().get_gametime();
2641 productionsites.back().unoccupied_till_ = game().get_gametime();
2642 productionsites.back().stats_zero_ = 0;
2643- productionsites.back().no_resources_count = 0;
2644+ productionsites.back().no_resources_since_ = std::numeric_limits<uint32_t>::max();
2645+ productionsites.back().bo->unoccupied_count_ += 1;
2646 if (bo.is_shipyard_) {
2647 marineTaskQueue_.push_back(kStopShipyard);
2648 marineTaskQueue_.push_back(kReprioritize);
2649@@ -4499,6 +4746,8 @@
2650 mines_.back().site = &dynamic_cast<ProductionSite&>(b);
2651 mines_.back().bo = &bo;
2652 mines_.back().built_time_ = game().get_gametime();
2653+ mines_.back().no_resources_since_ = std::numeric_limits<uint32_t>::max();
2654+ mines_.back().bo->unoccupied_count_ += 1;
2655
2656 for (uint32_t i = 0; i < bo.outputs_.size(); ++i)
2657 ++wares.at(bo.outputs_.at(i)).producers_;
2658@@ -4514,6 +4763,8 @@
2659 militarysites.back().bo = &bo;
2660 militarysites.back().checks = bo.desc->get_size();
2661 militarysites.back().enemies_nearby_ = true;
2662+ msites_per_size[bo.desc->get_size()].finished += 1;
2663+ vacant_mil_positions_ += 2; // at least some indication that there are vacant positions
2664
2665 } else if (bo.type == BuildingObserver::TRAININGSITE) {
2666 ts_without_trainers_ += 1;
2667@@ -4526,6 +4777,7 @@
2668 if (bo.trainingsite_type_ == TrainingSiteType::kAdvanced) {
2669 ts_advanced_count_ += 1;
2670 }
2671+ vacant_mil_positions_ += 8; // at least some indication that there are vacant positions
2672
2673 } else if (bo.type == BuildingObserver::WAREHOUSE) {
2674 ++numof_warehouses_;
2675@@ -4538,7 +4790,7 @@
2676 // unblock nearby fields, might be used for other buildings...
2677 Map& map = game().map();
2678 MapRegion<Area<FCoords>> mr(
2679- map, Area<FCoords>(map.get_fcoords(warehousesites.back().site->get_position()), 4));
2680+ map, Area<FCoords>(map.get_fcoords(warehousesites.back().site->get_position()), 3));
2681 do {
2682 const int32_t hash = coords_hash(map.get_fcoords(*(mr.location().field)));
2683 if (port_reserved_coords.count(hash) > 0)
2684@@ -4558,12 +4810,11 @@
2685 BuildingObserver& target_bo =
2686 get_building_observer(dynamic_cast<const ConstructionSite&>(b).building().name().c_str());
2687 --target_bo.cnt_under_construction_;
2688- --num_constructionsites_;
2689 if (target_bo.type == BuildingObserver::PRODUCTIONSITE) {
2690 --num_prod_constructionsites;
2691 }
2692 if (target_bo.type == BuildingObserver::MILITARYSITE) {
2693- --num_milit_constructionsites;
2694+ msites_per_size[target_bo.desc->get_size()].in_construction -= 1;
2695 }
2696 if (target_bo.type == BuildingObserver::MINE) {
2697 mines_per_type[target_bo.mines_].in_construction -= 1;
2698@@ -4580,6 +4831,18 @@
2699 } else {
2700 --bo.cnt_built_;
2701
2702+ // we are not able to reliably identify if lost building is counted in
2703+ // unconnected or unoccupied count, but we must adjust the value to
2704+ // avoid inconsistency
2705+ const uint32_t cnt_built = bo.cnt_built_;
2706+ if (bo.unconnected_count_ > cnt_built) {
2707+ bo.unconnected_count_ = cnt_built;
2708+ }
2709+ if (bo.unoccupied_count_ > cnt_built) {
2710+ bo.unoccupied_count_ = cnt_built;
2711+ }
2712+
2713+
2714 if (bo.type == BuildingObserver::PRODUCTIONSITE) {
2715
2716 for (std::list<ProductionSiteObserver>::iterator i = productionsites.begin();
2717@@ -4597,6 +4860,7 @@
2718 for (uint32_t i = 0; i < bo.inputs_.size(); ++i) {
2719 --wares.at(bo.inputs_.at(i)).consumers_;
2720 }
2721+
2722 } else if (bo.type == BuildingObserver::MINE) {
2723 for (std::list<ProductionSiteObserver>::iterator i = mines_.begin(); i != mines_.end();
2724 ++i) {
2725@@ -4617,6 +4881,7 @@
2726 mines_per_type[bo.mines_].finished -= 1;
2727
2728 } else if (bo.type == BuildingObserver::MILITARYSITE) {
2729+ msites_per_size[bo.desc->get_size()].finished -= 1;
2730
2731 for (std::list<MilitarySiteObserver>::iterator i = militarysites.begin();
2732 i != militarysites.end();
2733@@ -4787,6 +5052,21 @@
2734 treshold_ratio = 120;
2735 }
2736
2737+ // let's say a 'campaign' is a series of attacks,
2738+ // if there is more then 3 minutes without attack after last
2739+ // attack, then a campaign is over.
2740+ // To start new campaign (=attack again), our strenth must exceed
2741+ // target values (calculated above) by some treshold =
2742+ // ai_personality_attack_margin_
2743+ // Once a new campaign started we will fight until
2744+ // we get below above treshold or there will be 3
2745+ // minutes gap since last attack
2746+ // note - AI is not aware of duration of attacks
2747+ // everywhere we consider time when an attack is ordered.
2748+ if (last_attack_time_ < gametime - kCampaignDuration) {
2749+ treshold_ratio += ai_personality_attack_margin_;
2750+ }
2751+
2752 uint32_t my_power = 0;
2753 try {
2754 my_power = genstats.at(pn - 1).miltary_strength.back();
2755@@ -5098,7 +5378,11 @@
2756 }
2757
2758 game().send_player_enemyflagaction(*flag, player_number(), attackers);
2759+
2760+ last_attack_time_ = gametime;
2761+ player_->set_ai_data(last_attack_time_, kLastAttack);
2762 last_attacked_player_ = flag->owner().player_number();
2763+ player_->set_ai_data(static_cast<int16_t>(last_attacked_player_), kAttacker);
2764
2765 return true;
2766 }
2767@@ -5160,6 +5444,40 @@
2768 return DueTask;
2769 }
2770
2771+// following two functions count mines of the same type (same output,
2772+// all levels)
2773+uint32_t DefaultAI::mines_in_constr() const {
2774+ uint32_t count = 0;
2775+ for (const std::pair<const int, MineTypesObserver> m : mines_per_type) {
2776+ count += m.second.in_construction;
2777+ }
2778+ return count;
2779+}
2780+uint32_t DefaultAI::mines_built() const{
2781+ uint32_t count = 0;
2782+ for (const std::pair<const int, MineTypesObserver> m : mines_per_type) {
2783+ count += m.second.finished;
2784+ }
2785+ return count;
2786+}
2787+
2788+// following two functions count militarysites of the same size
2789+uint32_t DefaultAI::msites_in_constr() const {
2790+ uint32_t count = 0;
2791+ for (const std::pair<const int, MilitarySiteSizeObserver> m : msites_per_size) {
2792+ count += m.second.in_construction;
2793+ }
2794+ return count;
2795+}
2796+uint32_t DefaultAI::msites_built() const{
2797+ uint32_t count = 0;
2798+ for (const std::pair<const int, MilitarySiteSizeObserver> m : msites_per_size) {
2799+ count += m.second.finished;
2800+ }
2801+ return count;
2802+}
2803+
2804+
2805 // This prints some basic statistics during a game to the command line -
2806 // missing materials and counts of different types of buildings.
2807 // The main purpose of this is when a game creator needs to finetune a map
2808@@ -5216,3 +5534,22 @@
2809 num_ports,
2810 summary.c_str());
2811 }
2812+
2813+template<typename T>
2814+ void DefaultAI::check_range(T value, T bottom_range, T upper_range, const char* value_name) {
2815+ if (value < bottom_range || value > upper_range) {
2816+ log(" %d: unexpected value for %s: %d\n",
2817+ player_number(),
2818+ value_name,
2819+ value);
2820+ }
2821+}
2822+
2823+template<typename T> void DefaultAI::check_range(T value, T upper_range, const char* value_name) {
2824+ if (value > upper_range) {
2825+ log(" %d: unexpected value for %s: %d\n",
2826+ player_number(),
2827+ value_name,
2828+ value);
2829+ }
2830+}
2831
2832=== modified file 'src/ai/defaultai.h'
2833--- src/ai/defaultai.h 2015-09-04 06:16:58 +0000
2834+++ src/ai/defaultai.h 2015-10-24 18:56:46 +0000
2835@@ -82,7 +82,7 @@
2836 };
2837
2838 enum class WalkSearch : uint8_t {kAnyPlayer, kOtherPlayers, kEnemy};
2839- enum class WoodPolicy : uint8_t {kDismantleRangers, kStopRangers, kStartRangers, kBuildRangers};
2840+ enum class WoodPolicy : uint8_t {kDismantleRangers, kStopRangers, kAllowRangers};
2841 enum class NewShip : uint8_t {kBuilt, kFoundOnLoad};
2842 enum class PerfEvaluation : uint8_t {kForConstruction, kForDismantle};
2843 enum class ScheduleTasks : uint8_t {
2844@@ -105,13 +105,6 @@
2845 kCountMilitaryVacant,
2846 kCheckEnemySites
2847 };
2848- enum class MilitaryStrategy : uint8_t {
2849- kNoNewMilitary,
2850- kDefenseOnly,
2851- kResourcesOrDefense,
2852- kExpansion,
2853- kPushExpansion
2854- };
2855 enum class Tribes : uint8_t {
2856 kNone,
2857 kBarbarians,
2858@@ -119,6 +112,7 @@
2859 kEmpire
2860 };
2861
2862+
2863 /// Implementation for Aggressive
2864 struct AggressiveImpl : public ComputerPlayer::Implementation {
2865 AggressiveImpl() {
2866@@ -169,7 +163,12 @@
2867
2868 void update_productionsite_stats(uint32_t);
2869
2870- void check_building_necessity(BuildingObserver& bo);
2871+ // for productionsites
2872+ Widelands::BuildingNecessity check_building_necessity
2873+ (BuildingObserver& bo, PerfEvaluation purpose, uint32_t);
2874+ // for militarysites (overloading the function)
2875+ Widelands::BuildingNecessity check_building_necessity
2876+ (uint8_t, uint32_t);
2877
2878 ScheduleTasks get_oldest_task(uint32_t);
2879
2880@@ -225,7 +224,6 @@
2881 const WalkSearch type);
2882
2883 int32_t recalc_with_border_range(const BuildableField&, int32_t);
2884- int32_t calculate_need_for_ps(BuildingObserver&, int32_t);
2885
2886 void
2887 consider_productionsite_influence(BuildableField&, Widelands::Coords, const BuildingObserver&);
2888@@ -243,16 +241,16 @@
2889 void expedition_management(ShipObserver&);
2890 void out_of_resources_site(const Widelands::ProductionSite&);
2891 void soldier_trained(const Widelands::TrainingSite&);
2892- bool is_productionsite_needed(int32_t outputs,
2893- int32_t performance,
2894- PerfEvaluation purpose);
2895
2896 bool check_supply(const BuildingObserver&);
2897
2898- // bool consider_attack(int32_t);
2899-
2900 void print_land_stats();
2901
2902+ //checks whether first value is in range, or lesser then...
2903+ template<typename T> void check_range(const T, const T, const T, const char *);
2904+ template<typename T> void check_range(const T, const T, const char *);
2905+
2906+
2907 private:
2908 // Variables of default AI
2909 uint8_t type_;
2910@@ -264,15 +262,18 @@
2911 Widelands::TribeDescr const* tribe_;
2912
2913 std::vector<BuildingObserver> buildings_;
2914- uint32_t num_constructionsites_;
2915- uint32_t num_milit_constructionsites;
2916 uint32_t num_prod_constructionsites;
2917 uint32_t num_ports;
2918
2919- uint16_t last_attacked_player_;
2920+ int16_t last_attacked_player_;
2921+ uint32_t last_attack_time_;
2922 // check ms in this interval - will auto-adjust
2923 uint32_t enemysites_check_delay_;
2924
2925+ // helping scores for building new military sites
2926+ int32_t target_military_score_;
2927+ int32_t least_military_score_;
2928+
2929 WoodPolicy wood_policy_;
2930
2931 std::list<Widelands::FCoords> unusable_fields;
2932@@ -294,6 +295,13 @@
2933 std::map<uint32_t, EnemySiteObserver> enemy_sites;
2934 // it will map mined material to observer
2935 std::map<int32_t, MineTypesObserver> mines_per_type;
2936+ // returns count of mines of the same type (output)
2937+ uint32_t mines_in_constr() const;
2938+ uint32_t mines_built() const;
2939+ std::map<int32_t, MilitarySiteSizeObserver> msites_per_size;
2940+ // returns count of militarysites
2941+ uint32_t msites_in_constr() const;
2942+ uint32_t msites_built() const;
2943
2944 std::vector<WareObserver> wares;
2945
2946@@ -315,8 +323,9 @@
2947 int32_t resource_necessity_water_;
2948 bool resource_necessity_water_needed_; // unless atlanteans
2949
2950- uint16_t unstationed_milit_buildings_; // counts empty military buildings (ones where no soldier
2951- // is belogning to)
2952+ // average count of trees around cutters
2953+ uint32_t trees_around_cutters_;
2954+
2955 uint16_t military_last_dismantle_;
2956 uint32_t military_last_build_; // sometimes expansions just stops, this is time of last military
2957 // building build
2958@@ -337,12 +346,15 @@
2959 // the purpose is to print out a warning that the game is pacing too fast
2960 int32_t scheduler_delay_counter_;
2961
2962+ int16_t ai_personality_military_loneliness_;
2963+ uint32_t ai_personality_attack_margin_;
2964+ int32_t ai_personality_wood_difference_;
2965+ uint32_t ai_productionsites_ratio_;
2966+ uint32_t ai_personality_early_militarysites;
2967+
2968 // this is a bunch of patterns that have to identify weapons and armors for input queues of trainingsites
2969 std::vector<std::string> const armors_and_weapons =
2970 {"ax", "lance", "armor", "helm", "lance", "trident", "tabard", "shield", "mask"};
2971- // some buildings can be upgraded even when they are only one
2972- // now only microbrewery get this special treatment
2973- const char* preferred_upgrade[1] = {"micro-brewery"};
2974
2975 enum {kReprioritize, kStopShipyard, kStapShipyard};
2976
2977
2978=== modified file 'src/game_io/game_player_info_packet.cc'
2979--- src/game_io/game_player_info_packet.cc 2014-10-12 07:35:42 +0000
2980+++ src/game_io/game_player_info_packet.cc 2015-10-24 18:56:46 +0000
2981@@ -30,7 +30,7 @@
2982
2983 namespace Widelands {
2984
2985-constexpr uint16_t kCurrentPacketVersion = 16;
2986+constexpr uint16_t kCurrentPacketVersion = 17;
2987
2988 void GamePlayerInfoPacket::read
2989 (FileSystem & fs, Game & game, MapObjectLoader *) {
2990@@ -68,6 +68,11 @@
2991 player.m_msites_defeated = fr.unsigned_32();
2992 player.m_civil_blds_lost = fr.unsigned_32();
2993 player.m_civil_blds_defeated = fr.unsigned_32();
2994+ for (int32_t ai_pos = 0; ai_pos < kAIDataSize; ++ai_pos) {
2995+ player.m_ai_data_int32[ai_pos] = fr.signed_32();
2996+ player.m_ai_data_uint32[ai_pos] = fr.unsigned_32();
2997+ player.m_ai_data_int16[ai_pos] = fr.unsigned_16();
2998+ }
2999 }
3000 }
3001 game.read_statistics(fr);
3002@@ -115,6 +120,11 @@
3003 fw.unsigned_32(plr->msites_defeated ());
3004 fw.unsigned_32(plr->civil_blds_lost ());
3005 fw.unsigned_32(plr->civil_blds_defeated());
3006+ for (int32_t ai_pos = 0; ai_pos < kAIDataSize; ++ai_pos) {
3007+ fw.signed_32(plr->m_ai_data_int32[ai_pos]);
3008+ fw.unsigned_32(plr->m_ai_data_uint32[ai_pos]);
3009+ fw.unsigned_16(plr->m_ai_data_int16[ai_pos]);
3010+ }
3011 } else
3012 fw.unsigned_8(0); // Player is NOT in game.
3013
3014
3015=== modified file 'src/logic/player.cc'
3016--- src/logic/player.cc 2015-10-04 18:30:05 +0000
3017+++ src/logic/player.cc 2015-10-24 18:56:46 +0000
3018@@ -166,7 +166,11 @@
3019 m_current_consumed_statistics(tribe_descr.get_nrwares ()),
3020 m_ware_productions (tribe_descr.get_nrwares ()),
3021 m_ware_consumptions (tribe_descr.get_nrwares ()),
3022- m_ware_stocks (tribe_descr.get_nrwares ())
3023+ m_ware_stocks (tribe_descr.get_nrwares ()),
3024+ m_ai_data_int32 (),
3025+ m_ai_data_uint32 (),
3026+ m_ai_data_int16 ()
3027+
3028 {
3029 set_name(name);
3030
3031@@ -1283,17 +1287,48 @@
3032 building_position.x, building_position.y);
3033 }
3034 }
3035+/**
3036+ * Functions used by AI to save/read AI data stored in Player class.
3037+ */
3038
3039-void Player::set_ai(const std::string & ai)
3040-{
3041+void Player::set_ai(const std::string & ai) {
3042 m_ai = ai;
3043 }
3044
3045-const std::string & Player::get_ai() const
3046-{
3047+const std::string & Player::get_ai() const {
3048 return m_ai;
3049 }
3050
3051+void Player::set_ai_data(int32_t value, uint32_t position) {
3052+ assert(position < kAIDataSize);
3053+ m_ai_data_int32[position] = value;
3054+}
3055+
3056+void Player::set_ai_data(uint32_t value, uint32_t position) {
3057+ assert(position < kAIDataSize);
3058+ m_ai_data_uint32[position] = value;
3059+}
3060+
3061+void Player::set_ai_data(int16_t value, uint32_t position) {
3062+ assert(position < kAIDataSize);
3063+ m_ai_data_int16[position] = value;
3064+}
3065+
3066+void Player::get_ai_data(int32_t * value, uint32_t position) {
3067+ assert(position < kAIDataSize);
3068+ *value = m_ai_data_int32[position];
3069+}
3070+
3071+void Player::get_ai_data(uint32_t * value, uint32_t position) {
3072+ assert(position < kAIDataSize);
3073+ *value = m_ai_data_uint32[position];
3074+}
3075+
3076+void Player::get_ai_data(int16_t * value, uint32_t position) {
3077+ assert(position < kAIDataSize);
3078+ *value = m_ai_data_int16[position];
3079+}
3080+
3081 /**
3082 * Read statistics data from a file.
3083 *
3084
3085=== modified file 'src/logic/player.h'
3086--- src/logic/player.h 2015-04-11 21:03:05 +0000
3087+++ src/logic/player.h 2015-10-24 18:56:46 +0000
3088@@ -33,6 +33,11 @@
3089 #include "logic/warehouse.h"
3090 #include "logic/widelands.h"
3091
3092+// there are three arrays to be used by AI
3093+// their size is defined here
3094+// (all are of the same size)
3095+constexpr int kAIDataSize = 6;
3096+
3097 class Node;
3098 namespace Widelands {
3099
3100@@ -517,6 +522,14 @@
3101 m_further_initializations .push_back(init);
3102 }
3103
3104+ // set of functions to be used by AI to save and read own data within this class
3105+ void set_ai_data(int32_t value, uint32_t position);
3106+ void set_ai_data(uint32_t value, uint32_t position);
3107+ void set_ai_data(int16_t value, uint32_t position);
3108+ void get_ai_data(int32_t * value, uint32_t position);
3109+ void get_ai_data(uint32_t * value, uint32_t position);
3110+ void get_ai_data(int16_t * value, uint32_t position);
3111+
3112 private:
3113 BuildingStatsVector* get_mutable_building_statistics(const BuildingIndex& i);
3114 void update_building_statistics(Building &, NoteImmovable::Ownership ownership);
3115@@ -586,6 +599,15 @@
3116 */
3117 std::vector< std::vector<uint32_t> > m_ware_stocks;
3118
3119+
3120+ /**
3121+ * AI internal data. These will be ignored by human player
3122+ * AI is managing the content of these arrays
3123+ */
3124+ int32_t m_ai_data_int32 [kAIDataSize];
3125+ uint32_t m_ai_data_uint32 [kAIDataSize];
3126+ int16_t m_ai_data_int16 [kAIDataSize];
3127+
3128 PlayerBuildingStats m_building_stats;
3129
3130 DISALLOW_COPY_AND_ASSIGN(Player);
3131
3132=== modified file 'tribes/atlanteans/blackroot_farm/conf'
3133--- tribes/atlanteans/blackroot_farm/conf 2015-07-31 07:26:49 +0000
3134+++ tribes/atlanteans/blackroot_farm/conf 2015-10-24 18:56:46 +0000
3135@@ -3,6 +3,7 @@
3136
3137 [aihints]
3138 prohibited_till=600
3139+forced_after=800
3140 space_consumer=true
3141
3142 [buildcost]
3143
3144=== modified file 'tribes/atlanteans/farm/conf'
3145--- tribes/atlanteans/farm/conf 2015-06-10 07:00:10 +0000
3146+++ tribes/atlanteans/farm/conf 2015-10-24 18:56:46 +0000
3147@@ -3,9 +3,9 @@
3148
3149 [aihints]
3150 space_consumer=true
3151-forced_after=180 # farm needs spidercloth to be build and spidercloth needs
3152+forced_after=400 # farm needs spidercloth to be build and spidercloth needs
3153 # corn for production -> farm should be build ASAP!
3154-prohibited_till=120
3155+prohibited_till=200
3156
3157 [buildcost]
3158 log=3
3159
3160=== modified file 'tribes/atlanteans/fish_breeders_house/conf'
3161--- tribes/atlanteans/fish_breeders_house/conf 2015-05-25 18:36:46 +0000
3162+++ tribes/atlanteans/fish_breeders_house/conf 2015-10-24 18:56:46 +0000
3163@@ -3,7 +3,8 @@
3164 [aihints]
3165 needs_water=true
3166 renews_map_resource=fish
3167-prohibited_till=300
3168+prohibited_till=700
3169+forced_after=900
3170
3171 [buildcost]
3172 log=1
3173
3174=== modified file 'tribes/atlanteans/foresters_house/conf'
3175--- tribes/atlanteans/foresters_house/conf 2014-08-02 19:55:23 +0000
3176+++ tribes/atlanteans/foresters_house/conf 2015-10-24 18:56:46 +0000
3177@@ -3,7 +3,7 @@
3178 [aihints]
3179 space_consumer=true
3180 renews_map_resource=log
3181-prohibited_till=50
3182+prohibited_till=240
3183
3184 [buildcost]
3185 log=1
3186
3187=== modified file 'tribes/atlanteans/hunters_house/conf'
3188--- tribes/atlanteans/hunters_house/conf 2015-07-26 10:59:28 +0000
3189+++ tribes/atlanteans/hunters_house/conf 2015-10-24 18:56:46 +0000
3190@@ -2,7 +2,7 @@
3191 output=meat
3192
3193 [aihints]
3194-prohibited_till=60
3195+prohibited_till=400
3196
3197 [buildcost]
3198 log=1
3199
3200=== modified file 'tribes/atlanteans/labyrinth/conf'
3201--- tribes/atlanteans/labyrinth/conf 2015-03-26 06:59:37 +0000
3202+++ tribes/atlanteans/labyrinth/conf 2015-10-24 18:56:46 +0000
3203@@ -100,3 +100,4 @@
3204
3205 [aihints]
3206 trainingsite_type=basic
3207+prohibited_till=900
3208
3209=== modified file 'tribes/atlanteans/planks/conf'
3210--- tribes/atlanteans/planks/conf 2014-07-28 14:04:36 +0000
3211+++ tribes/atlanteans/planks/conf 2015-10-24 18:56:46 +0000
3212@@ -1,7 +1,7 @@
3213 help=_Planks are an important building material of the Atlanteans. They are produced out of logs by the sawmill. The weapon smithy and the shipyard also use planks to produce the different tridents and mighty ships.
3214
3215 default_target_quantity=40
3216-preciousness=7
3217+preciousness=10
3218
3219 [idle]
3220 pics=idle.png
3221
3222=== modified file 'tribes/atlanteans/quarry/conf'
3223--- tribes/atlanteans/quarry/conf 2015-07-26 10:59:28 +0000
3224+++ tribes/atlanteans/quarry/conf 2015-10-24 18:56:46 +0000
3225@@ -2,7 +2,8 @@
3226 output=stone
3227
3228 [aihints]
3229-forced_after=60
3230+prohibited_till=240
3231+forced_after=240
3232 stoneproducer=true
3233
3234 [buildcost]
3235
3236=== modified file 'tribes/atlanteans/sawmill/conf'
3237--- tribes/atlanteans/sawmill/conf 2015-05-25 18:36:46 +0000
3238+++ tribes/atlanteans/sawmill/conf 2015-10-24 18:56:46 +0000
3239@@ -2,8 +2,8 @@
3240 output=planks
3241
3242 [aihints]
3243-forced_after=120
3244-prohibited_till=60
3245+forced_after=250
3246+prohibited_till=250
3247
3248 [buildcost]
3249 log=2
3250
3251=== modified file 'tribes/atlanteans/smokery/conf'
3252--- tribes/atlanteans/smokery/conf 2015-05-25 18:36:46 +0000
3253+++ tribes/atlanteans/smokery/conf 2015-10-24 18:56:46 +0000
3254@@ -3,7 +3,7 @@
3255 output=smoked_fish
3256
3257 [aihints]
3258-forced_after=900
3259+forced_after=800
3260 prohibited_till=180
3261
3262 [buildcost]
3263
3264=== modified file 'tribes/atlanteans/spiderfarm/conf'
3265--- tribes/atlanteans/spiderfarm/conf 2015-05-25 18:36:46 +0000
3266+++ tribes/atlanteans/spiderfarm/conf 2015-10-24 18:56:46 +0000
3267@@ -37,5 +37,5 @@
3268 hotspot=87 75
3269
3270 [aihints]
3271-forced_after=150
3272-prohibited_till=60
3273+forced_after=450
3274+prohibited_till=350
3275
3276=== modified file 'tribes/atlanteans/toolsmithy/conf'
3277--- tribes/atlanteans/toolsmithy/conf 2014-08-02 19:55:23 +0000
3278+++ tribes/atlanteans/toolsmithy/conf 2015-10-24 18:56:46 +0000
3279@@ -13,7 +13,7 @@
3280 output=shovel
3281
3282 [aihints]
3283-forced_after=900
3284+forced_after=500
3285 prohibited_till=450
3286
3287 [buildcost]
3288
3289=== modified file 'tribes/atlanteans/weaving-mill/conf'
3290--- tribes/atlanteans/weaving-mill/conf 2015-05-25 18:36:46 +0000
3291+++ tribes/atlanteans/weaving-mill/conf 2015-10-24 18:56:46 +0000
3292@@ -4,8 +4,8 @@
3293 output=golden_tabard
3294
3295 [aihints]
3296-forced_after=150
3297-prohibited_till=60
3298+forced_after=600
3299+prohibited_till=450
3300
3301 [buildcost]
3302 log=3
3303
3304=== modified file 'tribes/atlanteans/well/conf'
3305--- tribes/atlanteans/well/conf 2015-07-26 10:59:28 +0000
3306+++ tribes/atlanteans/well/conf 2015-10-24 18:56:46 +0000
3307@@ -3,8 +3,8 @@
3308
3309 [aihints]
3310 mines_water=true
3311-forced_after=600
3312-prohibited_till=300
3313+forced_after=800
3314+prohibited_till=450
3315
3316 [buildcost]
3317 log=2
3318
3319=== modified file 'tribes/atlanteans/woodcutters_house/conf'
3320--- tribes/atlanteans/woodcutters_house/conf 2015-07-26 10:59:28 +0000
3321+++ tribes/atlanteans/woodcutters_house/conf 2015-10-24 18:56:46 +0000
3322@@ -3,7 +3,8 @@
3323
3324 [aihints]
3325 logproducer=true
3326-forced_after=0
3327+forced_after=210
3328+prohibited_till=210
3329
3330 [buildcost]
3331 log=2
3332
3333=== modified file 'tribes/barbarians/bakery/conf'
3334--- tribes/barbarians/bakery/conf 2014-08-02 19:55:23 +0000
3335+++ tribes/barbarians/bakery/conf 2015-10-24 18:56:46 +0000
3336@@ -2,7 +2,7 @@
3337 output=pittabread
3338
3339 [aihints]
3340-prohibited_till=600
3341+prohibited_till=800
3342
3343 [buildcost]
3344 log=2
3345
3346=== modified file 'tribes/barbarians/farm/conf'
3347--- tribes/barbarians/farm/conf 2015-06-28 17:41:39 +0000
3348+++ tribes/barbarians/farm/conf 2015-10-24 18:56:46 +0000
3349@@ -3,7 +3,7 @@
3350
3351 [aihints]
3352 space_consumer=true
3353-forced_after=900
3354+forced_after=600
3355
3356 [buildcost]
3357 log=4
3358
3359=== modified file 'tribes/barbarians/hardener/conf'
3360--- tribes/barbarians/hardener/conf 2015-02-24 19:41:30 +0000
3361+++ tribes/barbarians/hardener/conf 2015-10-24 18:56:46 +0000
3362@@ -2,7 +2,8 @@
3363 output=blackwood
3364
3365 [aihints]
3366-forced_after=0
3367+forced_after=250
3368+prohibited_till=250
3369
3370 [buildcost]
3371 log=3
3372
3373=== modified file 'tribes/barbarians/hunters_hut/conf'
3374--- tribes/barbarians/hunters_hut/conf 2015-07-26 10:59:28 +0000
3375+++ tribes/barbarians/hunters_hut/conf 2015-10-24 18:56:46 +0000
3376@@ -2,7 +2,7 @@
3377 output=meat
3378
3379 [aihints]
3380-prohibited_till=300
3381+prohibited_till=500
3382
3383 [buildcost]
3384 log=4
3385
3386=== modified file 'tribes/barbarians/lime_kiln/conf'
3387--- tribes/barbarians/lime_kiln/conf 2014-07-27 19:32:24 +0000
3388+++ tribes/barbarians/lime_kiln/conf 2015-10-24 18:56:46 +0000
3389@@ -1,6 +1,9 @@
3390 size=medium
3391 output=grout
3392
3393+[aihints]
3394+forced_after=600
3395+
3396 [buildcost]
3397 log=4
3398 raw_stone=2
3399
3400=== modified file 'tribes/barbarians/lumberjacks_hut/conf'
3401--- tribes/barbarians/lumberjacks_hut/conf 2015-07-26 10:59:28 +0000
3402+++ tribes/barbarians/lumberjacks_hut/conf 2015-10-24 18:56:46 +0000
3403@@ -2,7 +2,8 @@
3404 output=log
3405
3406 [aihints]
3407-forced_after=0
3408+forced_after=180
3409+prohibited_till=180
3410 logproducer=true
3411
3412 [buildcost]
3413
3414=== modified file 'tribes/barbarians/metalworks/conf'
3415--- tribes/barbarians/metalworks/conf 2014-08-02 19:55:23 +0000
3416+++ tribes/barbarians/metalworks/conf 2015-10-24 18:56:46 +0000
3417@@ -12,8 +12,8 @@
3418 enhancement=axfactory
3419
3420 [aihints]
3421-forced_after=300
3422-prohibited_till=120
3423+forced_after=400
3424+prohibited_till=400
3425
3426 [buildcost]
3427 log=1
3428
3429=== modified file 'tribes/barbarians/quarry/conf'
3430--- tribes/barbarians/quarry/conf 2015-07-26 10:59:28 +0000
3431+++ tribes/barbarians/quarry/conf 2015-10-24 18:56:46 +0000
3432@@ -2,8 +2,8 @@
3433 output=raw_stone
3434
3435 [aihints]
3436-forced_after=0
3437 stoneproducer=true
3438+prohibited_till=240
3439
3440 [buildcost]
3441 log=4
3442
3443=== modified file 'tribes/barbarians/rangers_hut/conf'
3444--- tribes/barbarians/rangers_hut/conf 2015-02-13 18:07:55 +0000
3445+++ tribes/barbarians/rangers_hut/conf 2015-10-24 18:56:46 +0000
3446@@ -3,6 +3,7 @@
3447 [aihints]
3448 renews_map_resource=log
3449 space_consumer=true
3450+prohibited_till=200
3451
3452 [buildcost]
3453 log=4
3454
3455=== modified file 'tribes/barbarians/reed_yard/conf'
3456--- tribes/barbarians/reed_yard/conf 2015-06-09 08:45:20 +0000
3457+++ tribes/barbarians/reed_yard/conf 2015-10-24 18:56:46 +0000
3458@@ -3,7 +3,8 @@
3459
3460 [aihints]
3461 space_consumer=true
3462-forced_after=0
3463+forced_after=250
3464+prohibited_till=250
3465
3466 [buildcost]
3467 log=5
3468
3469=== modified file 'tribes/barbarians/smelting_works/conf'
3470--- tribes/barbarians/smelting_works/conf 2014-08-02 19:55:23 +0000
3471+++ tribes/barbarians/smelting_works/conf 2015-10-24 18:56:46 +0000
3472@@ -3,7 +3,7 @@
3473 output=gold
3474
3475 [aihints]
3476-prohibited_till=300
3477+prohibited_till=400
3478
3479 [buildcost]
3480 log=3
3481
3482=== modified file 'tribes/barbarians/trainingcamp/conf'
3483--- tribes/barbarians/trainingcamp/conf 2015-03-26 06:59:37 +0000
3484+++ tribes/barbarians/trainingcamp/conf 2015-10-24 18:56:46 +0000
3485@@ -37,6 +37,7 @@
3486
3487 [aihints]
3488 trainingsite_type=advanced
3489+prohibited_till=500
3490
3491 [soldier hp]
3492 min_level=0
3493
3494=== modified file 'tribes/barbarians/well/conf'
3495--- tribes/barbarians/well/conf 2015-07-26 10:59:28 +0000
3496+++ tribes/barbarians/well/conf 2015-10-24 18:56:46 +0000
3497@@ -3,7 +3,8 @@
3498
3499 [aihints]
3500 mines_water=true
3501-prohibited_till=600
3502+prohibited_till=800
3503+forced_after=800
3504
3505 [buildcost]
3506 log=4
3507
3508=== modified file 'tribes/empire/armorsmithy/conf'
3509--- tribes/empire/armorsmithy/conf 2014-08-02 19:55:23 +0000
3510+++ tribes/empire/armorsmithy/conf 2015-10-24 18:56:46 +0000
3511@@ -5,7 +5,8 @@
3512 output=plate_armor
3513
3514 [aihints]
3515-prohibited_till=900
3516+prohibited_till=700
3517+forced_after=900
3518
3519 [buildcost]
3520 log=2
3521
3522=== modified file 'tribes/empire/bakery/conf'
3523--- tribes/empire/bakery/conf 2014-08-02 19:55:23 +0000
3524+++ tribes/empire/bakery/conf 2015-10-24 18:56:46 +0000
3525@@ -3,6 +3,7 @@
3526
3527 [aihints]
3528 prohibited_till=600
3529+forced_after=700
3530
3531 [buildcost]
3532 log=2
3533
3534=== modified file 'tribes/empire/bread/conf'
3535--- tribes/empire/bread/conf 2015-05-17 11:01:13 +0000
3536+++ tribes/empire/bread/conf 2015-10-24 18:56:46 +0000
3537@@ -1,7 +1,7 @@
3538 help=_The bakers of the Empire make really tasty bread out of flour and water. It is used in taverns and inns to prepare rations and meals. Bread is also consumed at the training sites (arena, colosseum, training camp).
3539
3540 default_target_quantity=20
3541-preciousness=5
3542+preciousness=7
3543
3544 [idle]
3545 pics=idle.png
3546
3547=== modified file 'tribes/empire/flour/conf'
3548--- tribes/empire/flour/conf 2014-07-15 20:04:19 +0000
3549+++ tribes/empire/flour/conf 2015-10-24 18:56:46 +0000
3550@@ -1,7 +1,7 @@
3551 help=_Flour is produced by the mill out of wheat and is needed in the bakery to produce the tasty Empire bread.
3552
3553 default_target_quantity=20
3554-preciousness=5
3555+preciousness=9
3556
3557 [idle]
3558 pics=flour_idle.png
3559
3560=== modified file 'tribes/empire/foresters_house/conf'
3561--- tribes/empire/foresters_house/conf 2014-07-29 09:27:08 +0000
3562+++ tribes/empire/foresters_house/conf 2015-10-24 18:56:46 +0000
3563@@ -3,6 +3,7 @@
3564 [aihints]
3565 space_consumer=true
3566 renews_map_resource=log
3567+prohibited_till=200
3568
3569 [buildcost]
3570 log=1
3571
3572=== modified file 'tribes/empire/lumberjacks_house/conf'
3573--- tribes/empire/lumberjacks_house/conf 2015-07-26 10:59:28 +0000
3574+++ tribes/empire/lumberjacks_house/conf 2015-10-24 18:56:46 +0000
3575@@ -2,7 +2,8 @@
3576 output=log
3577
3578 [aihints]
3579-forced_after=0
3580+forced_after=180
3581+prohibited_till=180
3582 logproducer=true
3583
3584 [buildcost]
3585
3586=== modified file 'tribes/empire/piggery/conf'
3587--- tribes/empire/piggery/conf 2015-03-18 20:46:03 +0000
3588+++ tribes/empire/piggery/conf 2015-10-24 18:56:46 +0000
3589@@ -2,7 +2,7 @@
3590 output=meat
3591
3592 [aihints]
3593-forced_after=9000
3594+forced_after=1800
3595
3596 [buildcost]
3597 log=2
3598
3599=== modified file 'tribes/empire/quarry/conf'
3600--- tribes/empire/quarry/conf 2015-07-26 10:59:28 +0000
3601+++ tribes/empire/quarry/conf 2015-10-24 18:56:46 +0000
3602@@ -3,8 +3,9 @@
3603 output=marble
3604
3605 [aihints]
3606-forced_after=0
3607 stoneproducer=true
3608+forced_after=240
3609+prohibited_till=240
3610
3611 [buildcost]
3612 log=2
3613
3614=== modified file 'tribes/empire/sawmill/conf'
3615--- tribes/empire/sawmill/conf 2014-08-02 19:55:23 +0000
3616+++ tribes/empire/sawmill/conf 2015-10-24 18:56:46 +0000
3617@@ -2,8 +2,8 @@
3618 output=wood
3619
3620 [aihints]
3621-forced_after=60
3622-prohibited_till=60
3623+forced_after=250
3624+prohibited_till=250
3625
3626 [buildcost]
3627 log=2
3628
3629=== modified file 'tribes/empire/stonemasons_house/conf'
3630--- tribes/empire/stonemasons_house/conf 2014-08-02 19:55:23 +0000
3631+++ tribes/empire/stonemasons_house/conf 2015-10-24 18:56:46 +0000
3632@@ -2,8 +2,8 @@
3633 output=marblecolumn
3634
3635 [aihints]
3636-forced_after=300
3637-prohibited_till=120
3638+forced_after=400
3639+prohibited_till=400
3640
3641 [buildcost]
3642 log=1
3643
3644=== modified file 'tribes/empire/toolsmithy/conf'
3645--- tribes/empire/toolsmithy/conf 2014-08-02 19:55:23 +0000
3646+++ tribes/empire/toolsmithy/conf 2015-10-24 18:56:46 +0000
3647@@ -13,8 +13,8 @@
3648 output=saw
3649
3650 [aihints]
3651-forced_after=1200
3652-prohibited_till=120
3653+forced_after=400
3654+prohibited_till=400
3655
3656 [buildcost]
3657 log=1
3658
3659=== modified file 'tribes/empire/vineyard/conf'
3660--- tribes/empire/vineyard/conf 2015-07-31 07:26:49 +0000
3661+++ tribes/empire/vineyard/conf 2015-10-24 18:56:46 +0000
3662@@ -3,7 +3,7 @@
3663
3664 [aihints]
3665 space_consumer=true
3666-forced_after=120
3667+forced_after=300
3668
3669 [buildcost]
3670 wood=2
3671
3672=== modified file 'tribes/empire/well/conf'
3673--- tribes/empire/well/conf 2015-07-26 10:59:28 +0000
3674+++ tribes/empire/well/conf 2015-10-24 18:56:46 +0000
3675@@ -3,7 +3,8 @@
3676
3677 [aihints]
3678 mines_water=true
3679-prohibited_till=60
3680+prohibited_till=800
3681+forced_after=800
3682
3683 [buildcost]
3684 log=2
3685
3686=== modified file 'tribes/empire/winery/conf'
3687--- tribes/empire/winery/conf 2014-08-02 19:55:23 +0000
3688+++ tribes/empire/winery/conf 2015-10-24 18:56:46 +0000
3689@@ -2,8 +2,8 @@
3690 output=wine
3691
3692 [aihints]
3693-forced_after=900
3694-prohibited_till=60
3695+forced_after=600
3696+prohibited_till=600
3697
3698 [buildcost]
3699 wood=1
3700
3701=== modified file 'tribes/empire/wood/conf'
3702--- tribes/empire/wood/conf 2014-07-28 14:04:36 +0000
3703+++ tribes/empire/wood/conf 2015-10-24 18:56:46 +0000
3704@@ -1,7 +1,7 @@
3705 help=_Wood is a basic building material of the Empire. It is also used by the weapon smithy.
3706
3707 default_target_quantity=40
3708-preciousness=7
3709+preciousness=10
3710
3711 [idle]
3712 pics=idle.png

Subscribers

People subscribed via source and target branches

to status/vote changes: