Merge lp:~widelands-dev/widelands/ai_persistent_data into lp:widelands
- ai_persistent_data
- Merge into trunk
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 | ||||||||
Related bugs: |
|
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
GunChleoc | Approve | ||
TiborB | Needs Resubmitting | ||
Review via email: mp+271853@code.launchpad.net |
Commit message
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 :)
TiborB (tiborb95) wrote : | # |
TiborB (tiborb95) wrote : | # |
should be again ready for review
GunChleoc (gunchleoc) wrote : | # |
I have added 2 replays to https:/
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...
TiborB (tiborb95) wrote : | # |
But you replays are not good, both are too short and one even fails to load altogether
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.
GunChleoc (gunchleoc) wrote : | # |
I can't say anything about how good the heuristics are, but I have added some code style comments / ideas.
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.
GunChleoc (gunchleoc) wrote : | # |
Added comments to your comments :)
TiborB (tiborb95) wrote : | # |
my turn now, see my comments to your comments...
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.
TiborB (tiborb95) wrote : | # |
@GunChleoc - I incorporated you comments (most of them). Also see one comment in the diff.
TiborB (tiborb95) wrote : | # |
Oh, I forget about that packet - I will look at it...
TiborB (tiborb95) wrote : | # |
packet increased, see question in diff.
GunChleoc (gunchleoc) wrote : | # |
Increase it to 17 please.
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?
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/
#2 0xb784c9c3 in __GI_abort () at abort.c:89
#3 0xb7a77a25 in __gnu_cxx:
#4 0xb7a75733 in ?? () from /usr/lib/
#5 0xb7a757ad in std::terminate() () from /usr/lib/
#6 0xb7a76514 in __cxa_pure_virtual () from /usr/lib/
#7 0x08c12013 in ChatOverlay:
#8 0x08c11fcd in ChatOverlay:
#9 0x08a77d7e in InteractiveBase
#10 0x08a7bf01 in std::_Function_
at /usr/include/
#11 0x0885b94b in std::function<void (GraphicResolut
at /usr/include/
#12 0x0885b753 in Notifications:
message=...) at /var/widelands/
#13 0x0885affb in Notifications:
#14 0x0885a48d in Graphic:
#15 0x0885a3d5 in Graphic:
#16 0x087be6fb in WLApplication:
#17 0x087c113e in WLApplication:
#18 0x087bd8b4 in WLApplication::run (this=0x9181f38) at /var/widelands/
#19 0x087bbfd5 in main (argc=1, argv=0xbffffa24) at /var/widelands/
Is it related to notifications? Is it specific to this branch? I dont know...
TiborB (tiborb95) wrote : | # |
sorry, I wanted to say chat, not notifications
GunChleoc (gunchleoc) wrote : | # |
I am getting this error on trunk as well.
TiborB (tiborb95) wrote : | # |
So it has nothing to do with savegame (in)compatibility probably...
GunChleoc (gunchleoc) wrote : | # |
My guess is that it does - but not caused by this branch. So, this can go in now :)
Preview Diff
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 |
Please hold on, I will do some changes and resubmit...