Merge lp:~mxsscott/widelands/carli2-ai-improvements into lp:widelands

Proposed by Mark Scott
Status: Rejected
Rejected by: SirVer
Proposed branch: lp:~mxsscott/widelands/carli2-ai-improvements
Merge into: lp:widelands
Diff against target: 752 lines (+358/-242)
5 files modified
src/ai/ai_help_structs.h (+1/-0)
src/ai/defaultai.cc (+351/-242)
src/ai/defaultai.h (+4/-0)
src/logic/militarysite.h (+1/-0)
tribes/barbarians/fernery/conf (+1/-0)
To merge this branch: bzr merge lp:~mxsscott/widelands/carli2-ai-improvements
Reviewer Review Type Date Requested Status
SirVer Needs Fixing
Review via email: mp+142009@code.launchpad.net

Description of the change

(Branch author is carli2: https://code.launchpad.net/~s3734770 - having bzr problems)

 - Add "demand" to wares
 - missing input wares count as demand
 - missing soldiers add demand to weapons
 - a depth pass filter is applied to demand in order to get stable values
 - enhancements are now priorized correctly

gains:
 - all three tribes manage to recruit soldiers
 - the AI is able to finish its enemy after 90 minutes
 - great improvement for AIs economy

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

see http://wl.widelands.org/forum/topic/648/?page=3#post-8562. More comments and review welcome.

review: Needs Fixing
Revision history for this message
SirVer (sirver) wrote :

Setting to rejected because there was no followup - feel free to reopen or discuss more.

Unmerged revisions

6478. By carli <https://launchpad.net/~s3734770>

AI improvements

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'src/ai/ai_help_structs.h'
2--- src/ai/ai_help_structs.h 2012-09-21 21:36:07 +0000
3+++ src/ai/ai_help_structs.h 2013-01-05 13:44:24 +0000
4@@ -274,6 +274,7 @@
5 uint8_t producers;
6 uint8_t consumers;
7 uint8_t preciousness;
8+ float demand;
9 };
10
11 #endif
12
13=== modified file 'src/ai/defaultai.cc'
14--- src/ai/defaultai.cc 2012-09-21 21:36:07 +0000
15+++ src/ai/defaultai.cc 2013-01-05 13:44:24 +0000
16@@ -30,6 +30,7 @@
17 #include "economy/economy.h"
18 #include "economy/flag.h"
19 #include "economy/road.h"
20+#include "economy/wares_queue.h"
21 #include "logic/findimmovable.h"
22 #include "logic/findnode.h"
23 #include "log.h"
24@@ -75,7 +76,8 @@
25 next_attack_consideration_due(300000),
26 inhibit_road_building (0),
27 time_of_last_construction (0),
28- numof_warehouses (0)
29+ numof_warehouses (0),
30+ military_demand (0.0)
31 {}
32
33 DefaultAI::~DefaultAI()
34@@ -136,6 +138,9 @@
35 // handled by the AI itself.
36 update_all_not_buildable_fields();
37
38+ // now update the statistics of what we need (wares and military power)
39+ update_demand();
40+
41 // IF defaultAI is AGGRESSIVE - we definitely should consider to attack as
42 // often as possible.
43 if (type == AGGRESSIVE)
44@@ -234,6 +239,7 @@
45 wares.at(i).producers = 0;
46 wares.at(i).consumers = 0;
47 wares.at(i).preciousness = tribe->get_ware_descr(i)->preciousness();
48+ wares.at(i).demand = 0;
49 }
50
51 // collect information about the different buildings our tribe can construct
52@@ -472,6 +478,85 @@
53 }
54 }
55
56+/***
57+ * updates all needs of the economy
58+ */
59+void DefaultAI::update_demand()
60+{
61+ // military buildings need soldiers: count them!
62+ for
63+ (std::list<MilitarySiteObserver>::iterator i =
64+ militarysites.begin();
65+ i != militarysites.end();
66+ ++i)
67+ {
68+ military_demand += i->site->missingSoldiers();
69+ }
70+ military_demand += 1; // some extra points such that we always get new soldiers
71+ military_demand *= 0.99;
72+ military_demand = std::max(military_demand, (type + 2) * (float) 2000.0); // then limit it to some degree.
73+ // enable logging for debug purpose
74+ //printf("mil = %f\n", military_demand);
75+
76+ // now we know how much military we need, so we
77+ // need the wares to build the soldiers
78+ Ware_Index const nr_workers = tribe->get_nrworkers();
79+ for (Ware_Index i = Ware_Index::First(); i < nr_workers; ++i) {
80+ // Find all build costs for soldiers
81+ // is it a soldier?
82+ if(tribe->get_worker_descr(i)->get_worker_type() == Worker_Descr::SOLDIER) {
83+ Worker_Descr::Buildcost::const_iterator end = tribe->get_worker_descr(i)->buildcost().end();
84+ for(Worker_Descr::Buildcost::const_iterator it = tribe->get_worker_descr(i)->buildcost().begin(); it != end; ++it) {
85+ if(tribe->ware_index(it->first))
86+ wares.at(tribe->ware_index(it->first)).demand += it->second * military_demand / 100.0; // Add soldier-need priority
87+ }
88+ }
89+ }
90+
91+
92+ // production buildings need inputs
93+ std::list<ProductionSiteObserver>::const_iterator i =
94+ productionsites.begin();
95+ while(1)
96+ {
97+ // iterate through both: production buildings and mines
98+ if(i == productionsites.end())
99+ i = mines.begin();
100+ if(i == mines.end())
101+ break;
102+ // count all empty slots
103+ for
104+ (ProductionSite::Input_Queues::const_iterator j =
105+ i->site->warequeues().begin();
106+ j != i->site->warequeues().end();
107+ j++)
108+ {
109+ if((*j)->get_filled() == 0)
110+ // count queues that are empty
111+ wares.at((*j)->get_ware()).demand += 1;
112+ }
113+ i++;
114+ }
115+
116+ /* TODO: Iterate over all construction sites and add material need
117+ // Remark: construction materials are also handled by other code, but this
118+ // code could do it more scalable for big empires
119+
120+ Buildcost::const_iterator end = bld.buildcost().end();
121+ for(Buildcost::const_iterator it = bld.buildcost().begin(); it != end; ++it) {
122+ wares.at(it->first).demand += it->second; // Add build-need priority
123+ }*/
124+
125+ // now decrease the total ammount a bit
126+ Ware_Index nr_wares = tribe->get_nrwares();
127+ for (Ware_Index i = Ware_Index::First(); i < nr_wares; ++i)
128+ {
129+ wares.at(i).demand *= 0.99;
130+ // enable logging for debug purpose
131+ //printf("ware %s: %f\n", tribe->get_ware_descr(i)->name().c_str(), wares.at(i).demand);
132+ }
133+}
134+
135
136 /// Updates one buildable field
137 void DefaultAI::update_buildable_field
138@@ -860,245 +945,7 @@
139 if (bo.desc->get_size() > maxsize)
140 continue;
141
142- int32_t prio = 0;
143-
144- if (bo.type == BuildingObserver::PRODUCTIONSITE) {
145- // Don't build another building of this type, if there is already
146- // one that is unoccupied at the moment
147- if (bo.unoccupied)
148- continue;
149- if (bo.need_trees) {
150- // Priority of woodcutters depend on the number of near trees
151- prio += bf->trees_nearby * 3;
152- prio /= 3 * (1 + bf->producers_nearby.at(bo.outputs.at(0)));
153-
154- // TODO improve this - it's still useless to place lumberjack huts randomly
155- /*if (prio <= 0) // no, sometimes we need wood without having a forest
156- continue;*/
157-
158- // Check if the produced wares are needed
159- Ware_Index wt(static_cast<size_t>(bo.outputs.at(0)));
160- container_iterate(std::list<EconomyObserver *>, economies, l) {
161- // Don't check if the economy has no warehouse.
162- if ((*l.current)->economy.warehouses().empty())
163- continue;
164- if ((*l.current)->economy.needs_ware(wt))
165- prio += 1 + wares.at(bo.outputs.at(0)).preciousness;
166- }
167-
168- if (bo.total_count() < 2) {
169- prio *= 6; // big bonus for the basics
170- if (bo.total_count() == 0)
171- prio *= 4; // even more for the absolute basics
172- }
173- } else if (bo.need_stones) {
174- // Priority of quarries depend on the number of near stones
175- prio += bf->stones_nearby * 3;
176- prio /= 3 * (1 + bf->producers_nearby.at(bo.outputs.at(0)));
177- if (bo.total_count() < 2) {
178- prio *= 6; // big bonus for the basics
179- if (bo.total_count() == 0)
180- prio *= 4; // even more for the absolute basics
181- }
182- } else if (bo.production_hint >= 0) {
183- // production hint (f.e. associate forester with trunks)
184-
185- // Calculate the need for this building
186- int16_t inout = wares.at(bo.production_hint).consumers;
187- if
188- (tribe->safe_ware_index("trunk").value()
189- ==
190- bo.production_hint)
191- inout += total_constructionsites / 4;
192- inout -= wares.at(bo.production_hint).producers;
193- if (inout < 1)
194- inout = 1;
195- // the ware they're refreshing
196- Ware_Index wt(static_cast<size_t>(bo.production_hint));
197- container_iterate(std::list<EconomyObserver *>, economies, l) {
198- // Don't check if the economy has no warehouse.
199- if ((*l.current)->economy.warehouses().empty())
200- continue;
201- if ((*l.current)->economy.needs_ware(wt)) {
202- prio += wares.at(bo.production_hint).preciousness * inout * 2;
203- break;
204- }
205- }
206-
207- // Do not build too many of these buildings, but still care
208- // to build at least two.
209- // And add bonus near buildings outputting production_hint ware.
210- prio += (5 * bf->producers_nearby.at(bo.production_hint)) / 2;
211- prio -= bo.total_count() * 2;
212- prio /= bo.total_count() + 1;
213- prio += (bf->producers_nearby.at(bo.production_hint) - 1) * 5;
214- if (bo.total_count() > 2)
215- prio -= bo.total_count();
216- else {
217- prio += wares.at(bo.production_hint).preciousness;
218- prio *= 3;
219- }
220- if (prio < 0)
221- continue;
222- } else if (bo.recruitment) {
223- // "recruitment centeres" like the donkey farm should be build up
224- // as soon as a basic infrastructure was completed.
225- // and of course the defaultAI should think of further
226- // constructions of that type later in game.
227- prio -= 12; // start calculation with an offset
228- prio += productionsites.size() + mines.size();
229- prio -= (bo.total_count()) * 40;
230- prio *= 2;
231-
232- // take care about borders and enemies
233- prio = recalc_with_border_range(*bf, prio);
234- } else { // "normal" productionsites
235-
236- // ToDo: prefer soldier producing things
237- // Ware_Index const soldier_index = tribe().worker_index("soldier");
238-
239- if (bo.is_basic && (bo.total_count() == 0))
240- prio += 100; // for very important buildings
241-
242- // Check if the produced wares are needed
243- container_iterate(std::list<EconomyObserver *>, economies, l) {
244- // Don't check if the economy has no warehouse.
245- if ((*l.current)->economy.warehouses().empty())
246- continue;
247- for (uint32_t m = 0; m < bo.outputs.size(); ++m) {
248- Ware_Index wt(static_cast<size_t>(bo.outputs.at(m)));
249-
250- // if we have too much of it (avoids mass storage)
251- if
252- ((*l.current)->economy.stock_ware(wt) > 6 *
253- (*l.current)->economy.ware_target_quantity(wt).permanent)
254- prio -= 20;
255-
256- // if the economy needs this ware
257- if ((*l.current)->economy.needs_ware(wt)) {
258- prio += 1 + wares.at(bo.outputs.at(m)).preciousness;
259- if (bo.total_count() == 0)
260- // big bonus, this site might be elemental
261- prio += 3 * wares.at(bo.outputs.at(m)).preciousness;
262- }
263-
264- // we can enhance this building. build more
265- // maybe the enhancement can produce needed ware
266- if (bo.desc->enhancements().size() > 0) {
267- // this code builds more metalworks
268- if (bo.total_count() == 0)
269- prio += 2;
270- if (bo.total_count() == 1)
271- prio += 8;
272- }
273- }
274- for (uint32_t m = 0; m < bo.inputs.size(); ++m) {
275- Ware_Index wt(static_cast<size_t>(bo.inputs.at(m)));
276-
277- // if the economies don't need it: "waste" it
278- if (!(*l.current)->economy.needs_ware(wt)) {
279- if (bo.total_count() == 0 && bo.prod_build_material)
280- // big bonus, this site might be elemental
281- prio += 3 * wares.at(bo.inputs.at(m)).preciousness;
282- }
283- }
284- }
285-
286- // If the produced wares are needed
287- if (prio > 0) {
288- int32_t inout_prio = 0;
289- for (size_t k = 0; k < bo.inputs.size(); ++k) {
290- inout_prio += bf->producers_nearby.at(bo.inputs.at(k));
291- inout_prio -= bf->consumers_nearby.at(bo.inputs.at(k)) / 2;
292- }
293- for (size_t k = 0; k < bo.outputs.size(); ++k)
294- inout_prio += bf->consumers_nearby.at(bo.outputs.at(k));
295- prio += 2 * inout_prio;
296- prio = calculate_need_for_ps(bo, prio);
297- } else
298- continue;
299-
300- // take care about borders and enemies
301- prio = recalc_with_border_range(*bf, prio);
302-
303- // do not construct more than one building,
304- // if supply line is already broken.
305- if (!check_supply(bo) && bo.total_count() > 0)
306- prio -= 12;
307-
308- }
309- } else if (bo.type == BuildingObserver::MILITARYSITE) {
310- if (!bf->unowned_land_nearby)
311- continue;
312- prio = bf->unowned_land_nearby * (1 + type);
313- prio -= bf->military_influence * (5 - type);
314- // set to at least 1
315- prio = prio > 0 ? prio : 1;
316- prio *= expand_factor;
317- prio /= 2;
318-
319- if (bf->enemy_nearby)
320- prio *= 2;
321- else
322- prio -= bf->military_influence * 2;
323-
324- if (bf->avoid_military)
325- prio /= 5;
326-
327- prio -= militarysites.size() - productionsites.size() / (3 - type);
328-
329- } else if (bo.type == BuildingObserver::WAREHOUSE) {
330- // Build one warehouse for ~every 35 productionsites and mines.
331- // Militarysites are slightly important as well, to have a bigger
332- // chance for a warehouses (containing waiting soldiers or wares
333- // needed for soldier training) near the frontier.
334- prio += productionsites.size() + mines.size();
335- prio += militarysites.size() / 3;
336- prio -= (bo.cnt_under_construction + numof_warehouses) * 35;
337- prio *= 2;
338-
339- // take care about borders and enemies
340- prio = recalc_with_border_range(*bf, prio);
341-
342- } else if (bo.type == BuildingObserver::TRAININGSITE) {
343- // Start building trainingsites when there are already more than 50
344- // other buildings. That should be enough for a working economy.
345- // On the other hand only build more trainingsites of the same
346- // type if the economy is really big.
347- prio += productionsites.size() + militarysites.size();
348- prio += mines.size();
349- prio += type * 10; // +0 / +10 / +20 for DEFF/NORM/AGGR
350- prio = prio / (bo.total_count() + 1);
351- prio -= (bo.total_count() + 1) * 70;
352-
353- // take care about borders and enemies
354- prio = recalc_with_border_range(*bf, prio);
355- }
356-
357- // avoid to have too many construction sites
358- // but still enable the player to build up basic productionsites
359- if
360- (bo.type != BuildingObserver::PRODUCTIONSITE ||
361- !bo.is_basic || bo.total_count() > 0)
362- prio /=
363- 1 + bo.cnt_under_construction * (bo.cnt_under_construction + 1);
364-
365- // add big penalty if water is needed, but is not near
366- if (bo.need_water) {
367- if (bf->water_nearby < 3)
368- continue;
369- int effect = bf->water_nearby - 8;
370- prio +=
371- effect > 0 ?
372- static_cast<int>(sqrt(static_cast<double>(effect))) : effect;
373- // if same producers are nearby, then give some penalty
374- for (size_t k = 0; k < bo.outputs.size(); ++k)
375- if (bf->producers_nearby.at(bo.outputs.at(k)) > 0)
376- prio -= 3;
377- }
378-
379- // think of space consuming buildings nearby like farms or vineyards
380- prio /= 1 + bf->space_consumers_nearby;
381+ int32_t prio = calculate_building_prio(bo, bf, expand_factor);
382
383 // Stop here, if priority is 0 or less.
384 if (prio <= 0)
385@@ -1199,6 +1046,7 @@
386 uint32_t ioprio = 0;
387 for (uint32_t m = 0; m < bo.outputs.size(); ++m) {
388 ioprio += 5 * wares.at(bo.outputs.at(m)).preciousness;
389+ ioprio += round(wares.at(bo.outputs.at(m)).demand / 100.0);
390 }
391
392 // tribes that have enhanceable mines should build more mines
393@@ -1214,7 +1062,7 @@
394 // multiply with current statistics of all other buildings of this
395 // type to avoid constructing buildings where already some are running
396 // on low resources.
397- prio *= 5 + bo.current_stats;
398+ prio *= 45 + bo.current_stats;
399 prio /= 100;
400
401 if (onlymissing) // mines aren't *that* important
402@@ -1252,6 +1100,262 @@
403 return true;
404 }
405
406+int32_t DefaultAI::calculate_building_prio(BuildingObserver & bo, BuildableField * const bf, uint32_t expand_factor)
407+{
408+ int32_t prio = 0;
409+
410+ if (bo.type == BuildingObserver::PRODUCTIONSITE) {
411+ // Don't build another building of this type, if there is already
412+ // one that is unoccupied at the moment
413+ if (bo.unoccupied)
414+ return -1;
415+ if (bo.need_trees) {
416+ // Priority of woodcutters depend on the number of near trees
417+ prio += bf->trees_nearby * 3;
418+ prio /= 3 * (1 + bf->producers_nearby.at(bo.outputs.at(0)));
419+
420+ // TODO improve this - it's still useless to place lumberjack huts randomly
421+ /*if (prio <= 0) // no, sometimes we need wood without having a forest
422+ return -1;*/
423+
424+ // Check if the produced wares are needed
425+ Ware_Index wt(static_cast<size_t>(bo.outputs.at(0)));
426+ container_iterate(std::list<EconomyObserver *>, economies, l) {
427+ // Don't check if the economy has no warehouse.
428+ if ((*l.current)->economy.warehouses().empty())
429+ continue;
430+ if ((*l.current)->economy.needs_ware(wt))
431+ prio += 1 + wares.at(bo.outputs.at(0)).preciousness;
432+ }
433+
434+ if (bo.total_count() < 2) {
435+ prio *= 6; // big bonus for the basics
436+ if (bo.total_count() == 0)
437+ prio *= 4; // even more for the absolute basics
438+ }
439+ } else if (bo.need_stones) {
440+ // Priority of quarries depend on the number of near stones
441+ prio += bf->stones_nearby * 3;
442+ prio /= 3 * (1 + bf->producers_nearby.at(bo.outputs.at(0)));
443+ if (bo.total_count() < 2) {
444+ prio *= 6; // big bonus for the basics
445+ if (bo.total_count() == 0)
446+ prio *= 4; // even more for the absolute basics
447+ }
448+ } else if (bo.production_hint >= 0) {
449+ // production hint (f.e. associate forester with trunks)
450+
451+ // Calculate the need for this building
452+ int16_t inout = wares.at(bo.production_hint).consumers;
453+ if
454+ (tribe->safe_ware_index("trunk").value()
455+ ==
456+ bo.production_hint)
457+ inout += total_constructionsites / 4;
458+ inout -= wares.at(bo.production_hint).producers;
459+ if (inout < 1)
460+ inout = 1;
461+ // the ware they're refreshing
462+ Ware_Index wt(static_cast<size_t>(bo.production_hint));
463+ container_iterate(std::list<EconomyObserver *>, economies, l) {
464+ // Don't check if the economy has no warehouse.
465+ if ((*l.current)->economy.warehouses().empty())
466+ continue;
467+ if ((*l.current)->economy.needs_ware(wt)) {
468+ prio += wares.at(bo.production_hint).preciousness * inout * 2;
469+ break;
470+ }
471+ }
472+
473+ // Do not build too many of these buildings, but still care
474+ // to build at least two.
475+ // And add bonus near buildings outputting production_hint ware.
476+ prio += (5 * bf->producers_nearby.at(bo.production_hint)) / 2;
477+ prio -= bo.total_count() * 2;
478+ prio /= bo.total_count() + 1;
479+ prio += (bf->producers_nearby.at(bo.production_hint) - 1) * 5;
480+ if (bo.total_count() > 2)
481+ prio -= bo.total_count();
482+ else {
483+ prio += wares.at(bo.production_hint).preciousness;
484+ prio *= 3;
485+ }
486+ if (prio < 0)
487+ return -1;
488+ } else if (bo.recruitment) {
489+ // "recruitment centeres" like the donkey farm should be build up
490+ // as soon as a basic infrastructure was completed.
491+ // and of course the defaultAI should think of further
492+ // constructions of that type later in game.
493+ prio -= 12; // start calculation with an offset
494+ prio += productionsites.size() + mines.size();
495+ prio -= (bo.total_count()) * 40;
496+ prio *= 2;
497+
498+ // take care about borders and enemies
499+ prio = recalc_with_border_range(*bf, prio);
500+ } else { // "normal" productionsites
501+
502+ if (bo.is_basic && (bo.total_count() == 0))
503+ prio += 100; // for very important buildings
504+
505+ // we can enhance this building. build more
506+ // maybe the enhancement can produce needed ware
507+ // TODO: rather plan an enhanced building from bottom up
508+ for (std::set<Building_Index>::const_iterator enhancement =
509+ bo.desc->enhancements().begin();
510+ enhancement != bo.desc->enhancements().end();
511+ enhancement++) {
512+ // when we build a, we can build b, too...
513+ BuildingObserver & bo2 = buildings[*enhancement];
514+ // so simply add the score of the building behind it...
515+ uint32_t prio2 = calculate_building_prio(bo2, bf, expand_factor);
516+ if (prio2 * (1 + bo.total_count()) > prio * (1 + bo2.total_count()))
517+ prio = prio / 2 + prio2; // we want to build the enhanced building instead of this
518+ }
519+
520+
521+ // Check if the produced wares are needed
522+ container_iterate(std::list<EconomyObserver *>, economies, l) {
523+ // Don't check if the economy has no warehouse.
524+ if ((*l.current)->economy.warehouses().empty())
525+ continue;
526+ for (uint32_t m = 0; m < bo.outputs.size(); ++m) {
527+ Ware_Index wt(static_cast<size_t>(bo.outputs.at(m)));
528+
529+ // Our main instinct: what we actually need
530+ // for military, production and construction
531+ prio += round(wares.at(bo.outputs.at(m)).demand / 50.0);
532+
533+ // if we have too much of it (avoids mass storage)
534+ if
535+ ((*l.current)->economy.stock_ware(wt) > 6 *
536+ (*l.current)->economy.ware_target_quantity(wt).permanent)
537+ prio -= 20;
538+
539+ // if the economy needs this ware
540+ if ((*l.current)->economy.needs_ware(wt)) {
541+ prio += 1 + wares.at(bo.outputs.at(m)).preciousness;
542+ if (bo.total_count() == 0)
543+ // big bonus, this site might be elemental
544+ prio += 3 * wares.at(bo.outputs.at(m)).preciousness;
545+ }
546+ }
547+ for (uint32_t m = 0; m < bo.inputs.size(); ++m) {
548+ Ware_Index wt(static_cast<size_t>(bo.inputs.at(m)));
549+
550+ // Wares that are needed should not be consumed too much
551+ prio -= round(wares.at(wt).demand / 100.0);
552+
553+ // if the economies don't need it: "waste" it
554+ if (!(*l.current)->economy.needs_ware(wt)) {
555+ prio++;
556+ if (bo.total_count() == 0 && bo.prod_build_material)
557+ // big bonus, this site might be elemental
558+ prio += 3 * wares.at(bo.inputs.at(m)).preciousness;
559+ }
560+ }
561+ }
562+
563+ // If the produced wares are needed
564+ if (prio > 0) {
565+ int32_t inout_prio = 0;
566+ for (size_t k = 0; k < bo.inputs.size(); ++k) {
567+ inout_prio += bf->producers_nearby.at(bo.inputs.at(k));
568+ inout_prio -= bf->consumers_nearby.at(bo.inputs.at(k)) / 2;
569+ }
570+ for (size_t k = 0; k < bo.outputs.size(); ++k)
571+ inout_prio += bf->consumers_nearby.at(bo.outputs.at(k));
572+ prio += 2 * inout_prio;
573+ prio = calculate_need_for_ps(bo, prio);
574+ } else
575+ return -1;
576+
577+ // take care about borders and enemies
578+ prio = recalc_with_border_range(*bf, prio);
579+
580+ // do not construct more than one building,
581+ // if supply line is already broken.
582+ if (!check_supply(bo) && bo.total_count() > 0)
583+ prio -= 12;
584+
585+ }
586+ } else if (bo.type == BuildingObserver::MILITARYSITE) {
587+ if (!bf->unowned_land_nearby)
588+ return -1;
589+ prio = bf->unowned_land_nearby * (1 + type);
590+ prio -= bf->military_influence * (5 - type);
591+ // set to at least 1
592+ prio = prio > 0 ? prio : 1;
593+ prio *= expand_factor;
594+ prio /= 2;
595+
596+ if (bf->enemy_nearby)
597+ prio *= 2;
598+ else
599+ prio -= bf->military_influence * 2;
600+
601+ if (bf->avoid_military)
602+ prio /= 5;
603+
604+ prio -= militarysites.size() - productionsites.size() / (3 - type);
605+
606+ } else if (bo.type == BuildingObserver::WAREHOUSE) {
607+ // Build one warehouse for ~every 35 productionsites and mines.
608+ // Militarysites are slightly important as well, to have a bigger
609+ // chance for a warehouses (containing waiting soldiers or wares
610+ // needed for soldier training) near the frontier.
611+ prio += productionsites.size() + mines.size();
612+ prio += militarysites.size() / 3;
613+ prio -= (bo.cnt_under_construction + numof_warehouses) * 35;
614+ prio *= 2;
615+
616+ // take care about borders and enemies
617+ prio = recalc_with_border_range(*bf, prio);
618+
619+ } else if (bo.type == BuildingObserver::TRAININGSITE) {
620+ // Start building trainingsites when there are already more than 50
621+ // other buildings. That should be enough for a working economy.
622+ // On the other hand only build more trainingsites of the same
623+ // type if the economy is really big.
624+ prio += productionsites.size() + militarysites.size();
625+ prio += mines.size();
626+ prio += type * 10; // +0 / +10 / +20 for DEFF/NORM/AGGR
627+ prio = prio / (bo.total_count() + 1);
628+ prio -= (bo.total_count() + 1) * 70;
629+
630+ // take care about borders and enemies
631+ prio = recalc_with_border_range(*bf, prio);
632+ }
633+
634+ // avoid to have too many construction sites
635+ // but still enable the player to build up basic productionsites
636+ if
637+ (bo.type != BuildingObserver::PRODUCTIONSITE ||
638+ !bo.is_basic || bo.total_count() > 0)
639+ prio /=
640+ 1 + bo.cnt_under_construction * (bo.cnt_under_construction + 1);
641+
642+ // add big penalty if water is needed, but is not near
643+ if (bo.need_water) {
644+ if (bf->water_nearby < 3)
645+ return -1;
646+ int effect = bf->water_nearby - 8;
647+ prio +=
648+ effect > 0 ?
649+ static_cast<int>(sqrt(static_cast<double>(effect))) : effect;
650+ // if same producers are nearby, then give some penalty
651+ for (size_t k = 0; k < bo.outputs.size(); ++k)
652+ if (bf->producers_nearby.at(bo.outputs.at(k)) > 0)
653+ prio -= 3;
654+ }
655+
656+ // think of space consuming buildings nearby like farms or vineyards
657+ prio /= 1 + bf->space_consumers_nearby;
658+
659+ return prio;
660+}
661+
662 /**
663 * This function searches for places where a new road is needed to connect two
664 * economies. It then sends the request to build the road.
665@@ -1722,7 +1826,9 @@
666 if (!site.site->has_workers(*x.current, game()))
667 continue;
668
669- int32_t prio = 0; // priority for enhancement
670+ /*BuildableField bf(map.get_fcoords(site.site->get_position()));
671+ int32_t prio = calculate_building_prio(en_bo, &bf, 0); // priority for enhancement*/
672+ int32_t prio = 0;
673
674 // Find new outputs of enhanced building
675 std::vector<int16_t> & current_outputs = site.bo->outputs;
676@@ -1742,6 +1848,7 @@
677 // Check if the new wares are needed in economy of the building
678 for (uint32_t i = 0; i < new_outputs.size(); ++i) {
679 Ware_Index wt(static_cast<size_t>(new_outputs.at(i)));
680+ prio += round(wares.at(new_outputs.at(i)).demand / 50.0);
681 if (site.site->economy().needs_ware(wt))
682 prio += 2 + wares.at(new_outputs.at(i)).preciousness;
683 }
684@@ -2012,6 +2119,7 @@
685 for (uint32_t k = 0; k < bo.inputs.size(); ++k) {
686 prio += 2 * wares.at(bo.inputs.at(k)).producers;
687 prio -= wares.at(bo.inputs.at(k)).consumers;
688+ prio -= round(wares.at(bo.inputs.at(k)).demand / 100.0);
689 }
690 if (bo.inputs.empty())
691 prio += 4;
692@@ -2021,6 +2129,7 @@
693 WareObserver & wo = wares.at(bo.outputs.at(k));
694 if (wo.consumers > 0) {
695 output_prio += wo.preciousness;
696+ output_prio += round(wo.demand / 100.0);
697 output_prio += wo.consumers * 2;
698 output_prio -= wo.producers * 2;
699 if (bo.total_count() == 0)
700
701=== modified file 'src/ai/defaultai.h'
702--- src/ai/defaultai.h 2012-02-20 15:54:26 +0000
703+++ src/ai/defaultai.h 2013-01-05 13:44:24 +0000
704@@ -118,6 +118,7 @@
705 void update_all_buildable_fields (int32_t);
706 void update_all_mineable_fields (int32_t);
707 void update_all_not_buildable_fields ();
708+ void update_demand();
709
710 void update_buildable_field(BuildableField &, uint16_t = 6, bool = false);
711 void update_mineable_field (MineableField &);
712@@ -138,6 +139,7 @@
713
714 int32_t recalc_with_border_range(const BuildableField &, int32_t);
715 int32_t calculate_need_for_ps(BuildingObserver &, int32_t);
716+ int32_t calculate_building_prio(BuildingObserver & bo, BuildableField * const bf, uint32_t expand_factor);
717
718 void consider_productionsite_influence
719 (BuildableField &, Widelands::Coords, BuildingObserver const &);
720@@ -193,6 +195,8 @@
721 int32_t time_of_last_construction;
722
723 uint16_t numof_warehouses;
724+
725+ float military_demand;
726 };
727
728 #endif
729
730=== modified file 'src/logic/militarysite.h'
731--- src/logic/militarysite.h 2012-02-15 21:25:34 +0000
732+++ src/logic/militarysite.h 2013-01-05 13:44:24 +0000
733@@ -75,6 +75,7 @@
734 // Begin implementation of SoldierControl
735 virtual std::vector<Soldier *> presentSoldiers() const;
736 virtual std::vector<Soldier *> stationedSoldiers() const;
737+ virtual uint32_t missingSoldiers() { return m_capacity - stationedSoldiers().size(); }
738 virtual uint32_t minSoldierCapacity() const throw ();
739 virtual uint32_t maxSoldierCapacity() const throw ();
740 virtual uint32_t soldierCapacity() const;
741
742=== modified file 'tribes/barbarians/fernery/conf'
743--- tribes/barbarians/fernery/conf 2011-09-12 17:29:32 +0000
744+++ tribes/barbarians/fernery/conf 2013-01-05 13:44:24 +0000
745@@ -3,6 +3,7 @@
746
747 [aihints]
748 space_consumer=true
749+is_basic=true
750
751 [buildcost]
752 trunk=5

Subscribers

People subscribed via source and target branches

to status/vote changes: