widelands-dev team mailing list archive
-
widelands-dev team
-
Mailing list archive
-
Message #03716
[Merge] lp:~widelands-dev/widelands/ai-enhancements into lp:widelands
TiborB has proposed merging lp:~widelands-dev/widelands/ai-enhancements into lp:widelands.
Requested reviews:
Widelands Developers (widelands-dev)
Related bugs:
Bug #1395521 in widelands: "[7237][7261] AI is too eager to raze newly conquered buildings"
https://bugs.launchpad.net/widelands/+bug/1395521
Bug #1421997 in widelands: "Shipcontrols doesn' t work correctly"
https://bugs.launchpad.net/widelands/+bug/1421997
For more details, see:
https://code.launchpad.net/~widelands-dev/widelands/ai-enhancements/+merge/250207
This is quick fix after seafaring branch merge. I fixed GUI control of ships. There was suggestion by SirVer to add a regression test for it, but I see that LUA api for control a ship movement is needed, so this would be separate job - making LUA interface to navigate the ship and prepare a test for this functionality.
To fix a bug about dismantling unconnected and occupied military buildings - I have to make deeper changes to the code, but I think now it is better.
Also, I changed the way how AI finds about portspaces - now it is bit cleaner...
There is one significant outstanding feature - to teach AI where ports and shipyards can be placed to be close to a "big water" - now AI is quite stupid about it...
--
Your team Widelands Developers is requested to review the proposed merge of lp:~widelands-dev/widelands/ai-enhancements into lp:widelands.
=== modified file 'src/ai/ai_help_structs.h'
--- src/ai/ai_help_structs.h 2015-02-16 13:10:35 +0000
+++ src/ai/ai_help_structs.h 2015-02-18 20:34:30 +0000
@@ -40,6 +40,8 @@
class ProductionSite;
class MilitarySite;
+enum class ExtendedBool : uint8_t {kUnset, kTrue, kFalse };
+
struct CheckStepRoadAI {
CheckStepRoadAI(Player* const pl, uint8_t const mc, bool const oe)
: player_(pl), movecaps_(mc), open_end_(oe) {
@@ -129,14 +131,13 @@
struct FindNodeMineable {
bool accept(const Map&, const FCoords& fc) const {
- return (fc.field->nodecaps() & BUILDCAPS_MINE) &&
- (fc.field->get_resources() == res);
+ return (fc.field->nodecaps() & BUILDCAPS_MINE) && (fc.field->get_resources() == res);
}
Game& game;
int32_t res;
- FindNodeMineable(Game& g, int32_t r) : game(g), res(r) {
+ FindNodeMineable(Game& g, int32_t r) : game(g), res(r) {
}
};
@@ -248,6 +249,7 @@
bool is_portspace_;
bool port_nearby_; // to increase priority if a port is nearby,
// especially for new colonies
+ Widelands::ExtendedBool portspace_nearby_; // prefer military buildings closer to the portspace
std::vector<uint8_t> consumers_nearby_;
std::vector<uint8_t> producers_nearby_;
@@ -259,6 +261,7 @@
enemy_nearby_(0),
unowned_land_nearby_(0),
near_border_(false),
+ unowned_mines_pots_nearby_(0),
trees_nearby_(0),
// explanation of starting values
// this is done to save some work for AI (CPU utilization)
@@ -279,8 +282,10 @@
military_in_constr_nearby_(0),
military_presence_(0),
military_stationed_(0),
+ military_unstationed_(0),
is_portspace_(false),
- port_nearby_(false) {
+ port_nearby_(false),
+ portspace_nearby_(Widelands::ExtendedBool::kUnset) {
}
};
@@ -292,24 +297,27 @@
bool preferred_;
int32_t mines_nearby_;
- //this is to provide that a mine is not built on the edge of mine area
+ // this is to provide that a mine is not built on the edge of mine area
int32_t same_mine_fields_nearby_;
MineableField(const Widelands::FCoords& fc)
- : coords(fc), next_update_due_(0), preferred_(false), mines_nearby_(0),
- same_mine_fields_nearby_(0) {
+ : coords(fc),
+ next_update_due_(0),
+ preferred_(false),
+ mines_nearby_(0),
+ same_mine_fields_nearby_(0) {
}
};
struct EconomyObserver {
Widelands::Economy& economy;
std::list<Widelands::Flag const*> flags;
- int32_t next_connection_try;
- uint32_t failed_connection_tries;
+ int32_t dismantle_grace_time_;
EconomyObserver(Widelands::Economy& e) : economy(e) {
- next_connection_try = 0;
- failed_connection_tries = 0;
+ // next_connection_try = 0;
+ // failed_connection_tries = 0;
+ dismantle_grace_time_ = std::numeric_limits<int32_t>::max();
}
};
=== modified file 'src/ai/defaultai.cc'
--- src/ai/defaultai.cc 2015-02-05 12:11:20 +0000
+++ src/ai/defaultai.cc 2015-02-18 20:34:30 +0000
@@ -67,7 +67,7 @@
constexpr int kMarineDecisionInterval = 20 * 1000;
constexpr int kTrainingSitesCheckInterval = 30 * 1000;
-//this is intended for map developers, by default should be off
+// this is intended for map developers, by default should be off
constexpr bool kPrintStats = false;
// Some buildings have to be built close to borders and their
@@ -100,8 +100,8 @@
next_productionsite_check_due_(0),
next_mine_check_due_(0),
next_militarysite_check_due_(0),
- next_ship_check_due(5 * 60 * 1000),
- next_marine_decisions_due(5 * 60 * 1000),
+ next_ship_check_due(30 * 1000),
+ next_marine_decisions_due(30 * 1000),
next_attack_consideration_due_(300000),
next_trainingsites_check_due_(15 * 60 * 1000),
next_bf_check_due_(1000),
@@ -130,34 +130,34 @@
// Subscribe to NoteFieldPossession.
field_possession_subscriber_ =
Notifications::subscribe<NoteFieldPossession>([this](const NoteFieldPossession& note) {
- if (note.player != player_) {
+ if (note.player != player_) {
return;
}
- if (note.ownership == NoteFieldPossession::Ownership::GAINED) {
+ if (note.ownership == NoteFieldPossession::Ownership::GAINED) {
unusable_fields.push_back(note.fc);
}
});
// Subscribe to NoteImmovables.
immovable_subscriber_ =
- Notifications::subscribe<NoteImmovable>([this](const NoteImmovable& note) {
- if (player_ == nullptr) {
- return;
- }
- if (note.pi->owner().player_number() != player_->player_number()) {
- return;
- }
- if (note.ownership == NoteImmovable::Ownership::GAINED) {
- gain_immovable(*note.pi);
- } else {
- lose_immovable(*note.pi);
- }
+ Notifications::subscribe<NoteImmovable>([this](const NoteImmovable& note) {
+ if (player_ == nullptr) {
+ return;
+ }
+ if (note.pi->owner().player_number() != player_->player_number()) {
+ return;
+ }
+ if (note.ownership == NoteImmovable::Ownership::GAINED) {
+ gain_immovable(*note.pi);
+ } else {
+ lose_immovable(*note.pi);
+ }
});
// Subscribe to ProductionSiteOutOfResources.
outofresource_subscriber_ = Notifications::subscribe<NoteProductionSiteOutOfResources>(
[this](const NoteProductionSiteOutOfResources& note) {
- if (note.ps->owner().player_number() != player_->player_number()) {
+ if (note.ps->owner().player_number() != player_->player_number()) {
return;
}
@@ -169,42 +169,42 @@
shipnotes_subscriber_ =
Notifications::subscribe<NoteShipMessage>([this](const NoteShipMessage& note) {
- // in a short time between start and late_initialization the player
- // can get notes that can not be processed.
- // It seems that this causes no problem, at least no substantial
- if (player_ == nullptr) {
- return;
- }
- if (note.ship->get_owner()->player_number() != player_->player_number()) {
- return;
- }
-
- switch (note.message) {
-
- case NoteShipMessage::Message::kGained:
+ // in a short time between start and late_initialization the player
+ // can get notes that can not be processed.
+ // It seems that this causes no problem, at least no substantial
+ if (player_ == nullptr) {
+ return;
+ }
+ if (note.ship->get_owner()->player_number() != player_->player_number()) {
+ return;
+ }
+
+ switch (note.message) {
+
+ case NoteShipMessage::Message::kGained:
gain_ship(*note.ship, NewShip::kBuilt);
break;
- case NoteShipMessage::Message::kLost:
- for (std::list<ShipObserver>::iterator i = allships.begin(); i != allships.end(); ++i) {
- if (i->ship == note.ship) {
+ case NoteShipMessage::Message::kLost:
+ for (std::list<ShipObserver>::iterator i = allships.begin(); i != allships.end(); ++i) {
+ if (i->ship == note.ship) {
allships.erase(i);
break;
}
}
break;
- case NoteShipMessage::Message::kWaitingForCommand:
+ case NoteShipMessage::Message::kWaitingForCommand:
for (std::list<ShipObserver>::iterator i = allships.begin(); i != allships.end(); ++i) {
- if (i->ship == note.ship) {
+ if (i->ship == note.ship) {
i->waiting_for_command_ = true;
break;
}
}
break;
- default:
+ default:
;
- }
+ }
});
}
@@ -339,7 +339,7 @@
review_wares_targets(gametime);
}
- //print statistics
+ // print statistics
if (kPrintStats && next_statistics_report_ <= gametime) {
print_stats();
next_statistics_report_ += 60 * 60 * 1000;
@@ -515,17 +515,39 @@
Map& map = game().map();
- //here we scan entire map for own ships
+ // here we generate list of all ports and their vicinity from entire map
+ for (const Coords& c : map.get_port_spaces()) {
+ MapRegion<Area<FCoords>> mr(map, Area<FCoords>(map.get_fcoords(c), 3));
+ do {
+ const int32_t hash = coords_hash(map.get_fcoords(*(mr.location().field)));
+ if (port_reserved_coords.count(hash) == 0)
+ port_reserved_coords.insert(hash);
+ } while (mr.advance(map));
+
+ //the same for NW neighbour of a field
+ Coords c_nw;
+ map.get_tln(c, &c_nw);
+ MapRegion<Area<FCoords>> mr_nw(map, Area<FCoords>(map.get_fcoords(c_nw), 3));
+ do {
+ const int32_t hash = coords_hash(map.get_fcoords(*(mr_nw.location().field)));
+ if (port_reserved_coords.count(hash) == 0)
+ port_reserved_coords.insert(hash);
+ } while (mr_nw.advance(map));
+ }
+
+ if (!port_reserved_coords.empty()) {
+ seafaring_economy = true;
+ }
+
+ // here we scan entire map for own ships
std::set<OPtr<Ship>> found_ships;
for (int16_t y = 0; y < map.get_height(); ++y) {
for (int16_t x = 0; x < map.get_width(); ++x) {
FCoords f = map.get_fcoords(Coords(x, y));
- //there are too many bobs on the map so we investigate
- //only bobs on water
+ // there are too many bobs on the map so we investigate
+ // only bobs on water
if (f.field->nodecaps() & MOVECAPS_SWIM) {
- for (Bob * bob = f.field->get_first_bob();
- bob;
- bob = bob->get_next_on_field()) {
+ for (Bob* bob = f.field->get_first_bob(); bob; bob = bob->get_next_on_field()) {
if (upcast(Ship, ship, bob)) {
if (ship->get_owner() == player_ && !found_ships.count(ship)) {
found_ships.insert(ship);
@@ -537,7 +559,7 @@
}
}
- //here we scan entire map for owned unused fields and own buildings
+ // here we scan entire map for owned unused fields and own buildings
std::set<OPtr<PlayerImmovable>> found_immovables;
for (int16_t y = 0; y < map.get_height(); ++y) {
for (int16_t x = 0; x < map.get_width(); ++x) {
@@ -558,6 +580,19 @@
}
}
}
+
+ // blocking space consumers vicinity (when reloading a game)
+ for (const ProductionSiteObserver& ps_obs : productionsites) {
+ if (ps_obs.bo->space_consumer_ && !ps_obs.bo->plants_trees_) {
+ MapRegion<Area<FCoords>> mr(
+ map, Area<FCoords>(map.get_fcoords(ps_obs.site->get_position()), 4));
+ do {
+ BlockedField blocked2(
+ map.get_fcoords(*(mr.location().field)), game().get_gametime() + 20 * 60 * 1000);
+ blocked_fields.push_back(blocked2);
+ } while (mr.advance(map));
+ }
+ }
}
/**
@@ -711,22 +746,25 @@
}
}
- // if curent port is a portspace we need add near fields to a list
- // of fields prohibited for buildings
+ // identifying portspace fields
if (!field.is_portspace_) { // if we know it, no need to do it once more
if (player_->get_buildcaps(field.coords) & BUILDCAPS_PORT) {
field.is_portspace_ = true;
- seafaring_economy = true;
- // blocking fields in vicinity
- MapRegion<Area<FCoords>> mr(map, Area<FCoords>(map.get_fcoords(field.coords), 3));
- do {
- const int32_t hash = coords_hash(map.get_fcoords(*(mr.location().field)));
- if (port_reserved_coords.count(hash) == 0)
- port_reserved_coords.insert(hash);
- } while (mr.advance(map));
}
}
+ //testing for near porspaces
+ if (field.portspace_nearby_ == Widelands::ExtendedBool::kUnset) {
+ field.portspace_nearby_ = ExtendedBool::kFalse;
+ MapRegion<Area<FCoords>> mr(map, Area<FCoords>(field.coords, 2));
+ do {
+ if (port_reserved_coords.count(coords_hash(mr.location())) > 0) {
+ field.portspace_nearby_ = ExtendedBool::kTrue;
+ break;
+ }
+ } while (mr.advance(map));
+ }
+
// testing if a port is nearby, such field will get a priority boost
uint16_t nearest_distance = std::numeric_limits<uint16_t>::max();
for (const WarehouseSiteObserver& wh_obs : warehousesites) {
@@ -777,7 +815,8 @@
}
// counting fields with fish
- if (field.water_nearby_ > 0 && (field.fish_nearby_ = -1 || game().get_gametime() % 10 == 0)) {
+ if (field.water_nearby_ > 0 &&
+ (field.fish_nearby_ == -1 || game().get_gametime() % 10 == 0)) {
map.find_fields(Area<FCoords>(field.coords, 6),
&resource_list,
FindNodeResource(world.get_resource("fish")));
@@ -978,12 +1017,7 @@
// Reset statistics for all buildings
for (uint32_t i = 0; i < buildings_.size(); ++i) {
- if (buildings_.at(i).cnt_built_ > 0) {
- buildings_.at(i).current_stats_ = 0;
- } else {
- buildings_.at(i).current_stats_ = 0;
- }
-
+ buildings_.at(i).current_stats_ = 0;
buildings_.at(i).unoccupied_ = false;
}
@@ -1698,6 +1732,15 @@
if (resource_necessity_water_needed_)
prio += bf->distant_water_ * resource_necessity_water_ / 255;
+ //special bonus if a portspace is close
+ if (bf->portspace_nearby_ == ExtendedBool::kTrue) {
+ if (num_ports == 0){
+ prio += 25;
+ } else {
+ prio += 5;
+ }
+ }
+
if (bo.desc->get_size() < maxsize) {
prio = prio - 5;
} // penalty
@@ -2093,12 +2136,12 @@
// if this is end flag (or sole building) or just randomly
if (flag.nr_of_roads() <= 1 || gametime % 200 == 0) {
- create_shortcut_road(flag, 13, 20);
+ create_shortcut_road(flag, 13, 20, gametime);
inhibit_road_building_ = gametime + 800;
}
// this is when a flag is full
else if (flag.current_wares() > 6 && gametime % 10 == 0) {
- create_shortcut_road(flag, 9, 0);
+ create_shortcut_road(flag, 9, 0, gametime);
inhibit_road_building_ = gametime + 400;
}
@@ -2109,7 +2152,7 @@
// and tries to find alternative route from one flag to another.
// if route exists, it is not too long, and current road is not intensively used
// the road can be dismantled
-bool DefaultAI::dispensable_road_test(const Road& road) {
+bool DefaultAI::dispensable_road_test(Widelands::Road& road) {
Flag& roadstartflag = road.get_flag(Road::FlagStart);
Flag& roadendflag = road.get_flag(Road::FlagEnd);
@@ -2182,66 +2225,82 @@
// trying to connect the flag to another one, be it from own economy
// or other economy
-bool DefaultAI::create_shortcut_road(const Flag& flag, uint16_t checkradius, uint16_t minred) {
+bool DefaultAI::create_shortcut_road(const Flag& flag,
+ uint16_t checkradius,
+ uint16_t minred,
+ int32_t gametime) {
// Increasing the failed_connection_tries counter
// At the same time it indicates a time an economy is without a warehouse
EconomyObserver* eco = get_economy_observer(flag.economy());
-
- // there are two special situations which have a bit different treatment
- bool is_remote_port_csite = false;
- bool stationed_military = false;
- if (flag.get_economy()->warehouses().empty()) {
- // first very special case - lonesome port (in the phase of constructionsite)
- // obviously it has no warehouse/road network to connect to
- if (upcast(ConstructionSite const, constructionsite, flag.get_building())) {
- BuildingObserver& bo = get_building_observer(constructionsite->building().name().c_str());
- if (bo.is_port_ &&
- remote_ports_coords.count(coords_hash(flag.get_building()->get_position())) > 0) {
- is_remote_port_csite = true;
- }
- }
-
- // second exemption is when a military buiding was conquered, it
- // might be just too far from near connected building
- if (Building* b = flag.get_building()) {
- if (upcast(MilitarySite, militb, b)) {
- if (militb->present_soldiers().size() > 0) {
- stationed_military = true;
- // also increasing checkradius a bit
- checkradius += 4;
- }
- }
- }
- }
-
- if (is_remote_port_csite ||
- (stationed_military && game().get_gametime() % 10 > 0)) { // counter disabled
- ;
- } else if (flag.get_economy()->warehouses().empty()) {
- eco->failed_connection_tries += 1;
- } else {
- eco->failed_connection_tries = 0;
- }
-
- // explanation for 'eco->flags.size() * eco->flags.size()'
- // The AI is able to dismantle whole economy without warehouse as soon as single
- // building not connected anywhere. But so fast dismantling is not deserved (probably)
- // so the bigger economy the longer it takes to be dismantled
- if (eco->failed_connection_tries > 3 + eco->flags.size() * eco->flags.size()) {
-
- Building* bld = flag.get_building();
-
- if (bld) {
- // first we block the field for 15 minutes, probably it is not good place to build a
- // building on
- BlockedField blocked(
- game().map().get_fcoords(bld->get_position()), game().get_gametime() + 15 * 60 * 1000);
- blocked_fields.push_back(blocked);
- eco->flags.remove(&flag);
- game().send_player_bulldoze(*const_cast<Flag*>(&flag));
- }
- return true;
+ // if we passed grace time this will be last attempt and if it fails
+ // building is destroyes
+ bool last_attempt_ = false;
+
+ // this should not happen, but if the economy has a warehouse and a dismantle
+ // grace time set, we must 'zero' the dismantle grace time
+ if (!flag.get_economy()->warehouses().empty() &&
+ eco->dismantle_grace_time_ != std::numeric_limits<int32_t>::max()) {
+ eco->dismantle_grace_time_ = std::numeric_limits<int32_t>::max();
+ }
+
+ // first we deal with situations when this is economy with no warehouses
+ // and this is a flag belonging to a building/constructionsite
+ if (flag.get_economy()->warehouses().empty() && flag.get_building()) {
+
+ // if we are within grace time, it is OK, just go on
+ if (eco->dismantle_grace_time_ > gametime &&
+ eco->dismantle_grace_time_ != std::numeric_limits<int32_t>::max()) {
+ ;
+
+ // if grace time is not set, this is probably first time without a warehouse and we must
+ // set it
+ } else if (eco->dismantle_grace_time_ == std::numeric_limits<int32_t>::max()) {
+
+ // constructionsites
+ if (upcast(ConstructionSite const, constructionsite, flag.get_building())) {
+ BuildingObserver& bo =
+ get_building_observer(constructionsite->building().name().c_str());
+ // first very special case - a port (in the phase of constructionsite)
+ // this might be a new colonization port
+ if (bo.is_port_) {
+ eco->dismantle_grace_time_ = gametime + 60 * 60 * 1000; // one hour should be enough
+ } else { // other constructionsites, usually new (standalone) constructionsites
+ eco->dismantle_grace_time_ =
+ gametime + 30 * 1000 + // very shot time is enough
+ (eco->flags.size() * 30 * 1000); // + 30 seconds for every flag in economy
+ }
+
+ // buildings
+ } else {
+
+ //occupied military buildings get special treatment
+ //(extended grace time)
+ bool occupied_military_ = false;
+ Building* b = flag.get_building();
+ if (upcast(MilitarySite, militb, b)) {
+ if (militb->stationed_soldiers().size() > 0) {
+ occupied_military_ = true;
+ }
+ }
+
+ if (occupied_military_) {
+ eco->dismantle_grace_time_ =
+ (gametime + 20 * 60 * 1000) + (eco->flags.size() * 20 * 1000);
+ checkradius += 3;
+
+ } else { // for other normal buildings
+ eco->dismantle_grace_time_ =
+ gametime + (5 * 60 * 1000) + (eco->flags.size() * 20 * 1000);
+ }
+ }
+
+ // we have passed grace_time - it is time to dismantle
+ } else {
+ last_attempt_ = true;
+ //we increase a check radius in last attempt
+ checkradius += 2;
+ }
}
Map& map = game().map();
@@ -2255,10 +2314,10 @@
std::vector<Coords> reachable;
// vector reachable now contains all suitable fields
- map.find_reachable_fields(
+ const uint32_t reachable_fields_count = map.find_reachable_fields(
Area<FCoords>(map.get_fcoords(flag.get_position()), checkradius), &reachable, check, functor);
- if (reachable.empty()) {
+ if (reachable_fields_count == 0) {
return false;
}
@@ -2432,6 +2491,18 @@
}
// if all possible roads skipped
+ if (last_attempt_) {
+ Building* bld = flag.get_building();
+ // first we block the field for 15 minutes, probably it is not good place to build a
+ // building on
+ BlockedField blocked(
+ game().map().get_fcoords(bld->get_position()), game().get_gametime() + 15 * 60 * 1000);
+ blocked_fields.push_back(blocked);
+ eco->flags.remove(&flag);
+ game().send_player_bulldoze(*const_cast<Flag*>(&flag));
+ return true;
+ }
+
return false;
}
@@ -2792,7 +2863,7 @@
if (gametime < next_marine_decisions_due) {
return false;
}
- next_marine_decisions_due += kMarineDecisionInterval;
+ next_marine_decisions_due = gametime + kMarineDecisionInterval;
if (!seafaring_economy) {
return false;
@@ -2805,7 +2876,6 @@
uint16_t working_shipyards_count = 0;
uint16_t expeditions_in_prep = 0;
uint16_t expeditions_in_progress = 0;
- uint16_t territories_count = 1;
bool idle_shipyard_stocked = false;
// goes over all warehouses (these includes ports)
@@ -2816,10 +2886,6 @@
if (pd->expedition_started()) {
expeditions_in_prep += 1;
}
- } else {
- log(" there is a port without portdock at %3dx%3d?\n",
- wh_obs.site->get_position().x,
- wh_obs.site->get_position().y);
}
}
}
@@ -2852,35 +2918,13 @@
}
}
- // we must verify that all remote ports are still ours (and exists at all)
- bool still_ours;
- for (std::unordered_set<uint32_t>::iterator ports_iter = remote_ports_coords.begin();
- ports_iter != remote_ports_coords.end();
- ++ports_iter) {
- still_ours = false;
- FCoords fcoords = game().map().get_fcoords(coords_unhash(*ports_iter));
- if (fcoords.field->get_owned_by() == player_number()) {
- if (upcast(PlayerImmovable, imm, fcoords.field->get_immovable())) {
- still_ours = true;
- }
- }
-
- if (!still_ours) {
- remote_ports_coords.erase(*ports_iter);
- break;
- }
- }
- territories_count += remote_ports_coords.size();
-
enum class FleetStatus : uint8_t {kNeedShip = 0, kEnoughShips = 1, kDoNothing = 2 };
// now we must compare ports vs ships to decide if new ship is needed or new expedition can start
FleetStatus enough_ships = FleetStatus::kDoNothing;
- if (static_cast<float>(allships.size()) >
- static_cast<float>((territories_count - 1) * 0.6 + ports_count * 0.75)) {
+ if (static_cast<float>(allships.size()) >= ports_count) {
enough_ships = FleetStatus::kEnoughShips;
- } else if (static_cast<float>(allships.size()) <
- static_cast<float>((territories_count - 1) * 0.6 + ports_count * 0.75)) {
+ } else if (static_cast<float>(allships.size()) < ports_count) {
enough_ships = FleetStatus::kNeedShip;
}
@@ -2930,7 +2974,7 @@
return false;
}
- next_ship_check_due += kShipCheckInterval;
+ next_ship_check_due = gametime + kShipCheckInterval;
if (!seafaring_economy) {
return false;
@@ -3581,8 +3625,8 @@
}
// sometimes we search for any owned teritory (f.e. when considering
- //a port location), but when testing (starting from) own military building
- //we must ignore own teritory, of course
+ // a port location), but when testing (starting from) own military building
+ // we must ignore own teritory, of course
if (f->get_owned_by() > 0) {
if (type == WalkSearch::kAnyPlayer ||
(type == WalkSearch::kOtherPlayers && f->get_owned_by() != pn)) {
@@ -3693,8 +3737,8 @@
const uint8_t spot_score = spot_scoring(so.ship->exp_port_spaces()->front());
if ((gametime / 10) % 8 < spot_score) { // we build a port here
- const Coords last_portspace = so.ship->exp_port_spaces()->front();
- remote_ports_coords.insert(coords_hash(last_portspace));
+ // const Coords last_portspace = so.ship->exp_port_spaces()->front();
+ // remote_ports_coords.insert(coords_hash(last_portspace));
game().send_player_ship_construct_port(*so.ship, so.ship->exp_port_spaces()->front());
so.last_command_time = gametime;
so.waiting_for_command_ = false;
@@ -3842,6 +3886,15 @@
if (bo.is_port_) {
++num_ports;
seafaring_economy = true;
+ // unblock nearby fields, might be used for other buildings...
+ Map& map = game().map();
+ MapRegion<Area<FCoords>> mr(
+ map, Area<FCoords>(map.get_fcoords(warehousesites.back().site->get_position()), 4));
+ do {
+ const int32_t hash = coords_hash(map.get_fcoords(*(mr.location().field)));
+ if (port_reserved_coords.count(hash) > 0)
+ port_reserved_coords.erase(hash);
+ } while (mr.advance(map));
}
}
}
@@ -4257,10 +4310,24 @@
PlayerNumber const pn = player_number();
- //we test following materials
- const std::vector <std::string> materials = {"coal", "log", "ironore", "marble",
- "plank", "water", "goldore", "granite", "fish", "diamond", "stone", "corn",
- "wheat", "grape", "quartz", "bread", "meat" };
+ // we test following materials
+ const std::vector<std::string> materials = {"coal",
+ "log",
+ "ironore",
+ "marble",
+ "plank",
+ "water",
+ "goldore",
+ "granite",
+ "fish",
+ "diamond",
+ "stone",
+ "corn",
+ "wheat",
+ "grape",
+ "quartz",
+ "bread",
+ "meat"};
std::string summary = "";
for (uint32_t j = 0; j < materials.size(); ++j) {
WareIndex const index = tribe_->ware_index(materials.at(j));
@@ -4272,12 +4339,12 @@
}
summary = summary + materials.at(j) + ", ";
}
- log (" %1d: Buildings: Pr:%3d, Ml:%3d, Mi:%2d, Wh:%2d, Po:%2d. Missing: %s\n",
- pn,
- productionsites.size(),
- militarysites.size(),
- mines_.size(),
- warehousesites.size() - num_ports,
- num_ports,
- summary.c_str());
+ log(" %1d: Buildings: Pr:%3d, Ml:%3d, Mi:%2d, Wh:%2d, Po:%2d. Missing: %s\n",
+ pn,
+ productionsites.size(),
+ militarysites.size(),
+ mines_.size(),
+ warehousesites.size() - num_ports,
+ num_ports,
+ summary.c_str());
}
=== modified file 'src/ai/defaultai.h'
--- src/ai/defaultai.h 2015-02-16 10:22:29 +0000
+++ src/ai/defaultai.h 2015-02-18 20:34:30 +0000
@@ -154,9 +154,12 @@
// if needed it calls create_shortcut_road() with a flag from which
// new road should be considered (or is needed)
bool improve_roads(int32_t);
- bool create_shortcut_road(const Widelands::Flag&, uint16_t maxcheckradius, uint16_t minred);
+ bool create_shortcut_road(const Widelands::Flag&,
+ uint16_t maxcheckradius,
+ uint16_t minred,
+ const int32_t gametime);
// trying to identify roads that might be removed
- bool dispensable_road_test(const Widelands::Road&);
+ bool dispensable_road_test(Widelands::Road&);
bool check_economies();
bool check_productionsites(int32_t);
bool check_trainingsites(int32_t);
@@ -226,8 +229,6 @@
std::list<BuildableField*> buildable_fields;
std::list<BlockedField> blocked_fields;
std::unordered_set<uint32_t> port_reserved_coords;
- // to distinquish which ports are on home teritory and which one are remote
- std::unordered_set<uint32_t> remote_ports_coords;
std::list<MineableField*> mineable_fields;
std::list<Widelands::Flag const*> new_flags;
std::list<Widelands::Coords> flags_to_be_removed;
=== modified file 'src/economy/portdock.cc'
--- src/economy/portdock.cc 2015-02-10 21:25:14 +0000
+++ src/economy/portdock.cc 2015-02-18 20:34:30 +0000
@@ -214,11 +214,13 @@
PlayerImmovable::cleanup(egbase);
//now let attempt to recreate the portdock
- if (!wh->m_cleanup_in_progress){
- if (upcast(Game, game, &egbase)) {
- if (game->is_loaded()) { //do not attempt when shutting down
- Player& player = owner();
- wh->restore_portdock_or_destroy(egbase);
+ if (wh) {
+ if (!wh->m_cleanup_in_progress){
+ if (upcast(Game, game, &egbase)) {
+ if (game->is_loaded()) { //do not attempt when shutting down
+ Player& player = owner();
+ wh->restore_portdock_or_destroy(egbase);
+ }
}
}
}
@@ -439,14 +441,16 @@
void PortDock::log_general_info(const EditorGameBase& egbase) {
PlayerImmovable::log_general_info(egbase);
- Coords pos(m_warehouse->get_position());
- molog("PortDock for warehouse %u (at %i,%i) in fleet %u, need_ship: %s, waiting: %" PRIuS "\n",
- m_warehouse ? m_warehouse->serial() : 0,
- pos.x,
- pos.y,
- m_fleet ? m_fleet->serial() : 0,
- m_need_ship ? "true" : "false",
- m_waiting.size());
+ if (!m_warehouse) {
+ Coords pos(m_warehouse->get_position());
+ molog("PortDock for warehouse %u (at %i,%i) in fleet %u, need_ship: %s, waiting: %" PRIuS "\n",
+ m_warehouse ? m_warehouse->serial() : 0,
+ pos.x,
+ pos.y,
+ m_fleet ? m_fleet->serial() : 0,
+ m_need_ship ? "true" : "false",
+ m_waiting.size());
+ }
for (ShippingItem& shipping_item : m_waiting) {
molog(" IT %u, destination %u\n",
=== modified file 'src/logic/playercommand.cc'
--- src/logic/playercommand.cc 2015-02-13 18:48:37 +0000
+++ src/logic/playercommand.cc 2015-02-18 20:34:30 +0000
@@ -785,9 +785,11 @@
upcast(Ship, ship, game.objects().get_object(serial));
if (ship && ship->get_owner()->player_number() == sender()) {
if (!(ship->get_ship_state() == Widelands::Ship::EXP_WAITING ||
- ship->get_ship_state() == Widelands::Ship::EXP_FOUNDPORTSPACE)) {
+ ship->get_ship_state() == Widelands::Ship::EXP_FOUNDPORTSPACE ||
+ ship->get_ship_state() == Widelands::Ship::EXP_SCOUTING)) {
log (" %1d:ship on %3dx%3d received scout command but not in "
- "EXP_WAITING or PORTSPACE_FOUND status (expedition: %s), ignoring...\n",
+ "EXP_WAITING or PORTSPACE_FOUND or EXP_SCOUTING status "
+ "(expedition: %s), ignoring...\n",
ship->get_owner()->player_number(),
ship->get_position().x,
ship->get_position().y,
@@ -918,9 +920,11 @@
upcast(Ship, ship, game.objects().get_object(serial));
if (ship && ship->get_owner()->player_number() == sender()) {
if (!(ship->get_ship_state() == Widelands::Ship::EXP_WAITING ||
- ship->get_ship_state() == Widelands::Ship::EXP_FOUNDPORTSPACE)) {
+ ship->get_ship_state() == Widelands::Ship::EXP_FOUNDPORTSPACE ||
+ ship->get_ship_state() == Widelands::Ship::EXP_SCOUTING)) {
log (" %1d:ship on %3dx%3d received explore island command "
- "but not in EXP_WAITING or PORTSPACE_FOUND status (expedition: %s), ignoring...\n",
+ "but not in EXP_WAITING or PORTSPACE_FOUND or EXP_SCOUTING "
+ "status (expedition: %s), ignoring...\n",
ship->get_owner()->player_number(),
ship->get_position().x,
ship->get_position().y,
=== modified file 'src/logic/warehouse.cc'
--- src/logic/warehouse.cc 2015-02-10 21:25:14 +0000
+++ src/logic/warehouse.cc 2015-02-18 20:34:30 +0000
@@ -285,6 +285,7 @@
m_next_worker_without_cost_spawn[i] = never();
}
m_next_stock_remove_act = 0;
+ m_cleanup_in_progress = false;
}
=== modified file 'tribes/atlanteans/port/conf'
--- tribes/atlanteans/port/conf 2014-07-28 12:48:04 +0000
+++ tribes/atlanteans/port/conf 2015-02-18 20:34:30 +0000
@@ -26,3 +26,7 @@
[build]
pics=port_b_??.png # 4 frames
hotspot=74 70
+
+[aihints]
+prohibited_till=900
+
=== modified file 'tribes/atlanteans/shipyard/conf'
--- tribes/atlanteans/shipyard/conf 2014-10-07 20:06:46 +0000
+++ tribes/atlanteans/shipyard/conf 2015-02-18 20:34:30 +0000
@@ -2,6 +2,7 @@
[aihints]
needs_water=true
+prohibited_till=1500
[buildcost]
log=3
=== modified file 'tribes/barbarians/port/conf'
--- tribes/barbarians/port/conf 2014-07-28 12:48:04 +0000
+++ tribes/barbarians/port/conf 2015-02-18 20:34:30 +0000
@@ -28,3 +28,7 @@
[build]
pics=port_b_??.png # 4 frames
hotspot=67 80
+
+[aihints]
+prohibited_till=900
+
=== modified file 'tribes/barbarians/shipyard/conf'
--- tribes/barbarians/shipyard/conf 2014-10-07 20:06:46 +0000
+++ tribes/barbarians/shipyard/conf 2015-02-18 20:34:30 +0000
@@ -2,6 +2,7 @@
[aihints]
needs_water=true
+prohibited_till=1500
[buildcost]
log=3
=== modified file 'tribes/empire/port/conf'
--- tribes/empire/port/conf 2014-07-28 12:48:04 +0000
+++ tribes/empire/port/conf 2015-02-18 20:34:30 +0000
@@ -27,3 +27,7 @@
[build]
pics=port_b_??.png # 4 frames
hotspot=74 96
+
+[aihints]
+prohibited_till=900
+
=== modified file 'tribes/empire/shipyard/conf'
--- tribes/empire/shipyard/conf 2014-12-27 21:51:34 +0000
+++ tribes/empire/shipyard/conf 2015-02-18 20:34:30 +0000
@@ -2,6 +2,7 @@
[aihints]
needs_water=true
+prohibited_till=1500
[buildcost]
log=3
Follow ups