widelands-dev team mailing list archive
-
widelands-dev team
-
Mailing list archive
-
Message #00920
[Merge] lp:~hono/widelands/carli2-ai-improvements into lp:widelands
Mark Scott has proposed merging lp:~hono/widelands/carli2-ai-improvements into lp:widelands.
Requested reviews:
Widelands Developers (widelands-dev)
For more details, see:
https://code.launchpad.net/~hono/widelands/carli2-ai-improvements/+merge/142009
(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
--
https://code.launchpad.net/~hono/widelands/carli2-ai-improvements/+merge/142009
Your team Widelands Developers is requested to review the proposed merge of lp:~hono/widelands/carli2-ai-improvements into lp:widelands.
=== modified file 'src/ai/ai_help_structs.h'
--- src/ai/ai_help_structs.h 2012-09-21 21:36:07 +0000
+++ src/ai/ai_help_structs.h 2013-01-05 13:44:24 +0000
@@ -274,6 +274,7 @@
uint8_t producers;
uint8_t consumers;
uint8_t preciousness;
+ float demand;
};
#endif
=== modified file 'src/ai/defaultai.cc'
--- src/ai/defaultai.cc 2012-09-21 21:36:07 +0000
+++ src/ai/defaultai.cc 2013-01-05 13:44:24 +0000
@@ -30,6 +30,7 @@
#include "economy/economy.h"
#include "economy/flag.h"
#include "economy/road.h"
+#include "economy/wares_queue.h"
#include "logic/findimmovable.h"
#include "logic/findnode.h"
#include "log.h"
@@ -75,7 +76,8 @@
next_attack_consideration_due(300000),
inhibit_road_building (0),
time_of_last_construction (0),
- numof_warehouses (0)
+ numof_warehouses (0),
+ military_demand (0.0)
{}
DefaultAI::~DefaultAI()
@@ -136,6 +138,9 @@
// handled by the AI itself.
update_all_not_buildable_fields();
+ // now update the statistics of what we need (wares and military power)
+ update_demand();
+
// IF defaultAI is AGGRESSIVE - we definitely should consider to attack as
// often as possible.
if (type == AGGRESSIVE)
@@ -234,6 +239,7 @@
wares.at(i).producers = 0;
wares.at(i).consumers = 0;
wares.at(i).preciousness = tribe->get_ware_descr(i)->preciousness();
+ wares.at(i).demand = 0;
}
// collect information about the different buildings our tribe can construct
@@ -472,6 +478,85 @@
}
}
+/***
+ * updates all needs of the economy
+ */
+void DefaultAI::update_demand()
+{
+ // military buildings need soldiers: count them!
+ for
+ (std::list<MilitarySiteObserver>::iterator i =
+ militarysites.begin();
+ i != militarysites.end();
+ ++i)
+ {
+ military_demand += i->site->missingSoldiers();
+ }
+ military_demand += 1; // some extra points such that we always get new soldiers
+ military_demand *= 0.99;
+ military_demand = std::max(military_demand, (type + 2) * (float) 2000.0); // then limit it to some degree.
+ // enable logging for debug purpose
+ //printf("mil = %f\n", military_demand);
+
+ // now we know how much military we need, so we
+ // need the wares to build the soldiers
+ Ware_Index const nr_workers = tribe->get_nrworkers();
+ for (Ware_Index i = Ware_Index::First(); i < nr_workers; ++i) {
+ // Find all build costs for soldiers
+ // is it a soldier?
+ if(tribe->get_worker_descr(i)->get_worker_type() == Worker_Descr::SOLDIER) {
+ Worker_Descr::Buildcost::const_iterator end = tribe->get_worker_descr(i)->buildcost().end();
+ for(Worker_Descr::Buildcost::const_iterator it = tribe->get_worker_descr(i)->buildcost().begin(); it != end; ++it) {
+ if(tribe->ware_index(it->first))
+ wares.at(tribe->ware_index(it->first)).demand += it->second * military_demand / 100.0; // Add soldier-need priority
+ }
+ }
+ }
+
+
+ // production buildings need inputs
+ std::list<ProductionSiteObserver>::const_iterator i =
+ productionsites.begin();
+ while(1)
+ {
+ // iterate through both: production buildings and mines
+ if(i == productionsites.end())
+ i = mines.begin();
+ if(i == mines.end())
+ break;
+ // count all empty slots
+ for
+ (ProductionSite::Input_Queues::const_iterator j =
+ i->site->warequeues().begin();
+ j != i->site->warequeues().end();
+ j++)
+ {
+ if((*j)->get_filled() == 0)
+ // count queues that are empty
+ wares.at((*j)->get_ware()).demand += 1;
+ }
+ i++;
+ }
+
+ /* TODO: Iterate over all construction sites and add material need
+ // Remark: construction materials are also handled by other code, but this
+ // code could do it more scalable for big empires
+
+ Buildcost::const_iterator end = bld.buildcost().end();
+ for(Buildcost::const_iterator it = bld.buildcost().begin(); it != end; ++it) {
+ wares.at(it->first).demand += it->second; // Add build-need priority
+ }*/
+
+ // now decrease the total ammount a bit
+ Ware_Index nr_wares = tribe->get_nrwares();
+ for (Ware_Index i = Ware_Index::First(); i < nr_wares; ++i)
+ {
+ wares.at(i).demand *= 0.99;
+ // enable logging for debug purpose
+ //printf("ware %s: %f\n", tribe->get_ware_descr(i)->name().c_str(), wares.at(i).demand);
+ }
+}
+
/// Updates one buildable field
void DefaultAI::update_buildable_field
@@ -860,245 +945,7 @@
if (bo.desc->get_size() > maxsize)
continue;
- int32_t prio = 0;
-
- if (bo.type == BuildingObserver::PRODUCTIONSITE) {
- // Don't build another building of this type, if there is already
- // one that is unoccupied at the moment
- if (bo.unoccupied)
- continue;
- if (bo.need_trees) {
- // Priority of woodcutters depend on the number of near trees
- prio += bf->trees_nearby * 3;
- prio /= 3 * (1 + bf->producers_nearby.at(bo.outputs.at(0)));
-
- // TODO improve this - it's still useless to place lumberjack huts randomly
- /*if (prio <= 0) // no, sometimes we need wood without having a forest
- continue;*/
-
- // Check if the produced wares are needed
- Ware_Index wt(static_cast<size_t>(bo.outputs.at(0)));
- container_iterate(std::list<EconomyObserver *>, economies, l) {
- // Don't check if the economy has no warehouse.
- if ((*l.current)->economy.warehouses().empty())
- continue;
- if ((*l.current)->economy.needs_ware(wt))
- prio += 1 + wares.at(bo.outputs.at(0)).preciousness;
- }
-
- if (bo.total_count() < 2) {
- prio *= 6; // big bonus for the basics
- if (bo.total_count() == 0)
- prio *= 4; // even more for the absolute basics
- }
- } else if (bo.need_stones) {
- // Priority of quarries depend on the number of near stones
- prio += bf->stones_nearby * 3;
- prio /= 3 * (1 + bf->producers_nearby.at(bo.outputs.at(0)));
- if (bo.total_count() < 2) {
- prio *= 6; // big bonus for the basics
- if (bo.total_count() == 0)
- prio *= 4; // even more for the absolute basics
- }
- } else if (bo.production_hint >= 0) {
- // production hint (f.e. associate forester with trunks)
-
- // Calculate the need for this building
- int16_t inout = wares.at(bo.production_hint).consumers;
- if
- (tribe->safe_ware_index("trunk").value()
- ==
- bo.production_hint)
- inout += total_constructionsites / 4;
- inout -= wares.at(bo.production_hint).producers;
- if (inout < 1)
- inout = 1;
- // the ware they're refreshing
- Ware_Index wt(static_cast<size_t>(bo.production_hint));
- container_iterate(std::list<EconomyObserver *>, economies, l) {
- // Don't check if the economy has no warehouse.
- if ((*l.current)->economy.warehouses().empty())
- continue;
- if ((*l.current)->economy.needs_ware(wt)) {
- prio += wares.at(bo.production_hint).preciousness * inout * 2;
- break;
- }
- }
-
- // Do not build too many of these buildings, but still care
- // to build at least two.
- // And add bonus near buildings outputting production_hint ware.
- prio += (5 * bf->producers_nearby.at(bo.production_hint)) / 2;
- prio -= bo.total_count() * 2;
- prio /= bo.total_count() + 1;
- prio += (bf->producers_nearby.at(bo.production_hint) - 1) * 5;
- if (bo.total_count() > 2)
- prio -= bo.total_count();
- else {
- prio += wares.at(bo.production_hint).preciousness;
- prio *= 3;
- }
- if (prio < 0)
- continue;
- } else if (bo.recruitment) {
- // "recruitment centeres" like the donkey farm should be build up
- // as soon as a basic infrastructure was completed.
- // and of course the defaultAI should think of further
- // constructions of that type later in game.
- prio -= 12; // start calculation with an offset
- prio += productionsites.size() + mines.size();
- prio -= (bo.total_count()) * 40;
- prio *= 2;
-
- // take care about borders and enemies
- prio = recalc_with_border_range(*bf, prio);
- } else { // "normal" productionsites
-
- // ToDo: prefer soldier producing things
- // Ware_Index const soldier_index = tribe().worker_index("soldier");
-
- if (bo.is_basic && (bo.total_count() == 0))
- prio += 100; // for very important buildings
-
- // Check if the produced wares are needed
- container_iterate(std::list<EconomyObserver *>, economies, l) {
- // Don't check if the economy has no warehouse.
- if ((*l.current)->economy.warehouses().empty())
- continue;
- for (uint32_t m = 0; m < bo.outputs.size(); ++m) {
- Ware_Index wt(static_cast<size_t>(bo.outputs.at(m)));
-
- // if we have too much of it (avoids mass storage)
- if
- ((*l.current)->economy.stock_ware(wt) > 6 *
- (*l.current)->economy.ware_target_quantity(wt).permanent)
- prio -= 20;
-
- // if the economy needs this ware
- if ((*l.current)->economy.needs_ware(wt)) {
- prio += 1 + wares.at(bo.outputs.at(m)).preciousness;
- if (bo.total_count() == 0)
- // big bonus, this site might be elemental
- prio += 3 * wares.at(bo.outputs.at(m)).preciousness;
- }
-
- // we can enhance this building. build more
- // maybe the enhancement can produce needed ware
- if (bo.desc->enhancements().size() > 0) {
- // this code builds more metalworks
- if (bo.total_count() == 0)
- prio += 2;
- if (bo.total_count() == 1)
- prio += 8;
- }
- }
- for (uint32_t m = 0; m < bo.inputs.size(); ++m) {
- Ware_Index wt(static_cast<size_t>(bo.inputs.at(m)));
-
- // if the economies don't need it: "waste" it
- if (!(*l.current)->economy.needs_ware(wt)) {
- if (bo.total_count() == 0 && bo.prod_build_material)
- // big bonus, this site might be elemental
- prio += 3 * wares.at(bo.inputs.at(m)).preciousness;
- }
- }
- }
-
- // If the produced wares are needed
- if (prio > 0) {
- int32_t inout_prio = 0;
- for (size_t k = 0; k < bo.inputs.size(); ++k) {
- inout_prio += bf->producers_nearby.at(bo.inputs.at(k));
- inout_prio -= bf->consumers_nearby.at(bo.inputs.at(k)) / 2;
- }
- for (size_t k = 0; k < bo.outputs.size(); ++k)
- inout_prio += bf->consumers_nearby.at(bo.outputs.at(k));
- prio += 2 * inout_prio;
- prio = calculate_need_for_ps(bo, prio);
- } else
- continue;
-
- // take care about borders and enemies
- prio = recalc_with_border_range(*bf, prio);
-
- // do not construct more than one building,
- // if supply line is already broken.
- if (!check_supply(bo) && bo.total_count() > 0)
- prio -= 12;
-
- }
- } else if (bo.type == BuildingObserver::MILITARYSITE) {
- if (!bf->unowned_land_nearby)
- continue;
- prio = bf->unowned_land_nearby * (1 + type);
- prio -= bf->military_influence * (5 - type);
- // set to at least 1
- prio = prio > 0 ? prio : 1;
- prio *= expand_factor;
- prio /= 2;
-
- if (bf->enemy_nearby)
- prio *= 2;
- else
- prio -= bf->military_influence * 2;
-
- if (bf->avoid_military)
- prio /= 5;
-
- prio -= militarysites.size() - productionsites.size() / (3 - type);
-
- } else if (bo.type == BuildingObserver::WAREHOUSE) {
- // Build one warehouse for ~every 35 productionsites and mines.
- // Militarysites are slightly important as well, to have a bigger
- // chance for a warehouses (containing waiting soldiers or wares
- // needed for soldier training) near the frontier.
- prio += productionsites.size() + mines.size();
- prio += militarysites.size() / 3;
- prio -= (bo.cnt_under_construction + numof_warehouses) * 35;
- prio *= 2;
-
- // take care about borders and enemies
- prio = recalc_with_border_range(*bf, prio);
-
- } else if (bo.type == BuildingObserver::TRAININGSITE) {
- // Start building trainingsites when there are already more than 50
- // other buildings. That should be enough for a working economy.
- // On the other hand only build more trainingsites of the same
- // type if the economy is really big.
- prio += productionsites.size() + militarysites.size();
- prio += mines.size();
- prio += type * 10; // +0 / +10 / +20 for DEFF/NORM/AGGR
- prio = prio / (bo.total_count() + 1);
- prio -= (bo.total_count() + 1) * 70;
-
- // take care about borders and enemies
- prio = recalc_with_border_range(*bf, prio);
- }
-
- // avoid to have too many construction sites
- // but still enable the player to build up basic productionsites
- if
- (bo.type != BuildingObserver::PRODUCTIONSITE ||
- !bo.is_basic || bo.total_count() > 0)
- prio /=
- 1 + bo.cnt_under_construction * (bo.cnt_under_construction + 1);
-
- // add big penalty if water is needed, but is not near
- if (bo.need_water) {
- if (bf->water_nearby < 3)
- continue;
- int effect = bf->water_nearby - 8;
- prio +=
- effect > 0 ?
- static_cast<int>(sqrt(static_cast<double>(effect))) : effect;
- // if same producers are nearby, then give some penalty
- for (size_t k = 0; k < bo.outputs.size(); ++k)
- if (bf->producers_nearby.at(bo.outputs.at(k)) > 0)
- prio -= 3;
- }
-
- // think of space consuming buildings nearby like farms or vineyards
- prio /= 1 + bf->space_consumers_nearby;
+ int32_t prio = calculate_building_prio(bo, bf, expand_factor);
// Stop here, if priority is 0 or less.
if (prio <= 0)
@@ -1199,6 +1046,7 @@
uint32_t ioprio = 0;
for (uint32_t m = 0; m < bo.outputs.size(); ++m) {
ioprio += 5 * wares.at(bo.outputs.at(m)).preciousness;
+ ioprio += round(wares.at(bo.outputs.at(m)).demand / 100.0);
}
// tribes that have enhanceable mines should build more mines
@@ -1214,7 +1062,7 @@
// multiply with current statistics of all other buildings of this
// type to avoid constructing buildings where already some are running
// on low resources.
- prio *= 5 + bo.current_stats;
+ prio *= 45 + bo.current_stats;
prio /= 100;
if (onlymissing) // mines aren't *that* important
@@ -1252,6 +1100,262 @@
return true;
}
+int32_t DefaultAI::calculate_building_prio(BuildingObserver & bo, BuildableField * const bf, uint32_t expand_factor)
+{
+ int32_t prio = 0;
+
+ if (bo.type == BuildingObserver::PRODUCTIONSITE) {
+ // Don't build another building of this type, if there is already
+ // one that is unoccupied at the moment
+ if (bo.unoccupied)
+ return -1;
+ if (bo.need_trees) {
+ // Priority of woodcutters depend on the number of near trees
+ prio += bf->trees_nearby * 3;
+ prio /= 3 * (1 + bf->producers_nearby.at(bo.outputs.at(0)));
+
+ // TODO improve this - it's still useless to place lumberjack huts randomly
+ /*if (prio <= 0) // no, sometimes we need wood without having a forest
+ return -1;*/
+
+ // Check if the produced wares are needed
+ Ware_Index wt(static_cast<size_t>(bo.outputs.at(0)));
+ container_iterate(std::list<EconomyObserver *>, economies, l) {
+ // Don't check if the economy has no warehouse.
+ if ((*l.current)->economy.warehouses().empty())
+ continue;
+ if ((*l.current)->economy.needs_ware(wt))
+ prio += 1 + wares.at(bo.outputs.at(0)).preciousness;
+ }
+
+ if (bo.total_count() < 2) {
+ prio *= 6; // big bonus for the basics
+ if (bo.total_count() == 0)
+ prio *= 4; // even more for the absolute basics
+ }
+ } else if (bo.need_stones) {
+ // Priority of quarries depend on the number of near stones
+ prio += bf->stones_nearby * 3;
+ prio /= 3 * (1 + bf->producers_nearby.at(bo.outputs.at(0)));
+ if (bo.total_count() < 2) {
+ prio *= 6; // big bonus for the basics
+ if (bo.total_count() == 0)
+ prio *= 4; // even more for the absolute basics
+ }
+ } else if (bo.production_hint >= 0) {
+ // production hint (f.e. associate forester with trunks)
+
+ // Calculate the need for this building
+ int16_t inout = wares.at(bo.production_hint).consumers;
+ if
+ (tribe->safe_ware_index("trunk").value()
+ ==
+ bo.production_hint)
+ inout += total_constructionsites / 4;
+ inout -= wares.at(bo.production_hint).producers;
+ if (inout < 1)
+ inout = 1;
+ // the ware they're refreshing
+ Ware_Index wt(static_cast<size_t>(bo.production_hint));
+ container_iterate(std::list<EconomyObserver *>, economies, l) {
+ // Don't check if the economy has no warehouse.
+ if ((*l.current)->economy.warehouses().empty())
+ continue;
+ if ((*l.current)->economy.needs_ware(wt)) {
+ prio += wares.at(bo.production_hint).preciousness * inout * 2;
+ break;
+ }
+ }
+
+ // Do not build too many of these buildings, but still care
+ // to build at least two.
+ // And add bonus near buildings outputting production_hint ware.
+ prio += (5 * bf->producers_nearby.at(bo.production_hint)) / 2;
+ prio -= bo.total_count() * 2;
+ prio /= bo.total_count() + 1;
+ prio += (bf->producers_nearby.at(bo.production_hint) - 1) * 5;
+ if (bo.total_count() > 2)
+ prio -= bo.total_count();
+ else {
+ prio += wares.at(bo.production_hint).preciousness;
+ prio *= 3;
+ }
+ if (prio < 0)
+ return -1;
+ } else if (bo.recruitment) {
+ // "recruitment centeres" like the donkey farm should be build up
+ // as soon as a basic infrastructure was completed.
+ // and of course the defaultAI should think of further
+ // constructions of that type later in game.
+ prio -= 12; // start calculation with an offset
+ prio += productionsites.size() + mines.size();
+ prio -= (bo.total_count()) * 40;
+ prio *= 2;
+
+ // take care about borders and enemies
+ prio = recalc_with_border_range(*bf, prio);
+ } else { // "normal" productionsites
+
+ if (bo.is_basic && (bo.total_count() == 0))
+ prio += 100; // for very important buildings
+
+ // we can enhance this building. build more
+ // maybe the enhancement can produce needed ware
+ // TODO: rather plan an enhanced building from bottom up
+ for (std::set<Building_Index>::const_iterator enhancement =
+ bo.desc->enhancements().begin();
+ enhancement != bo.desc->enhancements().end();
+ enhancement++) {
+ // when we build a, we can build b, too...
+ BuildingObserver & bo2 = buildings[*enhancement];
+ // so simply add the score of the building behind it...
+ uint32_t prio2 = calculate_building_prio(bo2, bf, expand_factor);
+ if (prio2 * (1 + bo.total_count()) > prio * (1 + bo2.total_count()))
+ prio = prio / 2 + prio2; // we want to build the enhanced building instead of this
+ }
+
+
+ // Check if the produced wares are needed
+ container_iterate(std::list<EconomyObserver *>, economies, l) {
+ // Don't check if the economy has no warehouse.
+ if ((*l.current)->economy.warehouses().empty())
+ continue;
+ for (uint32_t m = 0; m < bo.outputs.size(); ++m) {
+ Ware_Index wt(static_cast<size_t>(bo.outputs.at(m)));
+
+ // Our main instinct: what we actually need
+ // for military, production and construction
+ prio += round(wares.at(bo.outputs.at(m)).demand / 50.0);
+
+ // if we have too much of it (avoids mass storage)
+ if
+ ((*l.current)->economy.stock_ware(wt) > 6 *
+ (*l.current)->economy.ware_target_quantity(wt).permanent)
+ prio -= 20;
+
+ // if the economy needs this ware
+ if ((*l.current)->economy.needs_ware(wt)) {
+ prio += 1 + wares.at(bo.outputs.at(m)).preciousness;
+ if (bo.total_count() == 0)
+ // big bonus, this site might be elemental
+ prio += 3 * wares.at(bo.outputs.at(m)).preciousness;
+ }
+ }
+ for (uint32_t m = 0; m < bo.inputs.size(); ++m) {
+ Ware_Index wt(static_cast<size_t>(bo.inputs.at(m)));
+
+ // Wares that are needed should not be consumed too much
+ prio -= round(wares.at(wt).demand / 100.0);
+
+ // if the economies don't need it: "waste" it
+ if (!(*l.current)->economy.needs_ware(wt)) {
+ prio++;
+ if (bo.total_count() == 0 && bo.prod_build_material)
+ // big bonus, this site might be elemental
+ prio += 3 * wares.at(bo.inputs.at(m)).preciousness;
+ }
+ }
+ }
+
+ // If the produced wares are needed
+ if (prio > 0) {
+ int32_t inout_prio = 0;
+ for (size_t k = 0; k < bo.inputs.size(); ++k) {
+ inout_prio += bf->producers_nearby.at(bo.inputs.at(k));
+ inout_prio -= bf->consumers_nearby.at(bo.inputs.at(k)) / 2;
+ }
+ for (size_t k = 0; k < bo.outputs.size(); ++k)
+ inout_prio += bf->consumers_nearby.at(bo.outputs.at(k));
+ prio += 2 * inout_prio;
+ prio = calculate_need_for_ps(bo, prio);
+ } else
+ return -1;
+
+ // take care about borders and enemies
+ prio = recalc_with_border_range(*bf, prio);
+
+ // do not construct more than one building,
+ // if supply line is already broken.
+ if (!check_supply(bo) && bo.total_count() > 0)
+ prio -= 12;
+
+ }
+ } else if (bo.type == BuildingObserver::MILITARYSITE) {
+ if (!bf->unowned_land_nearby)
+ return -1;
+ prio = bf->unowned_land_nearby * (1 + type);
+ prio -= bf->military_influence * (5 - type);
+ // set to at least 1
+ prio = prio > 0 ? prio : 1;
+ prio *= expand_factor;
+ prio /= 2;
+
+ if (bf->enemy_nearby)
+ prio *= 2;
+ else
+ prio -= bf->military_influence * 2;
+
+ if (bf->avoid_military)
+ prio /= 5;
+
+ prio -= militarysites.size() - productionsites.size() / (3 - type);
+
+ } else if (bo.type == BuildingObserver::WAREHOUSE) {
+ // Build one warehouse for ~every 35 productionsites and mines.
+ // Militarysites are slightly important as well, to have a bigger
+ // chance for a warehouses (containing waiting soldiers or wares
+ // needed for soldier training) near the frontier.
+ prio += productionsites.size() + mines.size();
+ prio += militarysites.size() / 3;
+ prio -= (bo.cnt_under_construction + numof_warehouses) * 35;
+ prio *= 2;
+
+ // take care about borders and enemies
+ prio = recalc_with_border_range(*bf, prio);
+
+ } else if (bo.type == BuildingObserver::TRAININGSITE) {
+ // Start building trainingsites when there are already more than 50
+ // other buildings. That should be enough for a working economy.
+ // On the other hand only build more trainingsites of the same
+ // type if the economy is really big.
+ prio += productionsites.size() + militarysites.size();
+ prio += mines.size();
+ prio += type * 10; // +0 / +10 / +20 for DEFF/NORM/AGGR
+ prio = prio / (bo.total_count() + 1);
+ prio -= (bo.total_count() + 1) * 70;
+
+ // take care about borders and enemies
+ prio = recalc_with_border_range(*bf, prio);
+ }
+
+ // avoid to have too many construction sites
+ // but still enable the player to build up basic productionsites
+ if
+ (bo.type != BuildingObserver::PRODUCTIONSITE ||
+ !bo.is_basic || bo.total_count() > 0)
+ prio /=
+ 1 + bo.cnt_under_construction * (bo.cnt_under_construction + 1);
+
+ // add big penalty if water is needed, but is not near
+ if (bo.need_water) {
+ if (bf->water_nearby < 3)
+ return -1;
+ int effect = bf->water_nearby - 8;
+ prio +=
+ effect > 0 ?
+ static_cast<int>(sqrt(static_cast<double>(effect))) : effect;
+ // if same producers are nearby, then give some penalty
+ for (size_t k = 0; k < bo.outputs.size(); ++k)
+ if (bf->producers_nearby.at(bo.outputs.at(k)) > 0)
+ prio -= 3;
+ }
+
+ // think of space consuming buildings nearby like farms or vineyards
+ prio /= 1 + bf->space_consumers_nearby;
+
+ return prio;
+}
+
/**
* This function searches for places where a new road is needed to connect two
* economies. It then sends the request to build the road.
@@ -1722,7 +1826,9 @@
if (!site.site->has_workers(*x.current, game()))
continue;
- int32_t prio = 0; // priority for enhancement
+ /*BuildableField bf(map.get_fcoords(site.site->get_position()));
+ int32_t prio = calculate_building_prio(en_bo, &bf, 0); // priority for enhancement*/
+ int32_t prio = 0;
// Find new outputs of enhanced building
std::vector<int16_t> & current_outputs = site.bo->outputs;
@@ -1742,6 +1848,7 @@
// Check if the new wares are needed in economy of the building
for (uint32_t i = 0; i < new_outputs.size(); ++i) {
Ware_Index wt(static_cast<size_t>(new_outputs.at(i)));
+ prio += round(wares.at(new_outputs.at(i)).demand / 50.0);
if (site.site->economy().needs_ware(wt))
prio += 2 + wares.at(new_outputs.at(i)).preciousness;
}
@@ -2012,6 +2119,7 @@
for (uint32_t k = 0; k < bo.inputs.size(); ++k) {
prio += 2 * wares.at(bo.inputs.at(k)).producers;
prio -= wares.at(bo.inputs.at(k)).consumers;
+ prio -= round(wares.at(bo.inputs.at(k)).demand / 100.0);
}
if (bo.inputs.empty())
prio += 4;
@@ -2021,6 +2129,7 @@
WareObserver & wo = wares.at(bo.outputs.at(k));
if (wo.consumers > 0) {
output_prio += wo.preciousness;
+ output_prio += round(wo.demand / 100.0);
output_prio += wo.consumers * 2;
output_prio -= wo.producers * 2;
if (bo.total_count() == 0)
=== modified file 'src/ai/defaultai.h'
--- src/ai/defaultai.h 2012-02-20 15:54:26 +0000
+++ src/ai/defaultai.h 2013-01-05 13:44:24 +0000
@@ -118,6 +118,7 @@
void update_all_buildable_fields (int32_t);
void update_all_mineable_fields (int32_t);
void update_all_not_buildable_fields ();
+ void update_demand();
void update_buildable_field(BuildableField &, uint16_t = 6, bool = false);
void update_mineable_field (MineableField &);
@@ -138,6 +139,7 @@
int32_t recalc_with_border_range(const BuildableField &, int32_t);
int32_t calculate_need_for_ps(BuildingObserver &, int32_t);
+ int32_t calculate_building_prio(BuildingObserver & bo, BuildableField * const bf, uint32_t expand_factor);
void consider_productionsite_influence
(BuildableField &, Widelands::Coords, BuildingObserver const &);
@@ -193,6 +195,8 @@
int32_t time_of_last_construction;
uint16_t numof_warehouses;
+
+ float military_demand;
};
#endif
=== modified file 'src/logic/militarysite.h'
--- src/logic/militarysite.h 2012-02-15 21:25:34 +0000
+++ src/logic/militarysite.h 2013-01-05 13:44:24 +0000
@@ -75,6 +75,7 @@
// Begin implementation of SoldierControl
virtual std::vector<Soldier *> presentSoldiers() const;
virtual std::vector<Soldier *> stationedSoldiers() const;
+ virtual uint32_t missingSoldiers() { return m_capacity - stationedSoldiers().size(); }
virtual uint32_t minSoldierCapacity() const throw ();
virtual uint32_t maxSoldierCapacity() const throw ();
virtual uint32_t soldierCapacity() const;
=== modified file 'tribes/barbarians/fernery/conf'
--- tribes/barbarians/fernery/conf 2011-09-12 17:29:32 +0000
+++ tribes/barbarians/fernery/conf 2013-01-05 13:44:24 +0000
@@ -3,6 +3,7 @@
[aihints]
space_consumer=true
+is_basic=true
[buildcost]
trunk=5