widelands-dev team mailing list archive
-
widelands-dev team
-
Mailing list archive
-
Message #02218
[Merge] lp:~widelands-dev/widelands/tibor-ai4 into lp:widelands
Tibor Bamhor has proposed merging lp:~widelands-dev/widelands/tibor-ai4 into lp:widelands.
Requested reviews:
Widelands Developers (widelands-dev)
For more details, see:
https://code.launchpad.net/~widelands-dev/widelands/tibor-ai4/+merge/226029
Based on discussion with other developers, I created new branch and plainly copied files from tibor-ai3 that differed
--
https://code.launchpad.net/~widelands-dev/widelands/tibor-ai4/+merge/226029
Your team Widelands Developers is requested to review the proposed merge of lp:~widelands-dev/widelands/tibor-ai4 into lp:widelands.
=== modified file 'src/ai/ai_help_structs.cc'
--- src/ai/ai_help_structs.cc 2014-07-03 19:26:30 +0000
+++ src/ai/ai_help_structs.cc 2014-07-08 19:41:26 +0000
@@ -37,7 +37,7 @@
// CheckStepRoadAI
bool CheckStepRoadAI::allowed(Map& map, FCoords, FCoords end, int32_t, CheckStep::StepId const id)
- const {
+ const {
uint8_t endcaps = player_->get_buildcaps(end);
// Calculate cost and passability
=== modified file 'src/ai/ai_help_structs.h'
--- src/ai/ai_help_structs.h 2014-07-05 16:41:51 +0000
+++ src/ai/ai_help_structs.h 2014-07-08 19:41:26 +0000
@@ -70,6 +70,21 @@
}
};
+struct FindNodeEnemiesBuilding {
+ bool accept(const Map&, const FCoords& fc) const {
+ // we are looking for fields we can walk on
+ // and owned by hostile player.
+ return (fc.field->get_immovable()) && fc.field->get_owned_by() != 0 &&
+ player->is_hostile(*game.get_player(fc.field->get_owned_by()));
+ }
+
+ Player* player;
+ Game& game;
+
+ FindNodeEnemiesBuilding(Player* p, Game& g) : player(p), game(g) {
+ }
+};
+
struct FindNodeUnowned {
bool accept(const Map&, const FCoords& fc) const {
// when looking for unowned terrain to acquire, we are actually
@@ -105,10 +120,12 @@
};
struct FindNodeWater {
- FindNodeWater(const World& world) : world_(world) {}
+ FindNodeWater(const World& world) : world_(world) {
+ }
bool accept(const Map& /* map */, const FCoords& coord) const {
- return (world_.terrain_descr(coord.field->terrain_d()).get_is() & TerrainDescription::WATER) ||
+ return (world_.terrain_descr(coord.field->terrain_d()).get_is() &
+ TerrainDescription::WATER) ||
(world_.terrain_descr(coord.field->terrain_r()).get_is() & TerrainDescription::WATER);
}
@@ -116,6 +133,7 @@
const World& world_;
};
+
struct FindNodeWithFlagOrRoad {
Economy* economy;
bool accept(const Map&, FCoords) const;
@@ -174,10 +192,14 @@
bool enemy_nearby_;
uint8_t unowned_land_nearby_;
+ // to identify that field is too close to border and no production building should be built there
+ bool near_border_;
uint8_t unowned_mines_pots_nearby_;
uint8_t trees_nearby_;
uint8_t stones_nearby_;
int8_t water_nearby_;
+ int8_t fish_nearby_;
+ int8_t critters_nearby_;
int8_t ground_water_; // used by wells
uint8_t space_consumers_nearby_;
// to manage the military better following variables exists:
@@ -205,6 +227,7 @@
preferred_(false),
enemy_nearby_(0),
unowned_land_nearby_(0),
+ near_border_(false),
trees_nearby_(0),
// explanation of starting values
// this is done to save some work for AI (CPU utilization)
@@ -215,6 +238,8 @@
// non-negative, water is not recaldulated
stones_nearby_(1),
water_nearby_(-1),
+ fish_nearby_(-1),
+ critters_nearby_(-1),
ground_water_(1),
space_consumers_nearby_(0),
military_capacity_(0),
@@ -267,17 +292,22 @@
MINE
} type;
- bool is_basic_; // is a "must" to have for the ai
+ bool is_basic_; // is a "must" to have for the ai
+ bool is_food_basic_; // few food producer to be built sooner
bool prod_build_material_;
bool plants_trees_;
bool recruitment_; // is "producing" workers?
bool is_buildable_;
- bool need_trees_; // lumberjack = true
- bool need_stones_; // quarry = true
- bool mines_marble_; // need to distinquish mines_ that produce marbles
- bool mines_water_; // wells
- bool need_water_; // fisher, fish_breeder = true
- bool space_consumer_; // farm, vineyard... = true
+ bool need_trees_; // lumberjack = true
+ bool need_stones_; // quarry = true
+ bool mines_marble_; // need to distinquish mines_ that produce marbles
+ bool mines_water_; // wells
+ bool need_water_; // fisher, fish_breeder = true
+ bool is_hunter_; // need to identify hunters
+ bool space_consumer_; // farm, vineyard... = true
+ bool expansion_type_; // military building used that can be used to control area
+ bool fighting_type_; // military building built near enemies
+ bool mountain_conqueror_; // military building built near mountains
bool unoccupied_; //
@@ -309,8 +339,9 @@
};
struct ProductionSiteObserver {
- Widelands::OPtr<Widelands::ProductionSite> site;
+ Widelands::ProductionSite* site;
int32_t built_time_;
+ int32_t unoccupied_till_;
uint8_t stats_zero_;
BuildingObserver* bo;
};
@@ -319,6 +350,9 @@
Widelands::MilitarySite* site;
BuildingObserver* bo;
uint8_t checks;
+ // when considering attack most military sites are inside territory and should be skipped during
+ // evaluation
+ bool enemies_nearby;
};
struct WareObserver {
=== modified file 'src/ai/ai_hints.cc'
--- src/ai/ai_hints.cc 2014-06-21 15:17:04 +0000
+++ src/ai/ai_hints.cc 2014-07-08 19:41:26 +0000
@@ -19,7 +19,6 @@
#include "ai/ai_hints.h"
-#include <cstdlib>
#include <cstring>
#include "profile/profile.h"
@@ -30,22 +29,26 @@
}
BuildingHints::BuildingHints(Section* const section)
- : renews_map_resource(nullptr),
- mines_(nullptr),
- basic_(section ? section->get_bool("is_basic") : false),
- build_material_(section ? section->get_bool("build_material") : true),
- log_producer_(section ? section->get_bool("logproducer") : false),
- stone_producer_(section ? section->get_bool("stoneproducer") : false),
- marble_producer_(section ? section->get_bool("marbleproducer") : false),
- needs_water_(section ? section->get_bool("needs_water") : false),
- mines_water_(section ? section->get_bool("mines_water") : false),
- recruitment_(section ? section->get_bool("recruitment") : false),
- space_consumer_(section ? section->get_bool("space_consumer") : false),
- mines_percent_(section ? section->get_int("mines_percent", 100) : 0) {
- if (section) {
- if (char const* const s = section->get_string("renews_map_resource"))
- renews_map_resource = strdup(s);
- if (char const* const s = section->get_string("mines"))
- mines_ = strdup(s);
- }
+ : renews_map_resource(nullptr),
+ mines_(nullptr),
+ basic_(section ? section->get_bool("is_basic") : false),
+ food_basic_(section ? section->get_bool("is_food_basic") : false),
+ build_material_(section ? section->get_bool("build_material") : true),
+ log_producer_(section ? section->get_bool("logproducer") : false),
+ stone_producer_(section ? section->get_bool("stoneproducer") : false),
+ marble_producer_(section ? section->get_bool("marbleproducer") : false),
+ needs_water_(section ? section->get_bool("needs_water") : false),
+ mines_water_(section ? section->get_bool("mines_water") : false),
+ recruitment_(section ? section->get_bool("recruitment") : false),
+ space_consumer_(section ? section->get_bool("space_consumer") : false),
+ expansion_(section ? section->get_bool("expansion") : false),
+ fighting_(section ? section->get_bool("fighting") : false),
+ mountain_conqueror_(section ? section->get_bool("mountain_conqueror") : false),
+ mines_percent_(section ? section->get_int("mines_percent", 100) : 0) {
+ if (section) {
+ if (char const* const s = section->get_string("renews_map_resource"))
+ renews_map_resource = strdup(s);
+ if (char const* const s = section->get_string("mines"))
+ mines_ = strdup(s);
}
+}
=== modified file 'src/ai/ai_hints.h'
--- src/ai/ai_hints.h 2014-07-05 16:41:51 +0000
+++ src/ai/ai_hints.h 2014-07-08 19:41:26 +0000
@@ -20,11 +20,10 @@
#ifndef WL_AI_AI_HINTS_H
#define WL_AI_AI_HINTS_H
-#include <stdint.h>
-
+#include <SDL_types.h>
#include <boost/noncopyable.hpp>
-class Section;
+struct Section;
/// This struct is used to read out the data given in [aihints] section of a
/// buildings conf file. It is used to tell the computer player about the
@@ -45,6 +44,10 @@
return basic_;
}
+ bool is_food_basic() const {
+ return food_basic_;
+ }
+
bool prod_build_material() const {
return build_material_;
}
@@ -76,6 +79,15 @@
bool is_space_consumer() const {
return space_consumer_;
}
+ bool is_expansion_type() const {
+ return expansion_;
+ }
+ bool is_fighting_type() const {
+ return fighting_;
+ }
+ bool is_mountain_conqueror() const {
+ return mountain_conqueror_;
+ }
uint8_t get_mines_percent() const {
return mines_percent_;
@@ -85,6 +97,7 @@
char* renews_map_resource;
char* mines_;
bool basic_;
+ bool food_basic_;
bool build_material_; // whether the building produces build material
bool log_producer_;
bool stone_producer_;
@@ -93,6 +106,9 @@
bool mines_water_;
bool recruitment_; // whether building recruits special workers
bool space_consumer_;
+ bool expansion_;
+ bool fighting_;
+ bool mountain_conqueror_;
uint8_t mines_percent_;
};
=== modified file 'src/ai/defaultai.cc'
--- src/ai/defaultai.cc 2014-07-03 19:26:30 +0000
+++ src/ai/defaultai.cc 2014-07-08 19:41:26 +0000
@@ -16,8 +16,9 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*/
-
-#include "ai/defaultai.h"
+/**
+ * Default AI
+ */
#include <algorithm>
#include <ctime>
@@ -25,12 +26,14 @@
#include <typeinfo>
#include "ai/ai_hints.h"
+#include "ai/defaultai.h"
#include "base/log.h"
#include "base/macros.h"
#include "economy/economy.h"
#include "economy/flag.h"
#include "economy/road.h"
#include "logic/constructionsite.h"
+#include "logic/findbob.h"
#include "logic/findimmovable.h"
#include "logic/findnode.h"
#include "logic/map.h"
@@ -64,9 +67,14 @@
constexpr bool kWoodDebug = false;
constexpr bool kSpaceDebug = false;
constexpr bool kStatDebug = false;
-constexpr bool kIdleDismantle = false;
+constexpr bool kIdleDismantle = true;
constexpr bool kWellDebug = false;
+constexpr bool kHuntFishDebug = false;
+constexpr bool kAttackDebug = false;
constexpr int kBaseInfrastructureTime = 20 * 60 * 1000;
+// buildings marked as is_food_basic will be forced after 15 minutes, even though their outputs are
+// not needed yet
+constexpr int kPrimaryFoodStartTime = 15 * 60 * 1000;
using namespace Widelands;
@@ -144,7 +152,6 @@
if (construct_roads(gametime)) {
m_buildable_changed = true;
- // m_mineable_changed = true;
return;
}
} else
@@ -159,11 +166,9 @@
// handled by the AI itself.
update_all_not_buildable_fields();
- // IF defaultAI is AGGRESSIVE - we definitely should consider to attack as
- // often as possible.
- if (type == AGGRESSIVE)
- if (next_attack_consideration_due_ <= gametime)
- consider_attack(gametime);
+ // considering attack
+ if (next_attack_consideration_due_ <= gametime)
+ consider_attack(gametime);
// check if anything in the economies changed.
// This needs to be done before new buildings are placed, to ensure that no
@@ -199,12 +204,6 @@
if (check_militarysites(gametime))
return;
- // Finally consider military actions if defaultAI type is Aggressive or
- // Normal.
- if (!(type == DEFENSIVE))
- if (next_attack_consideration_due_ <= gametime)
- consider_attack(gametime);
-
// improve existing roads!
// This sounds important, but actually is not as important as the other
// actions are. Reasons are the following:
@@ -222,9 +221,10 @@
/// called by Widelands game engine when an immovable changed
void DefaultAI::receive(const NoteImmovable& note) {
- if (note.lg == LOSE)
+ if (note.lg == LOSE) {
+
lose_immovable(*note.pi);
- else
+ } else
gain_immovable(*note.pi);
}
@@ -282,6 +282,7 @@
bo.current_stats_ = 0;
bo.unoccupied_ = false;
bo.is_basic_ = false;
+ bo.is_food_basic_ = false;
bo.is_buildable_ = bld.is_buildable();
bo.need_trees_ = bh.is_logproducer();
bo.need_stones_ = bh.is_stoneproducer();
@@ -290,7 +291,9 @@
bo.mines_water_ = bh.mines_water();
bo.recruitment_ = bh.for_recruitment();
bo.space_consumer_ = bh.is_space_consumer();
-
+ bo.expansion_type_ = bh.is_expansion_type();
+ bo.fighting_type_ = bh.is_fighting_type();
+ bo.mountain_conqueror_ = bh.is_mountain_conqueror();
if (char const* const s = bh.get_renews_map_resource()) {
bo.production_hint_ = tribe->safe_ware_index(s);
@@ -326,8 +329,15 @@
}
bo.is_basic_ = bh.is_basic();
+ bo.is_food_basic_ = bh.is_food_basic();
bo.prod_build_material_ = bh.prod_build_material();
+ // here we identify hunters
+ if (bo.outputs_.size() == 1 and tribe->safe_ware_index("meat") == bo.outputs_.at(0)) {
+ bo.is_hunter_ = true;
+ } else
+ bo.is_hunter_ = false;
+
continue;
}
@@ -491,16 +501,24 @@
FindNodeUnowned find_unowned(player, game());
FindNodeUnownedMineable find_unowned_mines_pots(player, game());
Player_Number const pn = player->player_number();
+ const World& world = game().world();
field.unowned_land_nearby_ =
map.find_fields(Area<FCoords>(field.coords, range), nullptr, find_unowned);
- if (field.unowned_land_nearby_ > 2) // 2 is 'reasonably low' number here
+ field.near_border_ = false;
+ if (field.unowned_land_nearby_ > 0) {
+ if (map.find_fields(Area<FCoords>(field.coords, 4), nullptr, find_unowned) > 0)
+ field.near_border_ = true;
+ }
+
+ // to save some CPU
+ if (mines_.size() > 8 and game().get_gametime() % 3 > 0)
+ field.unowned_mines_pots_nearby_ = 0;
+ else
field.unowned_mines_pots_nearby_ = map.find_fields(
- Area<FCoords>(field.coords, range + 2),
+ Area<FCoords>(field.coords, range + 4),
nullptr,
find_unowned_mines_pots); //+2: a mine can mine raw materials from some range
- else
- field.unowned_mines_pots_nearby_ = 0;
// collect information about resources in the area
std::vector<ImmovableFound> immovables;
@@ -525,13 +543,30 @@
field.consumers_nearby_.clear();
field.consumers_nearby_.resize(wares.size());
std::vector<Coords> water_list;
+ std::vector<Coords> resource_list;
+ std::vector<Bob*> critters_list;
if (field.water_nearby_ == -1) { //-1 means "value has never been calculated"
FindNodeWater find_water(game().world());
- map.find_fields(Area<FCoords>(field.coords, 4), &water_list, find_water);
+ map.find_fields(Area<FCoords>(field.coords, 6), &water_list, find_water);
field.water_nearby_ = water_list.size();
}
+ // counting fields with fish
+ if (field.water_nearby_ > 0 and game().get_gametime() % 10 == 0) {
+ map.find_fields(Area<FCoords>(field.coords, 6),
+ &resource_list,
+ FindNodeResource(world.get_resource("fish")));
+ field.fish_nearby_ = resource_list.size();
+ }
+
+ // counting fields with critters (game)
+ // not doing this allways, this does not change fast
+ if (game().get_gametime() % 10 == 0) {
+ map.find_bobs(Area<FCoords>(field.coords, 6), &critters_list, FindBobCritter());
+ field.critters_nearby_ = critters_list.size();
+ }
+
FCoords fse;
map.get_neighbour(field.coords, WALK_SE, &fse);
@@ -590,13 +625,10 @@
}
}
- //// ground water is not renewable and its amount can only fall, we will count them only if
- /// previous state si nonzero
+ // ground water is not renewable and its amount can only fall, we will count them only if
+ // previous state si nonzero
if (field.ground_water_ > 0) {
- field.ground_water_ =
- field.coords.field->get_resources_amount(); // field->get_resources();
-
- // log(" RESOURCE DEBUG: %2d",field.get_resources());
+ field.ground_water_ = field.coords.field->get_resources_amount();
}
}
@@ -658,7 +690,7 @@
if (v > 0 and dist > 0) {
if (kMilitScoreDebug)
log(" FIELD SCORE: testing near military building at %3dx%3d, capacity: %d, "
- "loneliness:%3f (%2d:%2d), stationed: %" PRIuS "\n",
+ "loneliness:%3f (%2d:%2d), stationed: %1d\n",
immovables.at(i).coords.x,
immovables.at(i).coords.y,
militarysite->maxSoldierCapacity(),
@@ -738,45 +770,34 @@
// Check all available productionsites
for (uint32_t i = 0; i < productionsites.size(); ++i) {
- ProductionSiteObserver& productionsite_observer = productionsites.front();
- // TODO(sirver): Popping here means that we HAVE to push another thing at
- // the end or our loop will not do the right think. This is terrible
- // design. It would be much better to push to a new vector and swap the
- // productionsites' content after the loop. I refuse to fix this though.
+ assert(productionsites.front().bo->cnt_built_ > 0);
+ // Add statistics value
+ productionsites.front().bo->current_stats_ +=
+ productionsites.front().site->get_crude_statistics();
+ if (kStatDebug and abs(productionsites.front().site->get_crude_statistics() -
+ productionsites.front().site->get_statistics_percent()) > 50)
+ log(" STAT DEBUG: %15s (%3dx%3d): crude statistic: %3d vs official statistics: %3d\n",
+ productionsites.front().site->name().c_str(),
+ productionsites.front().site->get_position().x,
+ productionsites.front().site->get_position().y,
+ productionsites.front().site->get_crude_statistics(),
+ productionsites.front().site->get_statistics_percent());
+ // Check whether this building is completely occupied
+ productionsites.front().bo->unoccupied_ |= !productionsites.front().site->can_start_working();
+
+ // Now reorder the buildings
+ productionsites.push_back(productionsites.front());
productionsites.pop_front();
-
- assert(productionsite_observer.bo->cnt_built_ > 0);
-
- ProductionSite* productionsite = productionsite_observer.site.get(game());
- if (productionsite != nullptr) {
- // Add statistics value
- productionsite_observer.bo->current_stats_ += productionsite->get_crude_statistics();
- if (kStatDebug and abs(productionsite->get_crude_statistics() -
- productionsite->get_statistics_percent()) > 50)
- log(" STAT DEBUG: %15s (%3dx%3d): crude statistic: %3d vs official statistics: %3d\n",
- productionsite->name().c_str(),
- productionsite->get_position().x,
- productionsite->get_position().y,
- productionsite->get_crude_statistics(),
- productionsite->get_statistics_percent());
- // Check whether this building is completely occupied
- productionsite_observer.bo->unoccupied_ |= !productionsite->can_start_working();
- }
- // Now reorder the buildings
- productionsites.push_back(productionsite_observer);
}
// for mines_ also
// Check all available productionsites
for (uint32_t i = 0; i < mines_.size(); ++i) {
assert(mines_.front().bo->cnt_built_ > 0);
- ProductionSite* mine = mines_.front().site.get(game());
- if (mine != nullptr) {
- // Add statistics value
- mines_.front().bo->current_stats_ += mine->get_statistics_percent();
- // Check whether this building is completely occupied
- mines_.front().bo->unoccupied_ |= !mine->can_start_working();
- }
+ // Add statistics value
+ mines_.front().bo->current_stats_ += mines_.front().site->get_statistics_percent();
+ // Check whether this building is completely occupied
+ mines_.front().bo->unoccupied_ |= !mines_.front().site->can_start_working();
// Now reorder the buildings
mines_.push_back(mines_.front());
mines_.pop_front();
@@ -798,6 +819,8 @@
// - buildings producing building material are preffered
// - buildings identified as basic are preffered
// - first bulding of a type is preffered
+// - buildings identified as 'direct food supplier' as built after 15 min.
+// from game start
// - if a bulding is upgradeable, second building is also preffered
// (there should be no upgrade when there are not two buildings of the same type)
// - algorigthm is trying to take into account actual utlization of buildings
@@ -817,6 +840,7 @@
int32_t bulgarian_constant = 12;
std::vector<int32_t> spots_avail;
spots_avail.resize(4);
+ // uint16_t const pn = player_number();
for (int32_t i = 0; i < 4; ++i)
spots_avail.at(i) = 0;
@@ -826,57 +850,22 @@
++i)
++spots_avail.at((*i)->coords.field->nodecaps() & BUILDCAPS_SIZEMASK);
- // calculating expand factor
- int32_t expand_factor = 0;
-
- if (type != DEFENSIVE) {
- ++expand_factor;
-
- // check space and set the need for expansion
- if (spots_avail.at(BUILDCAPS_BIG) < static_cast<uint16_t>(2 + (productionsites.size() / 50)))
- expand_factor += 2;
-
- if (spots_avail.at(BUILDCAPS_MEDIUM) + spots_avail.at(BUILDCAPS_BIG) <
- static_cast<uint16_t>(4 + (productionsites.size() / 50)))
- expand_factor += type;
-
- spots = spots_avail.at(BUILDCAPS_SMALL);
- spots += spots_avail.at(BUILDCAPS_MEDIUM);
- spots += spots_avail.at(BUILDCAPS_BIG);
-
- if (type == AGGRESSIVE)
- spots -= militarysites.size() / 20;
-
- if (spots < 16)
- expand_factor *= 2;
-
- if ((type == AGGRESSIVE) && spots < 32)
- expand_factor *= 2;
- } else {
- // check space and set the need for expansion
- if (spots_avail.at(BUILDCAPS_BIG) < 7)
- ++expand_factor;
-
- if (spots_avail.at(BUILDCAPS_MEDIUM) + spots_avail.at(BUILDCAPS_BIG) < 12)
- ++expand_factor;
-
- if (spots_avail.at(BUILDCAPS_SMALL) + spots_avail.at(BUILDCAPS_MEDIUM) +
- spots_avail.at(BUILDCAPS_BIG) <
- 16)
- expand_factor *= 3;
- }
+ spots = spots_avail.at(BUILDCAPS_SMALL);
+ spots += spots_avail.at(BUILDCAPS_MEDIUM);
+ spots += spots_avail.at(BUILDCAPS_BIG);
// checking amount of free spots, if needed setting new building stop flag
new_buildings_stop_ = false;
- if (militarysites.size() * 2 + 20 < productionsites.size() or spots <
- (7 + static_cast<int32_t>(productionsites.size()) / 5)) {
+ if ((militarysites.size() * 2 + 20) <
+ productionsites.size()
+ or spots<(3 + (static_cast<int32_t>(productionsites.size()) / 5))or total_constructionsites>(
+ (militarysites.size() + productionsites.size()) / 2)) {
new_buildings_stop_ = true;
}
if (kNewBuildingDebug)
- log(" TDEBUG new buildings stop: %s; milit: %3" PRIuS " vs prod: %3" PRIuS
- " buildings, spots: %4d\n",
+ log(" TDEBUG new buildings stop: %s; milit: %3d vs prod: %3d buildings, spots: %4d\n",
new_buildings_stop_ ? "Y" : "N",
militarysites.size(),
productionsites.size(),
@@ -903,9 +892,10 @@
unstationed_milit_buildings_,
military_under_constr_);
} else if (kMilitaryDebug)
- log(" TDEBUG new military buildings stop OFF, %d %d\n",
+ log(" TDEBUG new military buildings stop OFF, %d %d, bf: %2d\n",
unstationed_milit_buildings_,
- military_under_constr_);
+ military_under_constr_,
+ buildable_fields.size());
if (unstationed_milit_buildings_ + military_under_constr_ / 3 > 2 * treshold) {
near_enemy_b_buildings_stop = true;
@@ -928,11 +918,6 @@
military_boost = 200;
}
- // Defensive AIs also attack sometimes (when they want to expand)
- if (type == DEFENSIVE && expand_factor > 1)
- if (next_attack_consideration_due_ <= game().get_gametime())
- consider_attack(game().get_gametime());
-
// Building_Index proposed_building = INVALID_INDEX; // I need BuildingObserver not index
BuildingObserver* best_building = nullptr;
int32_t proposed_priority = 0;
@@ -996,7 +981,7 @@
if (bo.unoccupied_)
continue;
- if (bo.type != BuildingObserver::MILITARYSITE and bo.cnt_under_construction_ >= 2)
+ if (not(bo.type == BuildingObserver::MILITARYSITE) and bo.cnt_under_construction_ >= 2)
continue;
// so we are going to seriously evaluate this building on this field,
@@ -1033,14 +1018,18 @@
}
}
+ int32_t prio = 0; // score of a bulding on a field
+
// if current field is not big enough
if (bo.desc->get_size() > maxsize)
continue;
- int32_t prio = 0; // score of a bulding on a field
-
if (bo.type == BuildingObserver::PRODUCTIONSITE) {
+ // exclude spots on border
+ if (bf->near_border_ and not bo.need_trees_ and not bo.need_stones_)
+ continue;
+
// this can be only a well (as by now)
if (bo.mines_water_) {
if (bf->ground_water_ < 2)
@@ -1080,15 +1069,15 @@
bo.cnt_built_,
bo.cnt_under_construction_,
bo.unoccupied_,
- bf->trees_nearby_ * 2,
+ bf->trees_nearby_,
(new_buildings_stop_) ? "Y" : "N");
if (bo.cnt_built_ + bo.cnt_under_construction_ + bo.unoccupied_ <= 2)
prio = bulgarian_constant + 200 + bf->trees_nearby_;
else if (bo.cnt_under_construction_ + bo.unoccupied_ <= 1) {
prio =
- bf->trees_nearby_ - 5 -
- new_buildings_stop_ * 40; //+ bf->producers_nearby_.at(bo.outputs_.at(0))*5;
+ bf->trees_nearby_ - 5 - bf->producers_nearby_.at(bo.outputs_.at(0)) * 5 -
+ new_buildings_stop_ * 15; //+ bf->producers_nearby_.at(bo.outputs_.at(0))*5;
}
if (kWoodDebug and prio > 0)
@@ -1114,10 +1103,10 @@
prio = prio * 2;
if (bo.total_count() == 0)
- prio = prio * 2;
+ prio = prio * 5;
// to prevent to many quaries on one spot
- prio = prio - 30 * bf->producers_nearby_.at(bo.outputs_.at(0));
+ prio = prio - 50 * bf->producers_nearby_.at(bo.outputs_.at(0));
} else if (bo.production_hint_ >= 0) {
// first setting targets (needed also for dismantling)
@@ -1128,33 +1117,58 @@
bo.cnt_target_ =
1 + static_cast<int32_t>(mines_.size() + productionsites.size()) / 20;
- if ((bo.cnt_under_construction_ + bo.unoccupied_) > 0)
+ if ((bo.cnt_under_construction_ + bo.unoccupied_) > 1)
continue;
// production hint (f.e. associate forester with logs)
- if (bo.need_water_ and bf->water_nearby_ < 3) // probably some of them needs water
+ if (bo.need_water_ and bf->water_nearby_ < 5) // probably some of them needs water
continue;
if (bo.plants_trees_) { // RANGERS
- if (bo.total_count() < bo.cnt_target_)
- prio = 70;
- else { // even when we are above goal we need to consider level of stock
- if (bo.stocklevel_time < game().get_gametime() - 5 * 1000) {
- bo.stocklevel_ =
- get_stocklevel_by_hint(static_cast<size_t>(bo.production_hint_));
- bo.stocklevel_time = game().get_gametime();
- }
-
- if (bo.stocklevel_ < 5 and new_buildings_stop_)
- prio = bf->producers_nearby_.at(bo.production_hint_) * 5 - 5 -
- bf->trees_nearby_ * 2;
- else if (bo.stocklevel_ < 50)
- prio = 50 + bf->producers_nearby_.at(bo.production_hint_) * 5 -
- bf->trees_nearby_ * 2;
- else
- continue; // we are above tresh
+
+ // if there are too many trees nearby
+ if (bf->trees_nearby_ > 25 and bo.total_count() >= 2)
+ continue;
+
+ // sometimes all area is blocked by trees so this is to prevent this
+ if (buildable_fields.size() < 4)
+ continue;
+
+ // prevent too many rangers
+ if (bo.total_count() * 3 > static_cast<int32_t>(productionsites.size()))
+ continue;
+
+ if (bo.stocklevel_time < game().get_gametime() - 5 * 1000) {
+ bo.stocklevel_ =
+ get_stocklevel_by_hint(static_cast<size_t>(bo.production_hint_));
+ bo.stocklevel_time = game().get_gametime();
}
+ prio = 0;
+ // if we need wood
+ if (bo.stocklevel_ < 50)
+ prio =
+ (50 - bo.stocklevel_) + bf->producers_nearby_.at(bo.production_hint_) * 5;
+
+ // if we just need some rangers to be on safe side
+ if (bo.total_count() < 2)
+ prio += (60 - bf->trees_nearby_) * 3 +
+ bf->producers_nearby_.at(bo.production_hint_) * 5;
+ else if (bo.total_count() < bo.cnt_target_)
+ prio += 30 + bf->producers_nearby_.at(bo.production_hint_) * 5;
+
+ if (kWoodDebug)
+ log(" RANGERS BUILT debug: goal: %2d, existing: %2d, cutters nearby: %2d, "
+ "trees around: %2d, stocklevel: %2d\n",
+ bo.cnt_target_,
+ bo.total_count(),
+ bf->producers_nearby_.at(bo.production_hint_),
+ bf->trees_nearby_,
+ bo.stocklevel_);
+
+ if (kWoodDebug)
+ log(" RANGERS BUILT debug: score: %2d \n", prio);
+
} else if (gametime > kBaseInfrastructureTime and not
new_buildings_stop_) { // gamekeepers or so
if (bo.stocklevel_time < game().get_gametime() - 5 * 1000) {
@@ -1163,13 +1177,20 @@
bo.stocklevel_time = game().get_gametime();
}
+ // especially for fish breeders
+ if (bo.need_water_)
+ prio = bf->water_nearby_;
+
+ if (bo.total_count() == 0)
+ prio += 5;
+
if (bo.total_count() < bo.cnt_target_) {
- prio = bf->producers_nearby_.at(bo.production_hint_) * 10;
- prio = recalc_with_border_range(*bf, prio);
+ prio += bf->producers_nearby_.at(bo.production_hint_) * 10;
+ prio += recalc_with_border_range(*bf, prio);
} else if (bo.stocklevel_ < 50 and not new_buildings_stop_) {
- prio = bf->producers_nearby_.at(bo.production_hint_) * 5;
- prio = recalc_with_border_range(*bf, prio); // only for not wood producers_
+ prio += bf->producers_nearby_.at(bo.production_hint_) * 5;
+ prio += recalc_with_border_range(*bf, prio); // only for not wood producers_
} else
continue;
}
@@ -1203,17 +1224,29 @@
if ((bo.cnt_under_construction_ + bo.unoccupied_) > 0)
continue;
+ // if hunter and too little critters nearby skipping
+ if (bo.is_hunter_ and bf->critters_nearby_ < 5)
+ continue;
+ // similarly for fishers
+ if (bo.need_water_ and bf->fish_nearby_ <= 1)
+ continue;
+
// first eliminate buildings needing water if there is short supplies
- if (bo.need_water_ and bf->water_nearby_ < 3)
+ if (bo.need_water_ and bf->water_nearby_ < 4)
continue;
- if ((bo.is_basic_ or bo.prod_build_material_)and bo.total_count() == 0)
+ if (bo.is_basic_ and bo.total_count() == 0)
prio = 150 + max_preciousness;
- else if (game().get_gametime() <
- kBaseInfrastructureTime or
- new_buildings_stop_) // leave 15 minutes for basic infrastructure only
+ else if (bo.is_food_basic_ and game().get_gametime() >
+ kPrimaryFoodStartTime and bo.total_count() ==
+ 0) {
+ // log (" %1d: Suggesting basic_food %12s\n",pn,bo.name);
+ prio = 40 + max_preciousness;
+ } else if (game().get_gametime() <
+ kBaseInfrastructureTime or
+ new_buildings_stop_) // leave 15 minutes for basic infrastructure only
continue;
- else if (((bo.is_basic_ or bo.prod_build_material_)and bo.total_count() <=
+ else if ((bo.is_basic_ and bo.total_count() <=
1)or(output_is_needed and bo.total_count() == 0))
prio = 80 + max_preciousness;
else if (bo.inputs_.size() == 0) {
@@ -1221,8 +1254,9 @@
1 + static_cast<int32_t>(mines_.size() + productionsites.size()) / 8;
if (bo.cnt_built_ >
- bo.cnt_target_ and not
- bo.space_consumer_) // spaceconsumers_ can be built more then target
+ bo.cnt_target_ and not(
+ bo.space_consumer_ or bo.is_food_basic_)) // spaceconsumers_ and basic_s
+ // can be built more then target
continue;
if (bo.stocklevel_time < game().get_gametime() - 5 * 1000) {
@@ -1238,8 +1272,8 @@
if (bo.stocklevel_ < 50) {
prio = max_preciousness + bulgarian_constant;
- if (bo.space_consumer_)
- prio += 5;
+ if (bo.space_consumer_) // need to consider trees nearby
+ prio += 20 - (bf->trees_nearby_ / 3);
if (not bo.space_consumer_)
prio -= bf->producers_nearby_.at(bo.outputs_.at(0)) *
@@ -1250,8 +1284,27 @@
prio = recalc_with_border_range(*bf, prio);
+ if (bo.stocklevel_ < 20)
+ prio += 20 - bo.stocklevel_;
+
+ // fisher
+ if (bo.need_water_) {
+ prio += bf->fish_nearby_ - 4;
+ if (kHuntFishDebug)
+ log(" Proposing %12s, fishes around: %2d\n", bo.name, bf->fish_nearby_);
+ }
+
+ // hunters
+ if (bo.is_hunter_) {
+ prio += (bf->critters_nearby_ * 2) - 8;
+ if (kHuntFishDebug)
+ log(" Proposing %12s, critters*2-8 around: %2d\n",
+ bo.name,
+ bf->critters_nearby_);
+ }
+
if (kProductionDebug or(kSpaceDebug and bo.space_consumer_))
- log(" TDEBUG: %1d: proposing %-15s , on stock: %3d(<50), stat: %3d, "
+ log(" TDEBUG: %1d: proposing %-15s , stocklevel: %3d(<50), stat: %3d, "
"count: %2d/T:%2d, setting priority: %2d, on %3d %3d\n",
player_number(),
bo.name,
@@ -1266,10 +1319,9 @@
} else if (bo.inputs_.size() > 0) {
// to have two buildings from everything (intended for upgradeable buildings)
// but I do not know how to identify such buildings
- if (bo.cnt_built_ == 1
- and game().get_gametime() > 60 * 60 * 1000
- and !bo.desc->enhancements().empty()
- and !mines_.empty()) {
+ if (bo.cnt_built_ == 1 and game().get_gametime() >
+ 60 * 60 * 1000 and bo.desc->enhancements().size() >
+ 0 and mines_.size() > 0) {
prio = max_preciousness + bulgarian_constant;
}
// if output is needed and there are no idle buildings
@@ -1319,6 +1371,7 @@
}
} // production sites done
else if (bo.type == BuildingObserver::MILITARYSITE) {
+
if (military_boost > 1 and kMilitaryDebug)
log(" TDEBUG: boosting: unowned land %d \n", bf->unowned_land_nearby_);
@@ -1328,6 +1381,22 @@
if (near_enemy_b_buildings_stop and bf->enemy_nearby_)
continue;
+ if (bf->enemy_nearby_ and bo.fighting_type_)
+ ; // it is ok, go on
+ else if (bf->unowned_mines_pots_nearby_ >
+ 0 and(bo.mountain_conqueror_ or bo.expansion_type_))
+ ; // it is ok, go on
+ else if (bf->unowned_land_nearby_ and bo.expansion_type_) {
+ // decreasing probability for big buidlings
+ if (bo.desc->get_size() == 2 and gametime % 5 >= 1)
+ continue;
+ if (bo.desc->get_size() == 3 and gametime % 15 >= 1)
+ continue;
+ }
+ // it is ok, go on
+ else
+ continue; // the building is not suitable for situation
+
if (bo.desc->get_size() ==
3 and game().get_gametime() <
15 * 60 * 1000) // do not built fortresses in first half of hour of game
@@ -1337,7 +1406,7 @@
continue;
// not to build so many military buildings nearby
- if (!bf->enemy_nearby_ and bf->military_in_constr_nearby_ > 1)
+ if (!bf->enemy_nearby_ and bf->military_in_constr_nearby_ > 0)
continue;
// here is to consider unowned potential mines
@@ -1387,6 +1456,11 @@
if (kMilitaryDebug and prio > 0)
log(" NEW MILITARY: candidate's final priority: %d \n", prio);
} else if (bo.type == BuildingObserver::WAREHOUSE) {
+
+ // exclude spots on border
+ if (bf->near_border_)
+ continue;
+
// 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
@@ -1403,6 +1477,11 @@
// introduce check that there is no warehouse nearby to prevent to close placing
} else if (bo.type == BuildingObserver::TRAININGSITE) {
+
+ // exclude spots on border
+ if (bf->near_border_)
+ continue;
+
// build after 20 production sites and then after each 50 production site
if (static_cast<int32_t>((productionsites.size() + 30) / 50) >
bo.total_count() and bo.cnt_under_construction_ ==
@@ -1439,7 +1518,7 @@
update_all_mineable_fields(gametime);
next_mine_construction_due_ = gametime + kIdleMineUpdateInterval;
- if (!mineable_fields.empty()) {
+ if (mineable_fields.size() > 0) {
for (uint32_t i = 0; i < buildings.size() && productionsites.size() > 8; ++i) {
BuildingObserver& bo = buildings.at(i);
@@ -1566,6 +1645,7 @@
if (kWinnerDebug)
log(" TDEBUG: no building picked up\n");
+ mine = false;
return false;
}
@@ -1575,15 +1655,27 @@
game().map().get_fcoords(proposed_coords), game().get_gametime() + 120000); // two minutes
blocked_fields.push_back(blocked);
- if (best_building->type != BuildingObserver::MILITARYSITE)
+ // if space consumer we block also nearby fields
+ if (best_building->space_consumer_ and not best_building->plants_trees_) {
+ Map& map = game().map();
+
+ MapRegion<Area<FCoords>> mr(map, Area<FCoords>(map.get_fcoords(proposed_coords), 3));
+ do {
+ BlockedField blocked2(
+ map.get_fcoords(*(mr.location().field)), game().get_gametime() + 45 * 60 * 1000);
+ blocked_fields.push_back(blocked2);
+ } while (mr.advance(map));
+ }
+
+ if (not(best_building->type == BuildingObserver::MILITARYSITE))
best_building->construction_decision_time_ = gametime;
else // very ugly hack here
best_building->construction_decision_time_ = gametime - kBuildingMinInterval / 2;
if (kWinnerDebug)
- log(" TDEBUG: winning priority %4d, building %2d, coords: %3d x %3d, M: %s\n",
+ log(" TDEBUG: winning priority %4d, building %16s, coords: %3d x %3d, Mine: %s\n",
proposed_priority,
- best_building->id,
+ best_building->name,
proposed_coords.x,
proposed_coords.y,
mine ? "Y" : "N");
@@ -1686,7 +1778,7 @@
return false;
}
-/// improves current road system
+// improves current road system
bool DefaultAI::improve_roads(int32_t gametime) {
// Remove flags of dead end roads, as long as no more wares are stored on them
container_iterate(std::list<EconomyObserver*>, economies, i)
@@ -1819,7 +1911,7 @@
}
}
-/// adds alternative ways to already existing ones
+// adds alternative ways to already existing ones
bool DefaultAI::improve_transportation_ways(const Flag& flag) {
// First of all try to remove old building flags to clean up the road web if possible
container_iterate(std::list<Widelands::Coords>, flags_to_be_removed, i) {
@@ -1944,24 +2036,24 @@
if ((next_productionsite_check_due_ > gametime) || productionsites.empty())
return false;
- next_productionsite_check_due_ = gametime + 5000;
+ next_productionsite_check_due_ = gametime + 4000;
- // Get link to productionsite that should be checked
- ProductionSiteObserver& productionsite_observer = productionsites.front();
+ bool changed = false;
+ // Reorder and set new values; - better now because there are multiple returns in the function
+ productionsites.push_back(productionsites.front());
productionsites.pop_front();
- ProductionSite* productionsite = productionsite_observer.site.get(game());
- if (!productionsite) {
- // Site has vanished.
- return false;
+ // Get link to productionsite that should be checked
+ ProductionSiteObserver& site = productionsites.front();
+
+ // first we werify if site is working yet (can be unoccupied since the start)
+ if (!site.site->can_start_working()) {
+ site.unoccupied_till_ = game().get_gametime();
}
- // Push the back for future consideration.
- productionsites.push_back(productionsite_observer);
- bool changed = false;
// Get max radius of recursive workarea
Workarea_Info::size_type radius = 0;
- const Workarea_Info& workarea_info = productionsite_observer.bo->desc->m_workarea_info;
+ const Workarea_Info& workarea_info = site.bo->desc->m_workarea_info;
container_iterate_const(Workarea_Info, workarea_info, i)
if (radius < i.current->first)
@@ -1971,43 +2063,43 @@
// do not dismantle same type of building too soon - to give some time to update statistics
// yes it interferes with building updates, but not big problem here
- if (productionsite_observer.bo->last_dismantle_time_ > game().get_gametime() - 30 * 1000)
+ if (site.bo->last_dismantle_time_ > game().get_gametime() - 30 * 1000)
return false;
// Lumberjack / Woodcutter handling
- if (productionsite_observer.bo->need_trees_) {
- if (map.find_immovables(
- Area<FCoords>(map.get_fcoords(productionsite->get_position()), radius),
- nullptr,
- FindImmovableAttribute(Map_Object_Descr::get_attribute_id("tree"))) < 6) {
+ if (site.bo->need_trees_) {
+ if (map.find_immovables(Area<FCoords>(map.get_fcoords(site.site->get_position()), radius),
+ nullptr,
+ FindImmovableAttribute(Map_Object_Descr::get_attribute_id("tree"))) <
+ 6) {
// Do not destruct the last lumberjack - perhaps some small trees are
// near, a forester will plant some trees or some new trees will seed
// in reach. Computer player_s can easily run out of wood if this check
// is not done.
- if (productionsite_observer.bo->cnt_built_ <=
+ if (site.bo->cnt_built_ <=
3 + static_cast<int32_t>(mines_.size() + productionsites.size()) / 20) {
if (kWoodDebug)
log(" TDEBUG: %1d: cutter without trees, but not dismantling due to low numbers of "
"cutters (%2d)\n",
player_number(),
- productionsite_observer.bo->cnt_built_);
+ site.bo->cnt_built_);
return false;
}
- if (productionsite->get_statistics_percent() <= 20) {
+ if (site.site->get_statistics_percent() <= 20) {
// destruct the building and it's flag (via flag destruction)
// the destruction of the flag avoids that defaultAI will have too many
// unused roads - if needed the road will be rebuild directly.
// log (" TDEBUG: dismantling lumberjacks hut\n");
- productionsite_observer.bo->last_dismantle_time_ = game().get_gametime();
- flags_to_be_removed.push_back(productionsite->base_flag().get_position());
- game().send_player_dismantle(*productionsite);
+ site.bo->last_dismantle_time_ = game().get_gametime();
+ flags_to_be_removed.push_back(site.site->base_flag().get_position());
+ game().send_player_dismantle(*site.site);
if (kWoodDebug)
log(" TDEBUG %1d: cutter without trees, dismantling..., remaining cutters: %2d\n",
player_number(),
- productionsite_observer.bo->cnt_built_);
+ site.bo->cnt_built_);
return true;
}
@@ -2017,16 +2109,16 @@
}
// Wells handling
- if (productionsite_observer.bo->mines_water_) {
- if (productionsite_observer.built_time_ + 6 * 60 * 1000 <
- game().get_gametime() and productionsite->get_statistics_percent() ==
+ if (site.bo->mines_water_) {
+ if (site.unoccupied_till_ + 6 * 60 * 1000 < game().get_gametime()
+ and site.site->get_statistics_percent() ==
0) {
if (kWellDebug)
log(" TDEBUG: dismantling Well, statistics: %3d,\n",
- productionsite->get_statistics_percent());
- productionsite_observer.bo->last_dismantle_time_ = game().get_gametime();
- flags_to_be_removed.push_back(productionsite->base_flag().get_position());
- game().send_player_dismantle(*productionsite);
+ site.site->get_statistics_percent());
+ site.bo->last_dismantle_time_ = game().get_gametime();
+ flags_to_be_removed.push_back(site.site->base_flag().get_position());
+ game().send_player_dismantle(*site.site);
return true;
}
@@ -2034,39 +2126,39 @@
}
// Quarry handling
- if (productionsite_observer.bo->need_stones_) {
+ if (site.bo->need_stones_) {
if (kQuarryDismDebug) {
log(" QUARRY at %3d x %3d: statistics: %3d/%3d, age: %5d(>360s), stones:%3d\n",
- productionsite->get_position().x,
- productionsite->get_position().y,
- productionsite->get_statistics_percent(),
- productionsite->get_crude_statistics(),
- (gametime - productionsite_observer.built_time_) / 1000,
+ site.site->get_position().x,
+ site.site->get_position().y,
+ site.site->get_statistics_percent(),
+ site.site->get_crude_statistics(),
+ (gametime - site.unoccupied_till_) / 1000,
map.find_immovables(
- Area<FCoords>(map.get_fcoords(productionsite->get_position()), radius),
+ Area<FCoords>(map.get_fcoords(site.site->get_position()), radius),
nullptr,
FindImmovableAttribute(Map_Object_Descr::get_attribute_id("stone"))));
}
if (map.find_immovables(
- Area<FCoords>(map.get_fcoords(productionsite->get_position()), radius),
+ Area<FCoords>(map.get_fcoords(site.site->get_position()), radius),
nullptr,
FindImmovableAttribute(Map_Object_Descr::get_attribute_id("stone"))) == 0) {
// destruct the building and it's flag (via flag destruction)
// the destruction of the flag avoids that defaultAI will have too many
// unused roads - if needed the road will be rebuild directly.
- flags_to_be_removed.push_back(productionsite->base_flag().get_position());
- game().send_player_dismantle(*productionsite);
+ flags_to_be_removed.push_back(site.site->base_flag().get_position());
+ game().send_player_dismantle(*site.site);
return true;
}
- if (productionsite_observer.built_time_ + 6 * 60 * 1000 <
- game().get_gametime() and productionsite->get_statistics_percent() ==
+ if (site.unoccupied_till_ + 6 * 60 * 1000 < game().get_gametime()
+ and site.site->get_statistics_percent() ==
0) {
// it is possible that there are stones but quary is not able to mine them
- productionsite_observer.bo->last_dismantle_time_ = game().get_gametime();
- flags_to_be_removed.push_back(productionsite->base_flag().get_position());
- game().send_player_dismantle(*productionsite);
+ site.bo->last_dismantle_time_ = game().get_gametime();
+ flags_to_be_removed.push_back(site.site->base_flag().get_position());
+ game().send_player_dismantle(*site.site);
return true;
}
@@ -2075,57 +2167,58 @@
}
// All other SPACE_CONSUMERS without input and above target_count
- if (kSpaceDebug and productionsite_observer.bo->space_consumer_ and not
- productionsite_observer.bo->plants_trees_)
+ if (kSpaceDebug and site.bo->space_consumer_ and not site.bo->plants_trees_)
log(" TDEBUG: space consumer here: %15s at %3d x %3d: statistics: %3d, age: %5d(>360s)\n",
- productionsite_observer.bo->name,
- productionsite->get_position().x,
- productionsite->get_position().y,
- productionsite->get_statistics_percent(),
- (gametime - productionsite_observer.built_time_) / 1000);
+ site.bo->name,
+ site.site->get_position().x,
+ site.site->get_position().y,
+ site.site->get_statistics_percent(),
+ (gametime - site.unoccupied_till_) / 1000);
- if (productionsite_observer.bo->inputs_.empty() // does not consume anything
- and productionsite_observer.bo->production_hint_ ==
+ if (site.bo->inputs_.empty() // does not consume anything
+ and site.bo->production_hint_ ==
-1 // not a renewing building (forester...)
- and productionsite_observer.built_time_ +
- 6 * 60 * 1000 <
- game().get_gametime() // > 10 minutes old
- and productionsite->can_start_working() // building is occupied
- and productionsite_observer.bo->space_consumer_ and not
- productionsite_observer.bo->plants_trees_) {
- if (productionsite_observer.bo->cnt_built_ > productionsite_observer.bo->cnt_target_) {
- if (productionsite_observer.bo->stocklevel_time < game().get_gametime() - 5 * 1000) {
- productionsite_observer.bo->stocklevel_ = get_stocklevel(*productionsite_observer.bo);
- productionsite_observer.bo->stocklevel_time = game().get_gametime();
+ and site.unoccupied_till_ +
+ 10 * 60 * 1000 <
+ game().get_gametime() // > 10 minutes old
+ and site.site->can_start_working() // building is occupied
+ and site.bo->space_consumer_ and not site.bo->plants_trees_) {
+
+ // if we have more buildings then target
+ if (site.bo->cnt_built_ > site.bo->cnt_target_) {
+ if (site.bo->stocklevel_time < game().get_gametime() - 5 * 1000) {
+ site.bo->stocklevel_ = get_stocklevel(*site.bo);
+ site.bo->stocklevel_time = game().get_gametime();
}
if (kSpaceDebug)
log(" TDEBUG: considering dismantle of space consumer: %15s, count %2d/T:%2d, stock "
"level:%3d(>100)\n",
- productionsite_observer.bo->name,
- productionsite_observer.bo->cnt_built_,
- productionsite_observer.bo->cnt_target_,
- productionsite_observer.bo->stocklevel_);
+ site.bo->name,
+ site.bo->cnt_built_,
+ site.bo->cnt_target_,
+ site.bo->stocklevel_);
- if (productionsite->get_statistics_percent()<
- 95 and productionsite_observer.bo->stocklevel_> 100) { // production stats == 0%
- productionsite_observer.bo->last_dismantle_time_ = game().get_gametime();
- flags_to_be_removed.push_back(productionsite->base_flag().get_position());
- game().send_player_dismantle(*productionsite);
+ if (site.site->get_statistics_percent()<
+ 30 and site.bo->stocklevel_> 100) { // production stats == 0%
+ site.bo->last_dismantle_time_ = game().get_gametime();
+ flags_to_be_removed.push_back(site.site->base_flag().get_position());
+ game().send_player_dismantle(*site.site);
return true;
}
}
- if (productionsite->get_statistics_percent() <= 20) {
+ // regardless of count of sites a building can be dismanteld if it performs too bad
+ if (site.site->get_statistics_percent() <= 10) {
if (kSpaceDebug)
log(" TDEBUG: dismantling: %15s at %3d x %3d: due to low performance: %2d\n",
- productionsite_observer.bo->name,
- productionsite->get_position().x,
- productionsite->get_position().y,
- productionsite->get_statistics_percent());
+ site.bo->name,
+ site.site->get_position().x,
+ site.site->get_position().y,
+ site.site->get_statistics_percent());
- flags_to_be_removed.push_back(productionsite->base_flag().get_position());
- game().send_player_dismantle(*productionsite);
+ flags_to_be_removed.push_back(site.site->base_flag().get_position());
+ game().send_player_dismantle(*site.site);
return true;
}
@@ -2133,61 +2226,104 @@
}
// buildings with inputs_, checking if we can a dismantle some due to low performance
- if (productionsite_observer.bo->inputs_.size() > 0 and productionsite_observer.bo->cnt_built_ >=
- 3 and productionsite_observer.bo->current_stats_ < 30) {
+ if (site.bo->inputs_.size() > 0 and(site.bo->cnt_built_ - site.bo->unoccupied_) >=
+ 3 and site.site->can_start_working() and site.site->get_statistics_percent() <
+ 20 and // statistics for the building
+ site.bo->current_stats_<30 and // overall statistics
+ (game().get_gametime() - site.unoccupied_till_)> 10 *
+ 60 * 1000) {
if (kIdleDismantle)
log(" kIdleDismantle: dismantling due to too many buildings: %15s at %3d x %3d, total "
- "counts: %2d, stat: %2d\n",
- productionsite_observer.bo->name,
- productionsite->get_position().x,
- productionsite->get_position().y,
- productionsite_observer.bo->cnt_built_,
- productionsite_observer.bo->current_stats_);
- productionsite_observer.bo->last_dismantle_time_ = game().get_gametime();
- flags_to_be_removed.push_back(productionsite->base_flag().get_position());
- game().send_player_dismantle(*productionsite);
+ "count: %2d, stat: %2d/%3d\n",
+ site.bo->name,
+ site.site->get_position().x,
+ site.site->get_position().y,
+ site.bo->cnt_built_,
+ site.site->get_statistics_percent(),
+ site.bo->current_stats_);
+ site.bo->last_dismantle_time_ = game().get_gametime();
+ flags_to_be_removed.push_back(site.site->base_flag().get_position());
+ game().send_player_dismantle(*site.site);
+ return true;
+ }
+
+ // remaining buildings without inputs and not supporting ones (fishers only left probably and
+ // huters)
+ // first if is only for log, second one is "executive"
+ if (kHuntFishDebug and site.bo->inputs_.size() ==
+ 0 and site.site->can_start_working() and not site.bo->space_consumer_ and
+ site.bo->production_hint_ < 0 and site.site->get_statistics_percent() <
+ 50 and((game().get_gametime() - site.unoccupied_till_) > 5 * 60 * 1000)) {
+ if (kIdleDismantle)
+ log(" kIdleDismantle: Fisher+Hunters: considering dismantle due to too low "
+ "utilization: %15s at %3d x %3d, total "
+ " stat: %2d, age: %4d\n",
+ site.bo->name,
+ site.site->get_position().x,
+ site.site->get_position().y,
+ site.site->get_statistics_percent(),
+ (game().get_gametime() - site.unoccupied_till_) / 1000 / 60);
+ }
+ if (site.bo->inputs_.size() ==
+ 0 and site.bo->production_hint_ <
+ 0 and site.site->can_start_working()
+ and not site.bo->space_consumer_ and site.site->get_statistics_percent() <
+ 10 and((game().get_gametime() - site.built_time_) > 10 * 60 * 1000)) {
+ if (kIdleDismantle)
+ log(" kIdleDismantle: dismantling due to too low utilization: %15s at %3d x %3d, total "
+ " stat: %2d, age: %4d\n",
+ site.bo->name,
+ site.site->get_position().x,
+ site.site->get_position().y,
+ site.site->get_statistics_percent(),
+ (game().get_gametime() - site.built_time_) / 1000 / 60);
+ site.bo->last_dismantle_time_ = game().get_gametime();
+ flags_to_be_removed.push_back(site.site->base_flag().get_position());
+ game().send_player_dismantle(*site.site);
return true;
}
// supporting productionsites (rangers)
// stop/start them based on stock avaiable
- if (productionsite_observer.bo->production_hint_ >= 0) {
- if (productionsite_observer.bo->stocklevel_time < game().get_gametime() - 5 * 1000) {
- productionsite_observer.bo->stocklevel_ =
- get_stocklevel_by_hint(productionsite_observer.bo->production_hint_);
- productionsite_observer.bo->stocklevel_time = game().get_gametime();
+ if (site.bo->production_hint_ >= 0) {
+ // if (kStandbyDebug) log (" TDEBUG: check_productionsites(): testing building
+ // %s\n",site.bo->name);
+ if (site.bo->stocklevel_time < game().get_gametime() - 5 * 1000) {
+ site.bo->stocklevel_ = get_stocklevel_by_hint(site.bo->production_hint_);
+ site.bo->stocklevel_time = game().get_gametime();
}
+ uint16_t score = site.bo->stocklevel_;
+
if (kStandbyDebug)
log(" TDEBUG: standby review: %-16s(%dx):stock level: %3d, status: %s\n",
- productionsite_observer.bo->name,
- productionsite_observer.bo->cnt_built_,
- productionsite_observer.bo->stocklevel_,
- productionsite->is_stopped() ? "stopped" : "running");
+ site.bo->name,
+ site.bo->cnt_built_,
+ site.bo->stocklevel_,
+ site.site->is_stopped() ? "stopped" : "running");
- if (productionsite_observer.bo->stocklevel_ > 200 and productionsite_observer.bo->cnt_built_ >
- productionsite_observer.bo->cnt_target_) {
+ if (score > 150 and site.bo->cnt_built_ > site.bo->cnt_target_) {
if (kStandbyDebug)
log(" * dismantling the building\n");
- productionsite_observer.bo->last_dismantle_time_ = game().get_gametime();
- flags_to_be_removed.push_back(productionsite->base_flag().get_position());
- game().send_player_dismantle(*productionsite);
+ site.bo->last_dismantle_time_ = game().get_gametime();
+ flags_to_be_removed.push_back(site.site->base_flag().get_position());
+ game().send_player_dismantle(*site.site);
return true;
}
- if (productionsite_observer.bo->stocklevel_ > 150 and not productionsite->is_stopped()) {
+ if (score > 70 and not site.site->is_stopped()) {
if (kStandbyDebug)
log(" * stopping building\n");
- game().send_player_start_stop_building(*productionsite);
+ game().send_player_start_stop_building(*site.site);
}
- if (productionsite_observer.bo->stocklevel_ < 100 and productionsite->is_stopped()) {
+ if (score < 50 and site.site->is_stopped()) {
if (kStandbyDebug)
log(" * starting building\n");
- game().send_player_start_stop_building(*productionsite);
+ game().send_player_start_stop_building(*site.site);
}
}
@@ -2197,14 +2333,14 @@
// statistics percents are decisive
// do not upgrade if current building is only one in operation
- if ((productionsite_observer.bo->cnt_built_ - productionsite_observer.bo->unoccupied_) <= 1)
+ if ((site.bo->cnt_built_ - site.bo->unoccupied_) <= 1)
return false;
// Check whether building is enhanceable and if wares of the enhanced
// buildings are needed. If yes consider an upgrade.
- std::set<Building_Index> enhancements = productionsite->enhancements();
+ std::set<Building_Index> enhancements = site.site->enhancements();
int32_t maxprio = 0;
- Building_Index enbld = INVALID_INDEX;
+ Building_Index enbld; // to get rid of this
BuildingObserver* bestbld = nullptr;
container_iterate_const(std::set<Building_Index>, enhancements, x) {
// Only enhance buildings that are allowed (scenario mode)
@@ -2222,23 +2358,22 @@
continue;
// don't upgrade without workers
- if (!productionsite->has_workers(*x.current, game()))
+ if (!site.site->has_workers(*x.current, game()))
continue;
// forcing first upgrade
- if ((en_bo.cnt_under_construction_ + en_bo.cnt_built_ + en_bo.unoccupied_) == 0
- and (productionsite_observer.bo->cnt_built_ -
- productionsite_observer.bo->unoccupied_) >= 1
- and (game().get_gametime() - productionsite_observer.built_time_) > 30 * 60 * 1000
- and !mines_.empty()) {
+ if ((en_bo.cnt_under_construction_ + en_bo.cnt_built_ + en_bo.unoccupied_) ==
+ 0 and(site.bo->cnt_built_ - site.bo->unoccupied_) >=
+ 1 and(game().get_gametime() - site.unoccupied_till_) >
+ 30 * 60 * 1000 and mines_.size() > 0) {
if (kUpgradeDebug)
log(" UPGRADE: upgrading (forcing as first) %12s at %3d x %3d: age %d min.\n",
- productionsite_observer.bo->name,
- productionsite->get_position().x,
- productionsite->get_position().y,
- (game().get_gametime() - productionsite_observer.built_time_) / 60000);
+ site.bo->name,
+ site.site->get_position().x,
+ site.site->get_position().y,
+ (game().get_gametime() - site.unoccupied_till_) / 60000);
- game().send_player_enhance_building(*productionsite, (*x.current));
+ game().send_player_enhance_building(*site.site, (*x.current));
return true;
}
@@ -2260,16 +2395,15 @@
int32_t prio = 0;
if (en_bo.current_stats_ > 65) {
- prio = en_bo.current_stats_ -
- productionsite_observer.bo->current_stats_; // priority for enhancement
+ prio = en_bo.current_stats_ - site.bo->current_stats_; // priority for enhancement
prio += en_bo.current_stats_ - 65;
if (kUpgradeDebug)
log(" UPGRADE: proposing upgrade (non-first building) %12s at %3d x %3d: prio: "
"%2d, target statistics: %2d\n",
- productionsite_observer.bo->name,
- productionsite->get_position().x,
- productionsite->get_position().y,
+ site.bo->name,
+ site.site->get_position().x,
+ site.site->get_position().y,
prio,
en_bo.current_stats_);
}
@@ -2288,7 +2422,7 @@
if (kUpgradeDebug)
log(" UPGRADE: upgrading %15s(as non first)\n", bestbld->name);
- game().send_player_enhance_building(*productionsite, enbld);
+ game().send_player_enhance_building(*site.site, enbld);
bestbld->construction_decision_time_ = gametime;
changed = true;
}
@@ -2307,34 +2441,40 @@
return false;
next_mine_check_due_ = gametime + 10000; // 10 seconds is enough
+ // Reorder and set new values; - due to returns within the function
+ mines_.push_back(mines_.front());
+ mines_.pop_front();
// also statistics must be recalculated
// Get link to productionsite that should be checked
- ProductionSiteObserver& productionsite_observer = mines_.front();
- mines_.pop_front();
-
- ProductionSite* mine = productionsite_observer.site.get(game());
- if (!mine) {
- // Building has vanished.
- return false;
- }
-
+ ProductionSiteObserver& site = mines_.front();
Map& map = game().map();
- Field* field = map.get_fcoords(mine->get_position()).field;
- // Reorder and set new values; - due to returns within the function
- mines_.push_back(productionsite_observer);
+ Field* field = map.get_fcoords(site.site->get_position()).field;
if (kMinesUpdateDebug)
log(" MINES_UPDATE: %1d: reviewing %-15s at %3dx%3d, statistics: %3d, left resources: %2d\n",
player_number(),
- productionsite_observer.bo->name,
- mine->get_position().x,
- mine->get_position().y,
- mine->get_statistics_percent(),
+ site.bo->name,
+ site.site->get_position().x,
+ site.site->get_position().y,
+ site.site->get_statistics_percent(),
field->get_resources_amount());
+ // first get rid of mines that are missing workers for some time (5 minutes)
+ // released worker (if any) can be usefull elsewhere !
+ if (site.built_time_ + 5 * 60 * 1000 < gametime and not site.site->can_start_working()) {
+ if (kMinesUpdateDebug)
+ log(" MINES_UPDATE: Dismantling due to missing workers: %12s at %3d %3d\n",
+ site.bo->name,
+ site.site->get_position().x,
+ site.site->get_position().y);
+ flags_to_be_removed.push_back(site.site->base_flag().get_position());
+ game().send_player_dismantle(*site.site);
+ return true;
+ }
+
// It takes some time till performance gets to 0
// so I use 40% as a limit to check if there are some resources left
- if (mine->get_statistics_percent() > 40)
+ if (site.site->get_statistics_percent() > 40)
return false;
// Check if mine ran out of resources
@@ -2344,8 +2484,8 @@
// destruct the building and it's flag (via flag destruction)
// the destruction of the flag avoids that defaultAI will have too many
// unused roads - if needed the road will be rebuild directly.
- flags_to_be_removed.push_back(mine->base_flag().get_position());
- game().send_player_dismantle(*mine);
+ flags_to_be_removed.push_back(site.site->base_flag().get_position());
+ game().send_player_dismantle(*site.site);
if (kMinesUpdateDebug)
log(" MINES_UPDATE: Dismantling...\n");
@@ -2354,9 +2494,9 @@
}
// Check whether building is enhanceable. If yes consider an upgrade.
- std::set<Building_Index> enhancements = mine->enhancements();
+ std::set<Building_Index> enhancements = site.site->enhancements();
int32_t maxprio = 0;
- Building_Index enbld = INVALID_INDEX;
+ Building_Index enbld;
BuildingObserver* bestbld = nullptr;
bool changed = false;
container_iterate_const(std::set<Building_Index>, enhancements, x) {
@@ -2387,8 +2527,8 @@
continue;
// Check if mine needs an enhancement to mine more resources
- uint8_t const until = field->get_starting_res_amount() *
- (100 - productionsite_observer.bo->mines_percent_) / 100;
+ uint8_t const until =
+ field->get_starting_res_amount() * (100 - site.bo->mines_percent_) / 100;
if (kMinesUpdateDebug)
log(" MINES_UPDATE: until:%3d ?>, current: %3d\n", until, current);
@@ -2412,7 +2552,7 @@
// Enhance if enhanced building is useful
if (maxprio > 0) {
- game().send_player_enhance_building(*mine, enbld);
+ game().send_player_enhance_building(*site.site, enbld);
bestbld->construction_decision_time_ = gametime;
changed = true;
@@ -2420,9 +2560,6 @@
log(" MINES_UPDATE: ..enhancing\n");
}
- //// Reorder and set new values;
- // mines_.push_back(mines_.front());
- // mines_.pop_front();
return changed;
}
@@ -2439,7 +2576,7 @@
}
if (kStockDebug)
- log(" TDEBUG: stock : %3u for hint: %2" PRIuS ", time: %3d\n",
+ log(" TDEBUG: stock : %3d for hint: %2d, time: %3d\n",
count,
hintoutput,
game().get_gametime() / 1000);
@@ -2518,10 +2655,12 @@
uint32_t const vision = ms->vision_range();
FCoords f = map.get_fcoords(ms->get_position());
// look if there is any enemy land nearby
- FindNodeEnemy find_enemy(player, game());
+ // FindNodeEnemy find_enemy(player, game());
+ // look if there is any enemies building
+ FindNodeEnemiesBuilding find_enemy(player, game());
- // first if there are enemies nearby
- if (map.find_fields(Area<FCoords>(f, vision), nullptr, find_enemy) == 0) {
+ // first if there are enemies nearby, check for buildings not land
+ if (map.find_fields(Area<FCoords>(f, vision + 2), nullptr, find_enemy) == 0) {
// If no enemy in sight - decrease the number of stationed soldiers
// as long as it is > 1 - BUT take care that there is a warehouse in the
// same economy where the thrown out soldiers can go to.
@@ -2579,10 +2718,11 @@
uint32_t const k = ms->soldierCapacity();
if (j > k)
- game().send_player_change_soldier_capacity(*ms, j - k);
+ // game().send_player_change_soldier_capacity(*ms, j - k);
- if (MilitarySite::kPrefersHeroes != ms->get_soldier_preference())
- game().send_player_militarysite_set_soldier_preference(*ms, MilitarySite::kPrefersHeroes);
+ if (MilitarySite::kPrefersHeroes != ms->get_soldier_preference())
+ game().send_player_militarysite_set_soldier_preference(
+ *ms, MilitarySite::kPrefersHeroes);
changed = true;
}
@@ -2606,7 +2746,7 @@
*/
int32_t DefaultAI::recalc_with_border_range(const BuildableField& bf, int32_t prio) {
// Prefer building space in the inner land.
- prio /= (1 + (bf.unowned_land_nearby_ / 4));
+ // prio /= (1 + (bf.unowned_land_nearby_ / 4));
if (bf.unowned_land_nearby_ > 15)
prio -= (bf.unowned_land_nearby_ - 15);
@@ -2700,7 +2840,7 @@
return economies.front();
}
-/// \returns the building observer
+// \returns the building observer
BuildingObserver& DefaultAI::get_building_observer(char const* const name) {
if (tribe == nullptr)
late_initialization();
@@ -2712,7 +2852,7 @@
throw wexception("Help: I do not know what to do with a %s", name);
}
-/// this is called whenever we gain ownership of a PlayerImmovable
+// this is called whenever we gain ownership of a PlayerImmovable
void DefaultAI::gain_immovable(PlayerImmovable& pi) {
if (upcast(Building, building, &pi))
gain_building(*building);
@@ -2722,7 +2862,7 @@
roads.push_front(road);
}
-/// this is called whenever we lose ownership of a PlayerImmovable
+// this is called whenever we lose ownership of a PlayerImmovable
void DefaultAI::lose_immovable(const PlayerImmovable& pi) {
if (upcast(Building const, building, &pi))
lose_building(*building);
@@ -2745,7 +2885,7 @@
roads.remove(road);
}
-/// this is called whenever we gain a new building
+// this is called whenever we gain a new building
void DefaultAI::gain_building(Building& b) {
BuildingObserver& bo = get_building_observer(b.name().c_str());
@@ -2764,6 +2904,7 @@
productionsites.back().site = &ref_cast<ProductionSite, Building>(b);
productionsites.back().bo = &bo;
productionsites.back().built_time_ = game().get_gametime();
+ productionsites.back().unoccupied_till_ = game().get_gametime();
productionsites.back().stats_zero_ = 0;
for (uint32_t i = 0; i < bo.outputs_.size(); ++i)
@@ -2775,6 +2916,7 @@
mines_.push_back(ProductionSiteObserver());
mines_.back().site = &ref_cast<ProductionSite, Building>(b);
mines_.back().bo = &bo;
+ mines_.back().built_time_ = game().get_gametime();
for (uint32_t i = 0; i < bo.outputs_.size(); ++i)
++wares.at(bo.outputs_.at(i)).producers_;
@@ -2786,16 +2928,18 @@
militarysites.back().site = &ref_cast<MilitarySite, Building>(b);
militarysites.back().bo = &bo;
militarysites.back().checks = bo.desc->get_size();
+ militarysites.back().enemies_nearby = true;
} else if (bo.type == BuildingObserver::WAREHOUSE)
++numof_warehouses_;
}
}
-/// this is called whenever we lose a building
+// this is called whenever we lose a building
void DefaultAI::lose_building(const Building& b) {
BuildingObserver& bo = get_building_observer(b.name().c_str());
if (bo.type == BuildingObserver::CONSTRUCTIONSITE) {
+ // log (" TDEBUG: We lost constructionsite\n");
BuildingObserver& target_bo = get_building_observer(
ref_cast<ConstructionSite const, Building const>(b).building().name().c_str());
--target_bo.cnt_under_construction_;
@@ -2804,10 +2948,13 @@
--bo.cnt_built_;
if (bo.type == BuildingObserver::PRODUCTIONSITE) {
+
+ // log (" TDEBUG: We lost productionsite: %s\n",b.name().c_str());
+
for (std::list<ProductionSiteObserver>::iterator i = productionsites.begin();
i != productionsites.end();
++i)
- if (i->site.get(game()) == &b) {
+ if (i->site == &b) {
productionsites.erase(i);
break;
}
@@ -2820,7 +2967,7 @@
} else if (bo.type == BuildingObserver::MINE) {
for (std::list<ProductionSiteObserver>::iterator i = mines_.begin(); i != mines_.end();
++i)
- if (i->site.get(game()) == &b) {
+ if (i->site == &b) {
mines_.erase(i);
break;
}
@@ -2848,8 +2995,8 @@
m_mineable_changed = true;
}
-/// Checks that supply line exists for given building.
-/// Recurcsively verify that all inputs_ have a producer.
+// Checks that supply line exists for given building.
+// Recurcsively verify that all inputs_ have a producer.
// TODO: this function leads to periodic freezes of ~1 second on big games on my system.
// TODO: It needs profiling and optimization.
// NOTE: This is not needed anymore and it seems it is not missed neither
@@ -2881,76 +3028,226 @@
if (militarysites.empty())
return false;
- Map& map = game().map();
+ // First we iterate over all players and define which ones (if any)
+ // are attackable (comparing overal strength)
+ // counting players in game
+ uint32_t plr_in_game = 0;
+ std::vector<bool> player_attackable;
+ Player_Number const nr_players = game().map().get_nrplayers();
+ player_attackable.resize(nr_players);
+ bool any_attackable = false;
+ bool any_attacked = false;
uint16_t const pn = player_number();
- // Check next militarysite
- MilitarySite* ms = militarysites.front().site;
- uint32_t const vision = ms->vision_range();
- FCoords f = map.get_fcoords(ms->get_position());
- Building* target = ms; // dummy initialisation to silence the compiler
- int32_t chance = 0;
- uint32_t attackers = 0;
- // Search in a radius of the vision of the militarysite and collect
- // information about immovables in the area
- std::vector<ImmovableFound> immovables;
- map.find_immovables(Area<FCoords>(f, vision), &immovables, FindImmovableAttackable());
-
- for (uint32_t j = 0; j < immovables.size(); ++j)
- if (upcast(MilitarySite, bld, immovables.at(j).object)) {
- if (!player->is_hostile(bld->owner()))
- continue;
-
- if (bld->canAttack()) {
- int32_t ta = player->findAttackSoldiers(bld->base_flag());
-
- if (type == NORMAL)
- ta = ta * 2 / 3;
-
- if (ta < 1)
- continue;
-
- int32_t const tc = ta - bld->presentSoldiers().size();
-
- if (tc > chance) {
- target = bld;
- chance = tc;
- attackers = ta;
- }
- }
- } else if (upcast(Warehouse, wh, immovables.at(j).object)) {
- if (!player->is_hostile(wh->owner()))
- continue;
-
- if (wh->canAttack()) {
- int32_t ta = player->findAttackSoldiers(wh->base_flag());
-
- if (ta < 1)
- continue;
-
- // extra priority push!
- int32_t tc = ta * 2;
-
- if (tc > chance) {
- target = wh;
- chance = tc;
- attackers = ta;
- }
- }
- }
-
- // Reenque militarysite at the end of list
- militarysites.push_back(militarysites.front());
- militarysites.pop_front();
-
- // Return if chance to win is too low
- if (chance < 3) {
- next_attack_consideration_due_ = gametime % 7 * 1000 + gametime;
+
+ // defining treshold ratio of own_strenght/enemy's_strength
+ uint32_t treshold_ratio = 100;
+ if (type == AGGRESSIVE)
+ treshold_ratio = 80;
+ if (type == DEFENSIVE)
+ treshold_ratio = 120;
+
+ iterate_players_existing_novar(p, nr_players, game())++ plr_in_game;
+
+ // receiving games statistics and parsing it (reading latest entry)
+ const Game::General_Stats_vector& genstats = game().get_general_statistics();
+ for (uint8_t j = 1; j <= plr_in_game; ++j) {
+ if (pn == j) {
+ player_attackable[j - 1] = false;
+ continue;
+ }
+
+ if (genstats[j - 1].miltary_strength.back() == 0) {
+ // to avoid improbable zero division
+ player_attackable[j - 1] = true;
+ any_attackable = true;
+ } else if ((genstats[pn - 1].miltary_strength.back() * 100 /
+ genstats[j - 1].miltary_strength.back()) > treshold_ratio) {
+ player_attackable[j - 1] = true;
+ any_attackable = true;
+ } else {
+ player_attackable[j - 1] = false;
+ }
+ if (kAttackDebug)
+ log(" %2d: %s player %2d (strength: pl: %3d vs en: %3d))\n",
+ pn,
+ player_attackable[j - 1] ? "can attack" : "can not attack",
+ j,
+ genstats[pn - 1].miltary_strength.back(),
+ genstats[j - 1].miltary_strength.back());
+ }
+
+ if (not any_attackable) {
+ if (kAttackDebug)
+ log(" %2d: No attackable enemy... returning...\n", pn);
+ next_attack_consideration_due_ = 120 * 1000 + (gametime % 30 + 2) * 1000 + gametime;
return false;
}
- // Attack the selected target.
- game().send_player_enemyflagaction(target->base_flag(), pn, attackers);
+ // the logic of attacking is to pick n military buildings - random ones
+ // and test them for possible attack
+ const uint16_t attempts = militarysites.size() / 6 + 1;
+ Map& map = game().map();
+
+ uint16_t position = 0;
+ for (uint32_t i = 0; i < attempts && not any_attacked; ++i) {
+ position = (game().get_gametime() + (3 * i)) % militarysites.size();
+
+ if (kAttackDebug)
+ log(" %2d: Attack consideration #%1d: picking building: %2d/%2d\n",
+ pn,
+ i + 1,
+ position,
+ militarysites.size());
+
+ // picking random military sites
+ // using gametime as a random value, but it is constant so each next is on position +3
+ // iterating over fields
+ // (std::vector would be much better here)
+
+ std::list<MilitarySiteObserver>::iterator mso = militarysites.begin();
+ std::advance(mso, position);
+
+ MilitarySite* ms = mso->site;
+ Building* target = ms; // dummy initialisation to silence the compiler
+ uint32_t const vision = ms->vision_range();
+ FCoords f = map.get_fcoords(ms->get_position());
+ int32_t chance = 0;
+ uint32_t attackers = 0;
+ uint32_t defenders = 0;
+ uint32_t defend_ready_enemies = 0; // enemy soldiers that can come to defend the attacked
+ // building (one soldier has to stay)
+ // uint8_t retreat = ms->owner().get_retreat_percentage();
+
+ // skipping if based on "enemies nearby" there are probably no enemies nearby
+ if (not mso->enemies_nearby and gametime % 8 > 0) {
+ if (kAttackDebug)
+ log(" %2d: Skipping consideration due to enemies_nearby set to false\n", pn);
+ continue; // go on with next attempt
+ }
+ if (kAttackDebug)
+ log(" %2d: Scanning nearby buildings\n", pn);
+
+ // setting as default
+ mso->enemies_nearby = false;
+
+ // Search in a radius of the vision of the militarysite and collect
+ // information about immovables in the area
+ std::vector<ImmovableFound> immovables;
+ map.find_immovables(Area<FCoords>(f, vision), &immovables, FindImmovableAttackable());
+
+ for (uint32_t j = 0; j < immovables.size(); ++j) {
+ if (upcast(MilitarySite, bld, immovables.at(j).object)) {
+ if (!player->is_hostile(bld->owner()))
+ continue;
+
+ mso->enemies_nearby = true;
+
+ if (not player_attackable[bld->owner().player_number() - 1]) {
+ if (kAttackDebug)
+ log(" %2d: building of player %2d, not attackable... \n",
+ pn,
+ bld->owner().player_number());
+ continue;
+ }
+
+ if (bld->canAttack()) {
+
+ // any_attackable_building=true;
+
+ int32_t ta = player->findAttackSoldiers(bld->base_flag());
+
+ if (type == NORMAL)
+ ta = ta * 2 / 3;
+
+ if (ta < 1)
+ continue;
+
+ int32_t const tc = ta - bld->presentSoldiers().size();
+
+ if (bld->presentSoldiers().size() > 1)
+ defend_ready_enemies += bld->presentSoldiers().size() - 1;
+
+ if (tc > chance) {
+ target = bld;
+ chance = tc;
+ attackers = ta;
+ defenders = bld->presentSoldiers().size();
+ }
+ } else if (kAttackDebug)
+ log(" %2d: building of player %2d, considering for attack \n",
+ pn,
+ bld->owner().player_number());
+ } else if (upcast(Warehouse, wh, immovables.at(j).object)) {
+ if (!player->is_hostile(wh->owner()))
+ continue;
+
+ if (wh->canAttack()) {
+ int32_t ta = player->findAttackSoldiers(wh->base_flag());
+
+ if (ta < 1)
+ continue;
+
+ // extra priority push!
+ int32_t tc = ta * 2;
+
+ // we presume that there are no soldiers in warehouse
+ // after long fights this tend to be true :)
+
+ if (tc > chance) {
+ target = wh;
+ chance = tc;
+ attackers = ta;
+ defenders = 0;
+ }
+ }
+ }
+
+ // here we consider enemy soldiers in near buildings.
+ int32_t penalty;
+ if (defend_ready_enemies > 0)
+ penalty = (defenders * 100) / 5 * (defend_ready_enemies * 100) / 10 * 10 / 100;
+ else
+ penalty = 0;
+
+ // Return if chance to win is too low
+ if ((chance - penalty / 100) < 2) {
+ continue;
+ }
+
+ if (kAttackDebug)
+ log(" Player %1d attacking %3dx%3d, chance: %2d-%2d, attackers: %2d, "
+ "station.defenders: %2d, "
+ "nearby defenders: %2d, vision: %d \n",
+ pn,
+ target->base_flag().get_position().x,
+ target->base_flag().get_position().y,
+ chance,
+ penalty / 100,
+ attackers,
+ defenders,
+ defend_ready_enemies,
+ vision);
+
+ game().send_player_enemyflagaction(target->base_flag(), pn, attackers);
+
+ any_attacked = true;
+ break;
+ }
+ }
+
+ if (kAttackDebug)
+ log(" %2d: Attacked any?: %s\n", pn, any_attacked ? "Y" : "N");
+
// Do not attack again too soon - returning soldiers must get healed first.
- next_attack_consideration_due_ = (gametime % 51 + 10) * 1000 + gametime;
- return true;
+ if (any_attacked)
+ next_attack_consideration_due_ = (gametime % 40 + 10) * 1000 + gametime;
+ else {
+ next_attack_consideration_due_ = (gametime % 80 + 10) * 1000 + gametime;
+ }
+
+ if (any_attacked)
+ return true;
+ else {
+ return false;
+ }
}
=== modified file 'src/graphic/animation.cc'
--- src/graphic/animation.cc 2014-07-05 14:22:44 +0000
+++ src/graphic/animation.cc 2014-07-08 19:41:26 +0000
@@ -292,13 +292,21 @@
// opengl texture.
const Image* pc_image = g_gr->images().get(filename);
if (frames_[0]->width() != pc_image->width() or frames_[0]->height() != pc_image->height()) {
- throw wexception("playercolor mask has wrong size: (%u, %u), should "
- "be (%u, %u) like the animation frame",
- pc_image->width(),
- pc_image->height(),
- frames_[0]->width(),
- frames_[0]->height());
- }
+ //there was throw wexeption, it crashes game. Consider it when commiting.
+ log("ANIMATION ERROR: playercolor mask has wrong size: (%s: %u, %u), should "
+ "be (%u, %u) like the animation frame\n",
+ filename.c_str(), pc_image->width(), pc_image->height(),
+ frames_[0]->width(), frames_[0]->height());
+ hasplrclrs_ = false;
+ break;
+ }
+ //throw wexception("playercolor mask has wrong size: (%u, %u), should "
+ //"be (%u, %u) like the animation frame",
+ //pc_image->width(),
+ //pc_image->height(),
+ //frames_[0]->width(),
+ //frames_[0]->height());
+ //}
pcmasks_.push_back(pc_image);
}
}
=== modified file 'src/logic/findbob.cc'
--- src/logic/findbob.cc 2014-07-03 19:26:30 +0000
+++ src/logic/findbob.cc 2014-07-08 19:41:26 +0000
@@ -47,4 +47,10 @@
return bob->get_bob_type() == Bob::SHIP;
}
+bool FindBobCritter::accept(Bob * bob) const
+{
+ return bob->get_bob_type() == Bob::CRITTER;
+}
+
+
} // namespace Widelands
=== modified file 'src/logic/findbob.h'
--- src/logic/findbob.h 2014-07-05 16:41:51 +0000
+++ src/logic/findbob.h 2014-07-08 19:41:26 +0000
@@ -51,6 +51,10 @@
virtual bool accept(Bob * bob) const override;
};
+struct FindBobCritter : FindBob {
+ virtual bool accept(Bob * bob) const override;
+};
+
} // namespace Widelands
=== modified file 'src/logic/player.cc'
--- src/logic/player.cc 2014-07-05 14:22:44 +0000
+++ src/logic/player.cc 2014-07-08 19:41:26 +0000
@@ -447,9 +447,6 @@
if (BaseImmovable * const imm = fc.field->get_immovable())
if (imm->get_size() >= BaseImmovable::SMALL) {
- log
- ("%i: building road, immovable in the way, type=%d\n",
- player_number(), imm->get_type());
return nullptr;
}
if (!(get_buildcaps(fc) & MOVECAPS_WALK)) {
=== modified file 'tribes/atlanteans/bakery/conf'
--- tribes/atlanteans/bakery/conf 2014-07-03 20:06:38 +0000
+++ tribes/atlanteans/bakery/conf 2014-07-08 19:41:26 +0000
@@ -3,6 +3,7 @@
[aihints]
build_material=false
+is_food_basic=true
[buildcost]
log=2
=== modified file 'tribes/atlanteans/castle/conf'
--- tribes/atlanteans/castle/conf 2014-03-17 17:23:26 +0000
+++ tribes/atlanteans/castle/conf 2014-07-08 19:41:26 +0000
@@ -25,3 +25,9 @@
[idle]
pics=castle_i_??.png
hotspot=91 91
+
+[aihints]
+expansion=true
+fighting=true
+mountain_conqueror=true
+
=== modified file 'tribes/atlanteans/guardhall/conf'
--- tribes/atlanteans/guardhall/conf 2014-03-17 17:23:26 +0000
+++ tribes/atlanteans/guardhall/conf 2014-07-08 19:41:26 +0000
@@ -23,3 +23,6 @@
[idle]
pics=guardhall_i_??.png
hotspot=58 72
+
+[aihints]
+fighting=true
=== modified file 'tribes/atlanteans/guardhouse/conf'
--- tribes/atlanteans/guardhouse/conf 2014-03-17 17:23:26 +0000
+++ tribes/atlanteans/guardhouse/conf 2014-07-08 19:41:26 +0000
@@ -20,3 +20,7 @@
[idle]
pics=guardhouse_i_??.png
hotspot=33 41
+
+[aihints]
+expansion=true
+mountain_conqueror=true
=== modified file 'tribes/atlanteans/small_tower/conf'
--- tribes/atlanteans/small_tower/conf 2014-03-17 17:23:26 +0000
+++ tribes/atlanteans/small_tower/conf 2014-07-08 19:41:26 +0000
@@ -22,3 +22,6 @@
[idle]
pics=small_tower_i_??.png
hotspot=42 65
+
+[aihints]
+fighting=true
=== modified file 'tribes/atlanteans/smokery/conf'
--- tribes/atlanteans/smokery/conf 2014-07-02 16:36:07 +0000
+++ tribes/atlanteans/smokery/conf 2014-07-08 19:41:26 +0000
@@ -15,7 +15,7 @@
[aihints]
build_material=false
-is_basic=true
+is_food_basic=true
[working positions]
smoker=1
=== modified file 'tribes/atlanteans/tower/conf'
--- tribes/atlanteans/tower/conf 2014-03-17 17:23:26 +0000
+++ tribes/atlanteans/tower/conf 2014-07-08 19:41:26 +0000
@@ -25,3 +25,7 @@
[idle]
pics=tower_i_??.png
hotspot=55 60
+
+[aihints]
+expansion=true
+mountain_conqueror=true
=== modified file 'tribes/atlanteans/weaving-mill/conf'
--- tribes/atlanteans/weaving-mill/conf 2014-07-02 16:36:07 +0000
+++ tribes/atlanteans/weaving-mill/conf 2014-07-08 19:41:26 +0000
@@ -57,6 +57,10 @@
pics=weaving_mill_i_??.png # ???
hotspot=65 69
+[aihints]
+is_basic=true
+
[working]
pics=weaving_mill_i_??.png # ???
hotspot=65 69
+
=== modified file 'tribes/barbarians/donjon/conf'
--- tribes/barbarians/donjon/conf 2014-03-17 17:23:26 +0000
+++ tribes/barbarians/donjon/conf 2014-07-08 19:41:26 +0000
@@ -32,3 +32,8 @@
[unoccupied]
pics=donjon_u_??.png
hotspot=48 84
+
+[aihints]
+expansion=true
+fighting=true
+mountain_conqueror=true
=== modified file 'tribes/barbarians/fortress/conf'
--- tribes/barbarians/fortress/conf 2014-03-17 17:23:26 +0000
+++ tribes/barbarians/fortress/conf 2014-07-08 19:41:26 +0000
@@ -34,3 +34,8 @@
pics=fortress_i_??.png
hotspot=103 80
fps=10
+
+[aihints]
+expansion=true
+fighting=true
+mountain_conqueror=true
=== modified file 'tribes/barbarians/sentry/conf'
--- tribes/barbarians/sentry/conf 2014-03-17 17:23:26 +0000
+++ tribes/barbarians/sentry/conf 2014-07-08 19:41:26 +0000
@@ -27,3 +27,8 @@
[unoccupied]
pics=sentry_u_??.png
hotspot=39 40
+
+[aihints]
+expansion=true
+fighting=true
+mountain_conqueror=true
=== modified file 'tribes/barbarians/tavern/conf'
--- tribes/barbarians/tavern/conf 2014-07-03 20:06:38 +0000
+++ tribes/barbarians/tavern/conf 2014-07-08 19:41:26 +0000
@@ -15,6 +15,7 @@
[aihints]
build_material=false
+is_food_basic=true
[working positions]
innkeeper=1
=== modified file 'tribes/empire/barrier/conf'
--- tribes/empire/barrier/conf 2014-03-17 17:23:26 +0000
+++ tribes/empire/barrier/conf 2014-07-08 19:41:26 +0000
@@ -35,3 +35,6 @@
[idle]
pics=barrier_i_??.png
hotspot=49 77
+
+[aihints]
+fighting=true
=== modified file 'tribes/empire/brewery/conf'
--- tribes/empire/brewery/conf 2014-07-03 20:06:38 +0000
+++ tribes/empire/brewery/conf 2014-07-08 19:41:26 +0000
@@ -3,6 +3,7 @@
[aihints]
build_material=false
+is_food_basic=true
[buildcost]
log=1
=== modified file 'tribes/empire/farm/conf'
--- tribes/empire/farm/conf 2014-03-10 10:45:21 +0000
+++ tribes/empire/farm/conf 2014-07-08 19:41:26 +0000
@@ -3,6 +3,7 @@
[aihints]
space_consumer=true
+is_food_basic=true
[buildcost]
wood=2
=== modified file 'tribes/empire/fortress/conf'
--- tribes/empire/fortress/conf 2014-03-17 06:13:24 +0000
+++ tribes/empire/fortress/conf 2014-07-08 19:41:26 +0000
@@ -33,3 +33,7 @@
pics=fortress_b_??.png
hotspot=90 105
+[aihints]
+expansion=true
+fighting=true
+mountain_conqueror=true
=== modified file 'tribes/empire/outpost/conf'
--- tribes/empire/outpost/conf 2014-03-17 06:13:24 +0000
+++ tribes/empire/outpost/conf 2014-07-08 19:41:26 +0000
@@ -24,3 +24,6 @@
[idle]
pics=outpost_i_??.png
hotspot=57 77
+
+[aihints]
+expansion=true
=== modified file 'tribes/empire/sentry/conf'
--- tribes/empire/sentry/conf 2014-03-17 17:23:26 +0000
+++ tribes/empire/sentry/conf 2014-07-08 19:41:26 +0000
@@ -30,3 +30,8 @@
[idle]
pics=sentry_i_??.png
hotspot=37 60
+
+[aihints]
+expansion=true
+fighting=true
+mountain_conqueror=true
=== modified file 'tribes/empire/tavern/conf'
--- tribes/empire/tavern/conf 2014-07-03 20:06:38 +0000
+++ tribes/empire/tavern/conf 2014-07-08 19:41:26 +0000
@@ -14,6 +14,7 @@
[aihints]
build_material=false
+is_food_basic=true
[working positions]
innkeeper=1
=== modified file 'tribes/empire/tower/conf'
--- tribes/empire/tower/conf 2014-03-17 06:13:24 +0000
+++ tribes/empire/tower/conf 2014-07-08 19:41:26 +0000
@@ -29,3 +29,6 @@
[build]
pics=tower_b_??.png
hotspot=53 81
+
+[aihints]
+mountain_conqueror=true
=== modified file 'tribes/empire/vineyard/conf'
--- tribes/empire/vineyard/conf 2014-03-16 20:55:15 +0000
+++ tribes/empire/vineyard/conf 2014-07-08 19:41:26 +0000
@@ -5,6 +5,7 @@
space_consumer=true
is_basic=true
build_material=false
+is_food_basic=true
[buildcost]
wood=2
=== modified file 'tribes/empire/winery/conf'
--- tribes/empire/winery/conf 2013-07-23 19:04:12 +0000
+++ tribes/empire/winery/conf 2014-07-08 19:41:26 +0000
@@ -3,6 +3,7 @@
[aihints]
build_material=false
+is_food_basic=true
[buildcost]
wood=1
Follow ups