← Back to team overview

widelands-dev team mailing list archive

[Merge] lp:~widelands-dev/widelands/find_attack_soldiers into lp:widelands

 

SirVer has proposed merging lp:~widelands-dev/widelands/find_attack_soldiers into lp:widelands.

Requested reviews:
  Widelands Developers (widelands-dev)

For more details, see:
https://code.launchpad.net/~widelands-dev/widelands/find_attack_soldiers/+merge/245276

This patch was send to me by fk who has difficulties accessing launchpad.

I did some changes to make it compile, but I did not review nor test the changes. So I do not fully know what the code actually does, but it has something to do with better selection of soldiers on attack. 
-- 
Your team Widelands Developers is requested to review the proposed merge of lp:~widelands-dev/widelands/find_attack_soldiers into lp:widelands.
=== modified file 'src/ai/ai_help_structs.h'
--- src/ai/ai_help_structs.h	2014-10-30 20:24:57 +0000
+++ src/ai/ai_help_structs.h	2014-12-20 20:51:12 +0000
@@ -21,6 +21,7 @@
 #define WL_AI_AI_HELP_STRUCTS_H
 
 #include <list>
+#include <unordered_set>
 
 #include "economy/flag.h"
 #include "economy/road.h"
@@ -32,6 +33,7 @@
 #include "logic/player.h"
 #include "logic/world/terrain_description.h"
 #include "logic/world/world.h"
+#include "logic/ship.h"
 
 namespace Widelands {
 
@@ -187,6 +189,14 @@
 	Widelands::FCoords coords;
 	int32_t blocked_until_;
 
+	bool operator== (const BlockedField& other) const {
+		return coords == other.coords;
+	}
+
+	bool operator!= (const BlockedField& other) const {
+		return coords != other.coords;
+	}
+
 	BlockedField(Widelands::FCoords c, int32_t until) : coords(c), blocked_until_(until) {
 	}
 };
@@ -227,10 +237,9 @@
 	int16_t military_stationed_;
 	// stationed (manned) military buildings nearby
 	int16_t military_unstationed_;
-	// some buildings must be postponed bit
-	int32_t prohibited_till_;
-	// and then some must be forced
-	int32_t forced_after_;
+	bool is_portspace_;
+	bool port_nearby_;  // to increase priority if a port is nearby,
+	// especially for new colonies
 
 	std::vector<uint8_t> consumers_nearby_;
 	std::vector<uint8_t> producers_nearby_;
@@ -261,7 +270,9 @@
 	     military_loneliness_(1000),
 	     military_in_constr_nearby_(0),
 	     military_presence_(0),
-	     military_stationed_(0) {
+	     military_stationed_(0),
+	     is_portspace_(false),
+	     port_nearby_(false) {
 	}
 };
 
@@ -310,12 +321,14 @@
 	bool plants_trees_;
 	bool recruitment_;  // is "producing" workers?
 	bool is_buildable_;
-	bool need_trees_;          // lumberjack = true
-	bool need_stones_;         // quarry = true
-	bool mines_water_;         // wells
-	bool need_water_;          // fisher, fish_breeder = true
-	bool is_hunter_;           // need to identify hunters
-	bool is_fisher_;           // need to identify fishers
+	bool need_trees_;   // lumberjack = true
+	bool need_stones_;  // quarry = true
+	bool mines_water_;  // wells
+	bool need_water_;   // fisher, fish_breeder = true
+	bool is_hunter_;    // need to identify hunters
+	bool is_fisher_;    // need to identify fishers
+	bool is_port_;
+	bool is_shipyard_;
 	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
@@ -327,7 +340,6 @@
 
 	int32_t mines_;           // type of resource it mines_
 	uint16_t mines_percent_;  // % of res it can mine
-
 	uint32_t current_stats_;
 
 	std::vector<int16_t> inputs_;
@@ -372,6 +384,34 @@
 	bool enemies_nearby_;
 };
 
+struct TrainingSiteObserver {
+	Widelands::TrainingSite* site;
+	BuildingObserver* bo;
+};
+
+struct WarehouseSiteObserver {
+	Widelands::Warehouse* site;
+	BuildingObserver* bo;
+};
+
+struct ShipObserver {
+
+	bool operator== (const ShipObserver& other) const {
+		return ship->serial() == other.ship->serial();
+	}
+
+	bool operator!= (const ShipObserver& other) const {
+		return ship->serial() != other.ship->serial();
+	}
+
+	Widelands::Ship* ship;
+	Widelands::Coords expedition_start_point_;
+	std::unordered_set<uint32_t> visited_spots_;
+	bool island_circ_direction = true;  // a ship circumvents all island in the same direction
+	bool waiting_for_command_ = false;
+	int32_t last_command_time = 0;
+};
+
 struct WareObserver {
 	uint8_t producers_;
 	uint8_t consumers_;

=== modified file 'src/ai/defaultai.cc'
--- src/ai/defaultai.cc	2014-11-30 18:53:22 +0000
+++ src/ai/defaultai.cc	2014-12-20 20:51:12 +0000
@@ -31,7 +31,9 @@
 #include "base/macros.h"
 #include "economy/economy.h"
 #include "economy/flag.h"
+#include "economy/portdock.h"
 #include "economy/road.h"
+#include "economy/wares_queue.h"
 #include "logic/constructionsite.h"
 #include "logic/findbob.h"
 #include "logic/findimmovable.h"
@@ -39,7 +41,9 @@
 #include "logic/map.h"
 #include "logic/militarysite.h"
 #include "logic/player.h"
+#include "logic/playercommand.h"
 #include "logic/productionsite.h"
+#include "logic/ship.h"
 #include "logic/trainingsite.h"
 #include "logic/tribe.h"
 #include "logic/warehouse.h"
@@ -48,6 +52,7 @@
 
 // Building of new military buildings can be restricted
 constexpr int kPushExpansion = 1;
+
 constexpr int kResourcesOrDefense = 2;
 constexpr int kDefenseOnly = 3;
 constexpr int kNoNewMilitary = 4;
@@ -59,6 +64,10 @@
 // building of the same building can be started after 25s at earliest
 constexpr int kBuildingMinInterval = 25 * 1000;
 constexpr int kMinBFCheckInterval = 5 * 1000;
+constexpr int kShipCheckInterval = 5 * 1000;
+constexpr int kMarineDecisionInterval = 20 * 1000;
+constexpr int kTrainingSitesCheckInterval = 30 * 1000;
+
 // Some buildings have to be built close to borders and their
 // priority might be decreased below 0, so this is to
 // compensate
@@ -81,6 +90,7 @@
      num_constructionsites_(0),
      num_milit_constructionsites(0),
      num_prod_constructionsites(0),
+     num_ports(0),
      next_road_due_(2000),
      next_stats_update_due_(30000),
      next_construction_due_(1000),
@@ -88,9 +98,12 @@
      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_attack_consideration_due_(300000),
-     next_helpersites_check_due_(180000),
+     next_trainingsites_check_due_(15 * 60 * 1000),
      next_bf_check_due_(1000),
+     next_wares_review_due_(15 * 60 * 1000),
      inhibit_road_building_(0),
      time_of_last_construction_(0),
      enemy_last_seen_(-2 * 60 * 1000),
@@ -107,11 +120,13 @@
 	last_attack_target_(
         std::numeric_limits<uint16_t>::max(), std::numeric_limits<uint16_t>::max()),
      next_attack_waittime_(10),
+     seafaring_economy(false),
+     colony_scan_area_(35),
      spots_(0) {
 
 	// Subscribe to NoteFieldPossession.
 	field_possession_subscriber_ =
-	   Notifications::subscribe<NoteFieldPossession>([this](const NoteFieldPossession& note) {
+		Notifications::subscribe<NoteFieldPossession>([this](const NoteFieldPossession& note) {
 			if (note.player != player_) {
 			   return;
 		   }
@@ -122,7 +137,7 @@
 
 	// Subscribe to NoteImmovables.
 	immovable_subscriber_ =
-	   Notifications::subscribe<NoteImmovable>([this](const NoteImmovable& note) {
+		Notifications::subscribe<NoteImmovable>([this](const NoteImmovable& note) {
 			if (note.pi->owner().player_number() != player_->player_number()) {
 			   return;
 		   }
@@ -143,6 +158,49 @@
 		   out_of_resources_site(*note.ps);
 
 		});
+
+	// Subscribe to ShipNotes.
+	shipnotes_subscriber_ =
+	   Notifications::subscribe<NoteShipMessage>([this](const NoteShipMessage& note) {
+			if (note.ship->get_owner()->player_number() != player_->player_number()) {
+			   return;
+		   }
+
+			switch (note.message) {
+
+			case NoteShipMessage::Message::kGained:
+
+			   marineTaskQueue_.push_back(kStopShipyard);
+
+			   allships.push_back(ShipObserver());
+			   allships.back().ship = note.ship;
+				if (game().get_gametime() % 2 == 0) {
+				   allships.back().island_circ_direction = true;
+			   } else {
+				   allships.back().island_circ_direction = false;
+			   }
+				break;
+
+		   case NoteShipMessage::Message::kLost: {
+				for (const ShipObserver& ship_observer : allships) {
+					if (ship_observer.ship == note.ship) {
+						allships.remove(ship_observer);
+					   break;
+				   }
+				}
+		   case NoteShipMessage::Message::kWaitingForCommand:
+				for (ShipObserver& ship_observer : allships) {
+					if (ship_observer.ship == note.ship) {
+						ship_observer.waiting_for_command_ = true;
+					   break;
+				   }
+			   }
+			   break;
+		   default:
+				;
+		   }
+		}
+	});
 }
 
 DefaultAI::~DefaultAI() {
@@ -238,6 +296,14 @@
 		return;
 	}
 
+	if (check_ships(gametime)) {
+		return;
+	}
+
+	if (marine_main_decisions(gametime)) {
+		return;
+	}
+
 	// Check the mines and consider upgrading or destroying one
 	if (check_mines_(gametime)) {
 		return;
@@ -249,6 +315,10 @@
 		return;
 	}
 
+	if (check_trainingsites(gametime)) {
+		return;
+	}
+
 	// improve existing roads!
 	// main part of this improvment is creation 'shortcut roads'
 	// this includes also connection of new buildings
@@ -257,6 +327,12 @@
 		m_mineable_changed = true;
 		return;
 	}
+
+	// once in 15 minutes we increase(or decrease) targets for wares
+	if (next_wares_review_due_ <= gametime) {
+		next_wares_review_due_ = gametime + 15 * 60 * 1000;
+		review_wares_targets(gametime);
+	}
 }
 
 /**
@@ -317,6 +393,7 @@
 		bo.mountain_conqueror_ = bh.is_mountain_conqueror();
 		bo.prohibited_till_ = bh.get_prohibited_till() * 1000;  // value in conf is in seconds
 		bo.forced_after_ = bh.get_forced_after() * 1000;        // value in conf is in seconds
+		bo.is_port_ = bld.get_isport();
 		if (char const* const s = bh.get_renews_map_resource()) {
 			bo.production_hint_ = tribe_->safe_ware_index(s);
 		}
@@ -330,8 +407,7 @@
 
 		// Read all interesting data from ware producing buildings
 		if (bld.type() == MapObjectType::PRODUCTIONSITE) {
-			const ProductionSiteDescr& prod =
-					dynamic_cast<const ProductionSiteDescr&>(bld);
+			const ProductionSiteDescr& prod = dynamic_cast<const ProductionSiteDescr&>(bld);
 			bo.type = bld.get_ismine() ? BuildingObserver::MINE : BuildingObserver::PRODUCTIONSITE;
 			for (const WareAmount& temp_input : prod.inputs()) {
 				bo.inputs_.push_back(temp_input.first);
@@ -362,6 +438,13 @@
 			} else {
 				bo.is_fisher_ = false;
 			}
+
+			if (building_name == "shipyard") {
+				bo.is_shipyard_ = true;
+			} else {
+				bo.is_shipyard_ = false;
+			}
+
 			continue;
 		}
 
@@ -370,8 +453,7 @@
 		// non critical are excluded (see below)
 		if (bld.type() == MapObjectType::MILITARYSITE) {
 			bo.type = BuildingObserver::MILITARYSITE;
-			const MilitarySiteDescr& milit =
-				dynamic_cast<const MilitarySiteDescr&>(bld);
+			const MilitarySiteDescr& milit = dynamic_cast<const MilitarySiteDescr&>(bld);
 			for (const std::pair<unsigned char, unsigned char>& temp_buildcosts : milit.buildcost()) {
 				// bellow are non-critical wares
 				if (tribe_->ware_index("log") == temp_buildcosts.first ||
@@ -394,6 +476,10 @@
 
 		if (bld.type() == MapObjectType::TRAININGSITE) {
 			bo.type = BuildingObserver::TRAININGSITE;
+			const TrainingSiteDescr& train = dynamic_cast<const TrainingSiteDescr&>(bld);
+			for (const WareAmount& temp_input : train.inputs()) {
+				bo.inputs_.push_back(temp_input.first);
+			}
 			continue;
 		}
 
@@ -593,6 +679,34 @@
 		}
 	}
 
+	// if curent port is a portspace we need add near fields to a list
+	// of fields prohibited for buildings
+	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 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) {
+		const uint16_t actual_distance = map.calc_distance(field.coords, wh_obs.site->get_position());
+		nearest_distance = std::min(nearest_distance, actual_distance);
+	}
+	if (nearest_distance < 15) {
+		field.port_nearby_ = true;
+	} else {
+		field.port_nearby_ = false;
+	}
+
 	// collect information about resources in the area
 	std::vector<ImmovableFound> immovables;
 	// Search in a radius of range
@@ -704,7 +818,6 @@
 			field.stones_nearby_ = 0;
 
 			for (uint32_t j = 0; j < immovables.size(); ++j) {
-				// const BaseImmovable & base_immovable = *immovables.at(i).object;
 				if (immovables.at(j).object->has_attribute(stone_attr)) {
 					++field.stones_nearby_;
 				}
@@ -906,22 +1019,20 @@
 // - there is an enemy
 //   Currently more military buildings are built then needed
 //   and "optimalization" (dismantling not needed buildings) is done afterwards
-bool DefaultAI::construct_building(int32_t gametime) {  // (int32_t gametime)
+bool DefaultAI::construct_building(int32_t gametime) {
 	//  Just used for easy checking whether a mine or something else was built.
 	bool mine = false;
 	bool field_blocked = false;
 	uint32_t consumers_nearby_count = 0;
 	std::vector<int32_t> spots_avail;
 	spots_avail.resize(4);
-	// uint16_t const pn = player_number();
+	Map& map = game().map();
 
 	for (int32_t i = 0; i < 4; ++i)
 		spots_avail.at(i) = 0;
 
-	for (std::list<BuildableField*>::iterator i = buildable_fields.begin();
-	     i != buildable_fields.end();
-	     ++i)
-		++spots_avail.at((*i)->coords.field->nodecaps() & BUILDCAPS_SIZEMASK);
+	for (const BuildableField* buildable_field : buildable_fields)
+		++spots_avail.at(buildable_field->coords.field->nodecaps() & BUILDCAPS_SIZEMASK);
 
 	spots_ = spots_avail.at(BUILDCAPS_SMALL);
 	spots_ += spots_avail.at(BUILDCAPS_MEDIUM);
@@ -1011,15 +1122,15 @@
 	Coords proposed_coords;
 
 	// Remove outdated fields from blocker list
-	for (std::list<BlockedField>::iterator i = blocked_fields.begin(); i != blocked_fields.end();)
-		if (i->blocked_until_ < game().get_gametime()) {
-			i = blocked_fields.erase(i);
-		} else {
-			++i;
+	for (const BlockedField& blocked_field : blocked_fields) {
+		if (blocked_field.blocked_until_ < game().get_gametime()) {
+			blocked_fields.remove(blocked_field);
 		}
+	}
 
 	// testing big military buildings, whether critical construction
-	// material is (not) needed
+	// material is available (at least in amount of
+	// 2/3 of default target amount)
 	for (uint32_t j = 0; j < buildings_.size(); ++j) {
 
 		BuildingObserver& bo = buildings_.at(j);
@@ -1037,19 +1148,13 @@
 
 		bo.build_material_shortage_ = false;
 
-		for (EconomyObserver* observer : economies) {
-			// Don't check if the economy has no warehouse.
-			if (observer->economy.warehouses().empty()) {
-				continue;
-			}
-
-			for (uint32_t m = 0; m < bo.critical_built_mat_.size(); ++m) {
-				WareIndex wt(static_cast<size_t>(bo.critical_built_mat_.at(m)));
-
-				if (observer->economy.needs_ware(wt)) {
-					bo.build_material_shortage_ = true;
-					continue;
-				}
+		// checking we have enough critical material on stock
+		for (uint32_t m = 0; m < bo.critical_built_mat_.size(); ++m) {
+			WareIndex wt(static_cast<size_t>(bo.critical_built_mat_.at(m)));
+			// using default ware quantity, not the best solution but will do
+			if (get_warehoused_stock(wt) <
+			    tribe_->get_ware_descr(wt)->default_target_quantity() * 2 / 3) {
+				bo.build_material_shortage_ = true;
 			}
 		}
 	}
@@ -1060,25 +1165,17 @@
 	int16_t max_needed_preciousness = 0;  // preciousness_ of most precious NEEDED output
 
 	// first scan all buildable fields for regular buildings
-	for (std::list<BuildableField*>::iterator i = buildable_fields.begin();
-	     i != buildable_fields.end();
-	     ++i) {
-		BuildableField* const bf = *i;
+	for (const BuildableField* buildable_field : buildable_fields) {
 
-		// if 'buildable field' update is overdue for more then 8 seconds
-		// (= bf has not been updated for about 15 seconds)
-		// skip the bf in evaluation, bacause information
-		// contained in bf are too old
-		if (bf->next_update_due_ < gametime - 8000) {
+		if (buildable_field->next_update_due_ < gametime - 8000) {
 			continue;
 		}
 
 		// Continue if field is blocked at the moment
 		field_blocked = false;
 
-		for (std::list<BlockedField>::iterator j = blocked_fields.begin(); j != blocked_fields.end();
-		     ++j) {
-			if (j->coords == bf->coords) {
+		for (const BlockedField& blocked_field : blocked_fields) {
+			if (blocked_field.coords == buildable_field->coords) {
 				field_blocked = true;
 			}
 		}
@@ -1089,7 +1186,7 @@
 		}
 
 		assert(player_);
-		int32_t const maxsize = player_->get_buildcaps(bf->coords) & BUILDCAPS_SIZEMASK;
+		int32_t const maxsize = player_->get_buildcaps(buildable_field->coords) & BUILDCAPS_SIZEMASK;
 
 		// For every field test all buildings
 		for (uint32_t j = 0; j < buildings_.size(); ++j) {
@@ -1108,6 +1205,13 @@
 				continue;
 			}
 
+			// testing for reserved ports
+			if (!bo.is_port_) {
+				if (port_reserved_coords.count(coords_hash(buildable_field->coords)) > 0) {
+					continue;
+				}
+			}
+
 			if (time(nullptr) % 3 == 0 && bo.total_count() > 0) {
 				continue;
 			}  // add randomnes and ease AI
@@ -1139,13 +1243,13 @@
 			if (bo.type == BuildingObserver::PRODUCTIONSITE) {
 
 				// exclude spots on border
-				if (bf->near_border_ && !bo.need_trees_ && !bo.need_stones_ && !bo.is_fisher_) {
+				if (buildable_field->near_border_ && !bo.need_trees_ && !bo.need_stones_ && !bo.is_fisher_) {
 					continue;
 				}
 
 				// this can be only a well (as by now)
 				if (bo.mines_water_) {
-					if (bf->ground_water_ < 2) {
+					if (buildable_field->ground_water_ < 2) {
 						continue;
 					}
 
@@ -1171,8 +1275,8 @@
 					if (bo.stocklevel_ > 50 + productionsites.size() * 5) {
 						continue;
 					}
-					prio += bf->ground_water_ - 2;
-					prio = recalc_with_border_range(*bf, prio);
+					prio += buildable_field->ground_water_ - 2;
+					prio = recalc_with_border_range(*buildable_field, prio);
 
 				} else if (bo.need_trees_) {  // LUMBERJACS
 
@@ -1180,14 +1284,14 @@
 					   3 + static_cast<int32_t>(mines_.size() + productionsites.size()) / 15;
 
 					if (bo.total_count() == 0) {
-						prio = 500 + bf->trees_nearby_;
+						prio = 500 + buildable_field->trees_nearby_;
 					}
 
 					else if (bo.total_count() == 1) {
-						prio = 400 + bf->trees_nearby_;
+						prio = 400 + buildable_field->trees_nearby_;
 					}
 
-					else if (bf->trees_nearby_ < 2) {
+					else if (buildable_field->trees_nearby_ < 2) {
 						continue;
 					}
 
@@ -1199,15 +1303,15 @@
 							prio = 0;
 						}
 
-						if (bf->producers_nearby_.at(bo.outputs_.at(0)) > 1) {
+						if (buildable_field->producers_nearby_.at(bo.outputs_.at(0)) > 1) {
 							continue;
 						}
 
-						prio += 2 * bf->trees_nearby_ - 10 -
-						        bf->producers_nearby_.at(bo.outputs_.at(0)) * 5 -
+						prio += 2 * buildable_field->trees_nearby_ - 10 -
+								  buildable_field->producers_nearby_.at(bo.outputs_.at(0)) * 5 -
 						        new_buildings_stop_ * 15;
 
-						if (bf->near_border_) {
+						if (buildable_field->near_border_) {
 							prio = prio / 2;
 						}
 					}
@@ -1220,7 +1324,7 @@
 					if (bo.cnt_under_construction_ > 0) {
 						continue;
 					}
-					prio = bf->stones_nearby_;
+					prio = buildable_field->stones_nearby_;
 
 					if (prio <= 0) {
 						continue;
@@ -1240,14 +1344,14 @@
 					}
 
 					// to prevent to many quaries on one spot
-					prio = prio - 50 * bf->producers_nearby_.at(bo.outputs_.at(0));
+					prio = prio - 50 * buildable_field->producers_nearby_.at(bo.outputs_.at(0));
 
-					if (bf->near_border_) {
+					if (buildable_field->near_border_) {
 						prio = prio / 2;
 					}
 
 				} else if (bo.is_hunter_) {
-					if (bf->critters_nearby_ < 5) {
+					if (buildable_field->critters_nearby_ < 5) {
 						continue;
 					}
 
@@ -1256,7 +1360,7 @@
 					}
 
 					prio +=
-					   (bf->critters_nearby_ * 2) - 8 - 5 * bf->producers_nearby_.at(bo.outputs_.at(0));
+						(buildable_field->critters_nearby_ * 2) - 8 - 5 * buildable_field->producers_nearby_.at(bo.outputs_.at(0));
 
 				} else if (bo.is_fisher_) {  // fisher
 
@@ -1269,7 +1373,7 @@
 						continue;
 					}
 
-					if (bf->water_nearby_ < 2) {
+					if (buildable_field->water_nearby_ < 2) {
 						continue;
 					}
 
@@ -1288,11 +1392,11 @@
 						continue;
 					}
 
-					if (bf->producers_nearby_.at(bo.outputs_.at(0)) >= 1) {
+					if (buildable_field->producers_nearby_.at(bo.outputs_.at(0)) >= 1) {
 						continue;
 					}
 
-					prio = bf->fish_nearby_ - new_buildings_stop_ * 15 * bo.total_count();
+					prio = buildable_field->fish_nearby_ - new_buildings_stop_ * 15 * bo.total_count();
 
 				} else if (bo.production_hint_ >= 0) {
 					// first setting targets (needed also for dismantling)
@@ -1311,7 +1415,7 @@
 					if (bo.plants_trees_) {  // RANGERS
 
 						// if there are too many trees nearby
-						if (bf->trees_nearby_ > 25 && bo.total_count() >= 1) {
+						if (buildable_field->trees_nearby_ > 25 && bo.total_count() >= 1) {
 							continue;
 						}
 
@@ -1339,12 +1443,12 @@
 						}
 
 						// considering near trees and producers
-						prio += (30 - bf->trees_nearby_) * 2 +
-						        bf->producers_nearby_.at(bo.production_hint_) * 5 -
+						prio += (30 - buildable_field->trees_nearby_) * 2 +
+								  buildable_field->producers_nearby_.at(bo.production_hint_) * 5 -
 						        new_buildings_stop_ * 15;
 
 						// considering space consumers nearby
-						prio -= bf->space_consumers_nearby_ * 5;
+						prio -= buildable_field->space_consumers_nearby_ * 5;
 
 					} else {  // FISH BREEDERS and GAME KEEPERS
 						if (new_buildings_stop_ && bo.total_count() > 0) {
@@ -1352,11 +1456,11 @@
 						}
 
 						// especially for fish breeders
-						if (bo.need_water_ && bf->water_nearby_ < 2) {
+						if (bo.need_water_ && buildable_field->water_nearby_ < 2) {
 							continue;
 						}
 						if (bo.need_water_) {
-							prio += bf->water_nearby_ / 5;
+							prio += buildable_field->water_nearby_ / 5;
 						}
 
 						if (bo.total_count() > bo.cnt_target_) {
@@ -1373,14 +1477,14 @@
 						}
 
 						if (bo.total_count() == 0 && gametime > 45 * 1000) {
-							prio += 100 + bf->producers_nearby_.at(bo.production_hint_) * 10;
-						} else if (bf->producers_nearby_.at(bo.production_hint_) == 0) {
+							prio += 100 + buildable_field->producers_nearby_.at(bo.production_hint_) * 10;
+						} else if (buildable_field->producers_nearby_.at(bo.production_hint_) == 0) {
 							continue;
 						} else {
-							prio += bf->producers_nearby_.at(bo.production_hint_) * 10;
+							prio += buildable_field->producers_nearby_.at(bo.production_hint_) * 10;
 						}
 
-						if (bf->enemy_nearby_) {
+						if (buildable_field->enemy_nearby_) {
 							prio -= 10;
 						}
 					}
@@ -1405,6 +1509,10 @@
 					} else if (bo.cnt_built_ == 1 && game().get_gametime() > 40 * 60 * 1000 &&
 					           bo.desc->enhancement() != INVALID_INDEX && !mines_.empty()) {
 						prio += 10;
+					} else if (bo.is_shipyard_) {
+						if (!seafaring_economy) {
+							continue;
+						}
 					} else if (!output_is_needed) {
 						continue;
 					} else if (bo.cnt_built_ == 0 && game().get_gametime() > 40 * 60 * 1000) {
@@ -1420,31 +1528,37 @@
 						prio += max_needed_preciousness + kDefaultPrioBoost;
 
 						if (bo.space_consumer_) {  // need to consider trees nearby
-							prio += 20 - (bf->trees_nearby_ / 3);
+							prio += 20 - (buildable_field->trees_nearby_ / 3);
 						}
 
 						// we attempt to cluster space consumers together
 						if (bo.space_consumer_) {  // need to consider trees nearby
-							prio += bf->space_consumers_nearby_ * 2;
+							prio += buildable_field->space_consumers_nearby_ * 2;
 						}
 
-						if (bo.space_consumer_ && !bf->water_nearby_) {  // not close to water
+						if (bo.space_consumer_ && !buildable_field->water_nearby_) {  // not close to water
 							prio += 1;
 						}
 
 						if (bo.space_consumer_ &&
-						    !bf->unowned_mines_pots_nearby_) {  // not close to mountains
+							 !buildable_field->unowned_mines_pots_nearby_) {  // not close to mountains
 							prio += 1;
 						}
 
 						if (!bo.space_consumer_) {
-							prio -= bf->producers_nearby_.at(bo.outputs_.at(0)) * 20;
+							prio -= buildable_field->producers_nearby_.at(bo.outputs_.at(0)) * 20;
 						}  // leave some free space between them
 
-						prio -= bf->space_consumers_nearby_ * 3;
+						prio -= buildable_field->space_consumers_nearby_ * 3;
 					}
 
-					if (!bo.inputs_.empty()) {
+					else if (bo.is_shipyard_) {
+						// for now AI builds only one shipyard
+						if (buildable_field->water_nearby_ > 3 && bo.total_count() == 0 && seafaring_economy) {
+							prio += kDefaultPrioBoost + productionsites.size() * 5 + buildable_field->water_nearby_;
+						}
+
+					} else if (!bo.inputs_.empty()) {
 						if (bo.total_count() == 0) {
 							prio += max_needed_preciousness + kDefaultPrioBoost;
 						}
@@ -1462,7 +1576,7 @@
 					consumers_nearby_count = 0;
 
 					for (size_t k = 0; k < bo.outputs_.size(); ++k)
-						consumers_nearby_count += bf->consumers_nearby_.at(bo.outputs_.at(k));
+						consumers_nearby_count += buildable_field->consumers_nearby_.at(bo.outputs_.at(k));
 
 					if (consumers_nearby_count > 0) {
 						prio += 1;
@@ -1473,11 +1587,11 @@
 
 				// we allow 1 exemption from big buildings prohibition
 				if (bo.build_material_shortage_ &&
-				    (bo.cnt_under_construction_ > 0 || !(bf->enemy_nearby_))) {
+					 (bo.cnt_under_construction_ > 0 || !(buildable_field->enemy_nearby_))) {
 					continue;
 				}
 
-				if (!bf->unowned_land_nearby_) {
+				if (!buildable_field->unowned_land_nearby_) {
 					continue;
 				}
 
@@ -1489,21 +1603,21 @@
 					continue;
 				}
 
-				if (expansion_mode == kDefenseOnly && !bf->enemy_nearby_) {
+				if (expansion_mode == kDefenseOnly && !buildable_field->enemy_nearby_) {
 					continue;
 				}
 
-				if (bf->enemy_nearby_ && bo.fighting_type_) {
+				if (buildable_field->enemy_nearby_ && bo.fighting_type_) {
 					;
 				}  // it is ok, go on
-				else if (bf->unowned_mines_pots_nearby_ > 2 &&
+				else if (buildable_field->unowned_mines_pots_nearby_ > 2 &&
 				         (bo.mountain_conqueror_ || bo.expansion_type_)) {
 					;
 				}  // it is ok, go on
-				else if (bf->unowned_land_nearby_ && bo.expansion_type_ &&
+				else if (buildable_field->unowned_land_nearby_ && bo.expansion_type_ &&
 				         num_milit_constructionsites <= 1) {
 					;  // we allow big buildings now
-				} else if (bf->unowned_land_nearby_ &&
+				} else if (buildable_field->unowned_land_nearby_ &&
 				           bo.expansion_type_) {  // decreasing probability for big buidlings
 					if (bo.desc->get_size() == 2 && gametime % 15 >= 1) {
 						continue;
@@ -1518,8 +1632,8 @@
 				}  // the building is not suitable for situation
 
 				// not to build so many military buildings nearby
-				if (!bf->enemy_nearby_ &&
-				    (bf->military_in_constr_nearby_ + bf->military_unstationed_) > 0) {
+				if (!buildable_field->enemy_nearby_ &&
+					 (buildable_field->military_in_constr_nearby_ + buildable_field->military_unstationed_) > 0) {
 					continue;
 				}
 
@@ -1529,14 +1643,14 @@
 					local_boost = 200;
 				}
 
-				prio = (bf->unowned_land_nearby_ * 2 * resource_necessity_territory_ / 255 +
-				        bf->unowned_mines_pots_nearby_ * resource_necessity_mines_ / 255 +
-				        bf->stones_nearby_ / 2 + bf->military_loneliness_ / 10 - 60 + local_boost +
-				        bf->water_nearby_ * resource_necessity_water_ / 255);
+				prio = (buildable_field->unowned_land_nearby_ * 2 * resource_necessity_territory_ / 255 +
+						  buildable_field->unowned_mines_pots_nearby_ * resource_necessity_mines_ / 255 +
+						  buildable_field->stones_nearby_ / 2 + buildable_field->military_loneliness_ / 10 - 60 + local_boost +
+						  buildable_field->water_nearby_ * resource_necessity_water_ / 255);
 
 				// special bonus due to remote water for atlanteans
 				if (resource_necessity_water_needed_)
-					prio += bf->distant_water_ * resource_necessity_water_ / 255;
+					prio += buildable_field->distant_water_ * resource_necessity_water_ / 255;
 
 				if (bo.desc->get_size() < maxsize) {
 					prio = prio - 5;
@@ -1549,20 +1663,30 @@
 				// for expansion)
 				const int16_t bottom_treshold =
 				   15 - ((virtual_mines <= 4) ? (5 - virtual_mines) * 2 : 0);
-				if (bf->enemy_nearby_ && bf->military_capacity_ < bottom_treshold) {
-					prio += 50 + (bottom_treshold - bf->military_capacity_) * 20;
+				if (buildable_field->enemy_nearby_ && buildable_field->military_capacity_ < bottom_treshold) {
+					prio += 50 + (bottom_treshold - buildable_field->military_capacity_) * 20;
 				}
 
-				if (bf->enemy_nearby_ && bf->military_capacity_ > bottom_treshold + 4) {
-					prio -= (bf->military_capacity_ - (bottom_treshold + 4)) * 5;
+				if (buildable_field->enemy_nearby_ && buildable_field->military_capacity_ > bottom_treshold + 4) {
+					prio -= (buildable_field->military_capacity_ - (bottom_treshold + 4)) * 5;
 				}
 
 			} else if (bo.type == BuildingObserver::WAREHOUSE) {
 
 				// exclude spots on border
-				if (bf->near_border_) {
-					continue;
-				}
+				if (buildable_field->near_border_ && !bo.is_port_) {
+					continue;
+				}
+
+				if (!buildable_field->is_portspace_ && bo.is_port_) {
+					continue;
+				}
+
+				if (bo.cnt_under_construction_ > 0) {
+					continue;
+				}
+
+				bool warehouse_needed = false;
 
 				//  Build one warehouse for ~every 35 productionsites and mines_.
 				//  Militarysites are slightly important as well, to have a bigger
@@ -1572,64 +1696,107 @@
 				       static_cast<int32_t>(numof_warehouses_) &&
 				    bo.cnt_under_construction_ == 0) {
 					prio = 20;
-				}
-
-				// take care about borders and enemies
-				if (bf->enemy_nearby_) {
-					prio /= 2;
-				}
-
-				if (bf->unowned_land_nearby_) {
-					prio /= 2;
-				}
-
-				// TODO(unknown): introduce check that there is no warehouse nearby
-				// to prevent too close placing
+					warehouse_needed = true;
+				}
+
+				// but generally we prefer ports
+				if (bo.is_port_) {
+					prio += 10;
+				}
+
+				// special boost for first port
+				if (bo.is_port_ && bo.total_count() == 0 && productionsites.size() > 5 &&
+					 !buildable_field->enemy_nearby_ && buildable_field->is_portspace_ && seafaring_economy) {
+					prio += kDefaultPrioBoost + productionsites.size();
+					warehouse_needed = true;
+				}
+
+				if (!warehouse_needed) {
+					continue;
+				}
+
+				// iterating over current warehouses and testing a distance
+				// getting distance to nearest warehouse and adding it to a score
+				uint16_t nearest_distance = std::numeric_limits<uint16_t>::max();
+				for (const WarehouseSiteObserver& wh_obs : warehousesites) {
+					const uint16_t actual_distance =
+						map.calc_distance(buildable_field->coords, wh_obs.site->get_position());
+					nearest_distance = std::min(nearest_distance, actual_distance);
+				}
+				//but limit to 15
+				const uint16_t max_distance_considered = 15;
+				nearest_distance = std::min(nearest_distance, max_distance_considered);
+				prio += nearest_distance;
+
+				// take care about and enemies
+				if (buildable_field->enemy_nearby_) {
+					prio /= 2;
+				}
+
+				if (buildable_field->unowned_land_nearby_ && !bo.is_port_) {
+					prio /= 2;
+				}
 
 			} else if (bo.type == BuildingObserver::TRAININGSITE) {
 
+				if (virtual_mines < 5) {
+					continue;
+				}
+
 				// exclude spots on border
-				if (bf->near_border_) {
+				if (buildable_field->near_border_) {
 					continue;
 				}
 
-				if (virtual_mines<3) {
+				if (virtual_mines < 3) {
 					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() &&
+				if (static_cast<int32_t>((productionsites.size() + 40) / 60) > bo.total_count() &&
 				    bo.cnt_under_construction_ == 0) {
 					prio = 4 + kDefaultPrioBoost;
 				}
 
 				// take care about borders and enemies
-				if (bf->enemy_nearby_) {
+				if (buildable_field->enemy_nearby_) {
 					prio /= 2;
 				}
 
-				if (bf->unowned_land_nearby_) {
+				if (buildable_field->unowned_land_nearby_) {
 					prio /= 2;
 				}
 			}
 
 			// think of space consuming buildings nearby like farms or vineyards
-			prio -= bf->space_consumers_nearby_ * 10;
+			prio -= buildable_field->space_consumers_nearby_ * 10;
 
 			// Stop here, if priority is 0 or less.
 			if (prio <= 0) {
 				continue;
 			}
 
+			// testing also vicinity
+			if (!bo.is_port_) {
+				if (port_reserved_coords.count(coords_hash(buildable_field->coords)) > 0) {
+					continue;
+				}
+			}
+
 			// Prefer road side fields
-			prio += bf->preferred_ ? 1 : 0;
+			prio += buildable_field->preferred_ ? 1 : 0;
 			// don't waste good land for small huts
 			prio -= (maxsize - bo.desc->get_size()) * 5;
 
+			// prefer vicinity of ports (with exemption of warehouses)
+			if (buildable_field->port_nearby_ && bo.type == BuildingObserver::MILITARYSITE) {
+				prio *= 2;
+			}
+
 			if (prio > proposed_priority) {
 				best_building = &bo;
 				proposed_priority = prio;
-				proposed_coords = bf->coords;
+				proposed_coords = buildable_field->coords;
 			}
 		}  // ending loop over buildings
 	}     // ending loop over fields
@@ -1687,18 +1854,16 @@
 				}
 
 				// iterating over fields
-				for (std::list<MineableField*>::iterator j = mineable_fields.begin();
-				     j != mineable_fields.end();
-				     ++j) {
+				for (const MineableField* mineable_field : mineable_fields) {
 
-					if ((*j)->coords.field->get_resources() != bo.mines_) {
+					if (mineable_field->coords.field->get_resources() != bo.mines_) {
 						continue;
 					}
 
-					int32_t prio = (*j)->coords.field->get_resources_amount();
+					int32_t prio = mineable_field->coords.field->get_resources_amount();
 
 					// applying nearnes penalty
-					prio = prio - (*j)->mines_nearby_ * nearness_penalty;
+					prio = prio - mineable_field->mines_nearby_ * nearness_penalty;
 
 					// Only build mines_ on locations where some material can be mined
 					if (prio < 2) {
@@ -1708,10 +1873,8 @@
 					// Continue if field is blocked at the moment
 					bool blocked = false;
 
-					for (std::list<BlockedField>::iterator k = blocked_fields.begin();
-					     k != blocked_fields.end();
-					     ++k)
-						if ((*j)->coords == k->coords) {
+					for (const BlockedField& blocked_field :blocked_fields)
+						if (mineable_field->coords == blocked_field.coords) {
 							blocked = true;
 							break;
 						}
@@ -1722,13 +1885,13 @@
 					}
 
 					// Prefer road side fields
-					prio += (*j)->preferred_ ? 1 : 0;
+					prio += mineable_field->preferred_ ? 1 : 0;
 
 					if (prio > proposed_priority) {
 						// proposed_building = bo.id;
 						best_building = &bo;
 						proposed_priority = prio;
-						proposed_coords = (*j)->coords;
+						proposed_coords = mineable_field->coords;
 						mine = true;
 					}
 				}  // end of evaluation of field
@@ -1762,7 +1925,6 @@
 			block_time = 25 * 1000;
 			block_area = 6;
 		}
-		Map& map = game().map();
 
 		MapRegion<Area<FCoords>> mr(map, Area<FCoords>(map.get_fcoords(proposed_coords), block_area));
 		do {
@@ -1924,10 +2086,10 @@
 			continue;
 		}
 
-		std::vector<NearFlag>::iterator f =
+		std::vector<NearFlag>::iterator near_flag_it =
 		   find(reachableflags.begin(), reachableflags.end(), queue.top().flag);
 
-		if (f != reachableflags.end()) {
+		if (near_flag_it != reachableflags.end()) {
 			queue.pop();
 			continue;
 		}
@@ -1968,7 +2130,38 @@
 	// 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;
@@ -2014,7 +2207,7 @@
 
 	for (const Coords& reachable_coords : reachable) {
 
-		// first make sure there is an immovable (shold be, but still)
+		// first make sure there is an immovable (should be, but still)
 		if (upcast(PlayerImmovable const, player_immovable, map[reachable_coords].get_immovable())) {
 
 			// if it is the road, make a flag there
@@ -2034,7 +2227,7 @@
 			}
 
 			// now make sure that this field has not been processed yet
-			const int32_t hash = reachable_coords.x << 16 | reachable_coords.y;
+			const uint32_t hash = coords_hash(reachable_coords);
 			if (lookuptable.count(hash) == 0) {
 				lookuptable.insert(hash);
 
@@ -2075,10 +2268,10 @@
 
 	// algorithm to walk on roads
 	while (!queue.empty()) {
-		std::vector<NearFlag>::iterator f =
+		std::vector<NearFlag>::iterator near_flag_it =
 		   find(nearflags_tmp.begin(), nearflags_tmp.end(), queue.top().flag);
 
-		if (f != nearflags_tmp.end()) {
+		if (near_flag_it != nearflags_tmp.end()) {
 			queue.pop();
 			continue;
 		}
@@ -2113,21 +2306,16 @@
 	// iterating over nearflags_tmp, each item in nearflags_tmp should be contained also in nearflags
 	// so for each corresponding field in nearflags we update "cost" (distance on existing roads)
 	// to actual value
-	for (std::vector<NearFlag>::iterator nf_walk_it = nearflags_tmp.begin();
-	     nf_walk_it != nearflags_tmp.end();
-	     ++nf_walk_it) {
-		int32_t const hash_walk =
-		   nf_walk_it->flag->get_position().x << 16 | nf_walk_it->flag->get_position().y;
+	for (const NearFlag& temp_near_flag : nearflags_tmp) {
+		uint32_t const hash_walk = coords_hash(temp_near_flag.flag->get_position());
 		if (lookuptable.count(hash_walk) > 0) {
-			// iterting over nearflags
-			for (std::vector<NearFlag>::iterator nf_it = nearflags.begin(); nf_it != nearflags.end();
-			     ++nf_it) {
-				int32_t const hash =
-				   nf_it->flag->get_position().x << 16 | nf_it->flag->get_position().y;
+			// iterating over nearflags
+			for (NearFlag& near_flag : nearflags) {
+				uint32_t const hash = coords_hash(near_flag.flag->get_position());
 				if (hash == hash_walk) {
 					// decreasing "cost" (of walking via roads)
-					if (nf_it->cost_ > nf_walk_it->cost_) {
-						nf_it->cost_ = nf_walk_it->cost_;
+					if (near_flag.cost_ > temp_near_flag.cost_) {
+						near_flag.cost_ = temp_near_flag.cost_;
 					}
 				}
 			}
@@ -2200,26 +2388,21 @@
 		get_economy_observer(flag.economy())->flags.push_back(&flag);
 	}
 
-	for (std::list<EconomyObserver*>::iterator obs_iter = economies.begin();
-	     obs_iter != economies.end();
-	     ++obs_iter) {
+	for (EconomyObserver* economy_observer : economies) {
 		// check if any flag has changed its economy
-		std::list<Flag const*>& fl = (*obs_iter)->flags;
+		std::list<Flag const*>& fl = economy_observer->flags;
 
-		for (std::list<Flag const*>::iterator j = fl.begin(); j != fl.end();) {
-			if (&(*obs_iter)->economy != &(*j)->economy()) {
-				get_economy_observer((*j)->economy())->flags.push_back(*j);
-				j = fl.erase(j);
-			} else {
-				++j;
+		for (const Flag* flag : fl) {
+			if (&economy_observer->economy != &flag->economy()) {
+				get_economy_observer(flag->economy())->flags.push_back(flag);
+				fl.remove(flag);
 			}
 		}
 
 		// if there are no more flags in this economy,
 		// we no longer need it's observer
-		if ((*obs_iter)->flags.empty()) {
-			delete *obs_iter;
-			economies.erase(obs_iter);
+		if (economy_observer->flags.empty()) {
+			economies.remove(economy_observer);
 			return true;
 		}
 	}
@@ -2488,7 +2671,7 @@
 	}
 
 	// remaining buildings without inputs and not supporting ones (fishers only left probably and
-	// huters)
+	// hunters)
 
 	if (site.bo->inputs_.empty() && site.bo->production_hint_ < 0 &&
 	    site.site->can_start_working() && !site.bo->space_consumer_ &&
@@ -2536,6 +2719,209 @@
 	return changed;
 }
 
+// This function scans current situation with shipyards, ports, ships, ongoing expeditions
+// and makes two decisions:
+// - build a ship
+// - start preparation for expedition
+bool DefaultAI::marine_main_decisions(uint32_t const gametime) {
+	if (gametime < next_marine_decisions_due) {
+		return false;
+	}
+	next_marine_decisions_due += kMarineDecisionInterval;
+
+	if (!seafaring_economy) {
+		return false;
+	}
+
+	// getting some base statistics
+	player_ = game().get_player(player_number());
+	uint16_t ports_count = 0;
+	uint16_t shipyards_count = 0;
+	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)
+	for (const WarehouseSiteObserver& wh_obs : warehousesites) {
+		if (wh_obs.bo->is_port_) {
+			ports_count += 1;
+			if (Widelands::PortDock* pd = wh_obs.site->get_portdock()) {
+				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);
+			}
+		}
+	}
+
+	// goes over productionsites and gets status of shipyards
+	for (const ProductionSiteObserver& ps_obs : productionsites) {
+		if (ps_obs.bo->is_shipyard_) {
+			shipyards_count += 1;
+			if (!ps_obs.site->is_stopped()) {
+				working_shipyards_count += 1;
+			}
+			// counting stocks
+			uint8_t stocked_wares = 0;
+			std::vector<WaresQueue*> const warequeues = ps_obs.site->warequeues();
+			size_t const nr_warequeues = warequeues.size();
+			for (size_t i = 0; i < nr_warequeues; ++i) {
+				stocked_wares += warequeues[i]->get_filled();
+			}
+			if (stocked_wares == 16 && ps_obs.site->is_stopped()) {
+				idle_shipyard_stocked = true;
+			}
+		}
+	}
+
+	// and now over ships
+	for (const ShipObserver& ship_observer : allships) {
+		if (ship_observer.ship->state_is_expedition()) {
+			expeditions_in_progress += 1;
+		}
+	}
+
+	// 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_it = remote_ports_coords.begin();
+		  ports_it != remote_ports_coords.end();
+		  ++ports_it) {
+		still_ours = false;
+		FCoords fcoords = game().map().get_fcoords(coords_unhash(*ports_it));
+		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_it);
+			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)) {
+		enough_ships = FleetStatus::kEnoughShips;
+	} else if (static_cast<float>(allships.size()) <
+	           static_cast<float>((territories_count - 1) * 0.6 + ports_count * 0.75)) {
+		enough_ships = FleetStatus::kNeedShip;
+	}
+
+	// building a ship? if yes, find a shipyard and order it to build a ship
+	if (shipyards_count > 0 && enough_ships == FleetStatus::kNeedShip && idle_shipyard_stocked &&
+	    ports_count > 0) {
+
+		for (const ProductionSiteObserver& ps_obs : productionsites) {
+			if (ps_obs.bo->is_shipyard_ && ps_obs.site->can_start_working() &&
+			    ps_obs.site->is_stopped()) {
+				// make sure it is fully stocked
+				// counting stocks
+				uint8_t stocked_wares = 0;
+				std::vector<WaresQueue*> const warequeues = ps_obs.site->warequeues();
+				size_t const nr_warequeues = warequeues.size();
+				for (size_t i = 0; i < nr_warequeues; ++i) {
+					stocked_wares += warequeues[i]->get_filled();
+				}
+				if (stocked_wares < 16) {
+					continue;
+				}
+
+				game().send_player_start_stop_building(*ps_obs.site);
+				return true;
+			}
+		}
+	}
+
+	// starting an expedition? if yes, find a port and order it to start an expedition
+	if (ports_count > 0 && enough_ships == FleetStatus::kEnoughShips && expeditions_in_prep == 0 &&
+	    expeditions_in_progress == 0) {
+		// we need to find a port
+		for (const WarehouseSiteObserver& wh_obs : warehousesites) {
+
+			if (wh_obs.bo->is_port_) {
+				game().send_player_start_or_cancel_expedition(*wh_obs.site);
+				return true;
+			}
+		}
+	}
+	return true;
+}
+
+// This identifies ships that are waiting for command
+bool DefaultAI::check_ships(uint32_t const gametime) {
+	if (gametime < next_ship_check_due) {
+		return false;
+	}
+
+	next_ship_check_due += kShipCheckInterval;
+
+	if (!seafaring_economy) {
+		return false;
+	}
+
+	if (!allships.empty()) {
+		// Iterating over ships and executing what is needed.
+		for (ShipObserver& ship_observer : allships) {
+			// Only two states need attention.
+			if ((ship_observer.ship->get_ship_state() == Widelands::Ship::EXP_WAITING ||
+				  ship_observer.ship->get_ship_state() == Widelands::Ship::EXP_FOUNDPORTSPACE) &&
+				 !ship_observer.waiting_for_command_) {
+				if (gametime - ship_observer.last_command_time > 180 * 1000) {
+					ship_observer.waiting_for_command_ = true;
+					log("  %1d: last command for ship at %3dx%3d was %3d seconds ago, something wrong "
+					    "here?...\n",
+					    player_number(),
+						 ship_observer.ship->get_position().x,
+						 ship_observer.ship->get_position().y,
+						 (gametime - ship_observer.last_command_time) / 1000);
+				}
+			}
+			// If ship is waiting for command.
+			if (ship_observer.waiting_for_command_) {
+				expedition_management(ship_observer);
+			}
+		}
+	}
+
+	// processing marineTaskQueue_
+	while (!marineTaskQueue_.empty()) {
+		if (marineTaskQueue_.back() == kStopShipyard) {
+			// iterate over all production sites searching for shipyard
+			for (const ProductionSiteObserver& prod_site_observer : productionsites) {
+				if (prod_site_observer.bo->is_shipyard_) {
+					if (!prod_site_observer.site->is_stopped()) {
+						game().send_player_start_stop_building(*prod_site_observer.site);
+					}
+				}
+			}
+		}
+
+		if (marineTaskQueue_.back() == kReprioritize) {
+			for (const ProductionSiteObserver& prod_site_observer : productionsites) {
+				if (prod_site_observer.bo->is_shipyard_) {
+					for (uint32_t k = 0; k < prod_site_observer.bo->inputs_.size(); ++k) {
+						game().send_player_set_ware_priority(
+							*prod_site_observer.site, wwWARE, prod_site_observer.bo->inputs_.at(k), HIGH_PRIORITY);
+					}
+				}
+			}
+		}
+		marineTaskQueue_.pop_back();
+	}
+	return true;
+}
+
 /**
  * checks the first mine in list, takes care if it runs out of
  * resources and finally reenqueues it at the end of the list.
@@ -2640,7 +3026,7 @@
                                      int16_t* max_preciousness,
                                      int16_t* max_needed_preciousness) {
 
-	// reseting values
+	// resetting values
 	*output_is_needed = false;
 	*max_preciousness = 0;
 	*max_needed_preciousness = 0;
@@ -2709,6 +3095,43 @@
 	return count;
 }
 
+// counts produced output in warehouses (only)
+// perhaps it will be able to replace get_stocklevel
+uint32_t DefaultAI::get_warehoused_stock(WareIndex wt) {
+	uint32_t count = 0;
+	for (const WarehouseSiteObserver& warehouse_observer :  warehousesites) {
+		count += warehouse_observer.site->get_wares().stock(wt);
+	}
+	return count;
+}
+
+// this function only manipulates with trainingsites' inputs priority
+// decreases it when too many unoccupied military buildings
+bool DefaultAI::check_trainingsites(int32_t gametime) {
+	if (next_trainingsites_check_due_ > gametime) {
+		return false;
+	}
+	if (!trainingsites.empty()) {
+		next_trainingsites_check_due_ = gametime + kTrainingSitesCheckInterval;
+	} else {
+		next_trainingsites_check_due_ = gametime + 3 * kTrainingSitesCheckInterval;
+	}
+
+	uint8_t new_priority = DEFAULT_PRIORITY;
+	if (unstationed_milit_buildings_ > 2) {
+		new_priority = LOW_PRIORITY;
+	} else {
+		new_priority = DEFAULT_PRIORITY;
+	}
+	for (const TrainingSiteObserver& trainingsite_observer :trainingsites) {
+		for (uint32_t k = 0; k < trainingsite_observer.bo->inputs_.size(); ++k) {
+			game().send_player_set_ware_priority(
+				*trainingsite_observer.site, wwWARE, trainingsite_observer.bo->inputs_.at(k), new_priority);
+		}
+	}
+	return true;
+}
+
 /**
  * Updates the first military building in list and reenques it at the end of
  * the list afterwards. If a militarysite is in secure area but holds more than
@@ -2728,10 +3151,8 @@
 	// construction
 	unstationed_milit_buildings_ = 0;
 
-	for (std::list<MilitarySiteObserver>::iterator it = militarysites.begin();
-	     it != militarysites.end();
-	     ++it) {
-		if (it->site->stationed_soldiers().size() == 0) {
+	for (const MilitarySiteObserver& militarysite_observer : militarysites) {
+		if (militarysite_observer.site->stationed_soldiers().size() == 0) {
 			unstationed_milit_buildings_ += 1;
 		}
 	}
@@ -2929,9 +3350,11 @@
 
 /// \returns the economy observer containing \arg economy
 EconomyObserver* DefaultAI::get_economy_observer(Economy& economy) {
-	for (std::list<EconomyObserver*>::iterator i = economies.begin(); i != economies.end(); ++i)
-		if (&(*i)->economy == &economy)
-			return *i;
+	for (EconomyObserver* economy_observer : economies) {
+		if (&economy_observer->economy == &economy) {
+			return economy_observer;
+		}
+	}
 
 	economies.push_front(new EconomyObserver(economy));
 	return economies.front();
@@ -2969,20 +3392,16 @@
 		lose_building(*building);
 	} else if (upcast(Flag const, flag, &pi)) {
 		for (EconomyObserver* eco_obs : economies) {
-			for (std::list<Flag const*>::iterator flag_iter = eco_obs->flags.begin();
-			     flag_iter != eco_obs->flags.end();
-			     ++flag_iter) {
-				if (*flag_iter == flag) {
-					eco_obs->flags.erase(flag_iter);
+			for (const Flag* economy_flag : eco_obs->flags) {
+				if (economy_flag == flag) {
+					eco_obs->flags.remove(economy_flag);
 					return;
 				}
 			}
 		}
-		for (std::list<Flag const*>::iterator flag_iter = new_flags.begin();
-		     flag_iter != new_flags.end();
-		     ++flag_iter) {
-			if (*flag_iter == flag) {
-				new_flags.erase(flag_iter);
+		for (const Flag* new_flag : new_flags) {
+			if (new_flag == flag) {
+				new_flags.remove(new_flag);
 				return;
 			}
 		}
@@ -2995,20 +3414,217 @@
 void DefaultAI::out_of_resources_site(const ProductionSite& site) {
 
 	// we must identify which mine matches the productionsite a note reffers to
-	for (std::list<ProductionSiteObserver>::iterator i = mines_.begin(); i != mines_.end(); ++i)
-		if (i->site == &site) {
-			i->no_resources_count += 1;
+	for (ProductionSiteObserver& mine_observer : mines_)
+		if (mine_observer.site == &site) {
+			mine_observer.no_resources_count += 1;
 			break;
 		}
 }
 
+// this scores spot for potential colony
+uint8_t DefaultAI::spot_scoring(Widelands::Coords candidate_spot) {
+
+	uint8_t score = 0;
+	uint16_t mineable_fields_count = 0;
+	Map& map = game().map();
+	// first making sure there are no other players nearby
+	std::list<uint32_t> queue;
+	std::unordered_set<uint32_t> done;
+	queue.push_front(coords_hash(candidate_spot));
+	while (!queue.empty()) {
+
+		// if already processed
+		if (done.count(queue.front()) > 0) {
+			queue.pop_front();
+			continue;
+		}
+
+		done.insert(queue.front());
+
+		Coords tmp_coords = coords_unhash(queue.front());
+
+		// if beyond range
+		if (map.calc_distance(candidate_spot, tmp_coords) > colony_scan_area_) {
+			continue;
+		}
+
+		Field* f = map.get_fcoords(tmp_coords).field;
+
+		// if owned by someone:
+		if (f->get_owned_by() > 0) {
+			// just return 0 as score
+			return 0;
+		}
+
+		// not interested if not walkable
+		if (!(f->nodecaps() & MOVECAPS_WALK)) {
+			continue;
+		}
+
+		// increase mines counter
+		if (f->nodecaps() & BUILDCAPS_MINE) {
+			mineable_fields_count += 1;
+		};
+
+		// add neighbours to a queue (duplicates are no problem)
+		// to relieve AI/CPU we skip every second field in each direction
+		// obstacles are usually wider then one field
+		for (Direction dir = FIRST_DIRECTION; dir <= LAST_DIRECTION; ++dir) {
+			Coords neigh_coords1;
+			map.get_neighbour(tmp_coords, dir, &neigh_coords1);
+			Coords neigh_coords2;
+			map.get_neighbour(neigh_coords1, dir, &neigh_coords2);
+			queue.push_front(coords_hash(neigh_coords2));
+		}
+	}
+
+	// if the island is too small
+	if (done.size() < 50) {
+		return 0;
+	}
+
+	// if we are here we put score
+	score = 1;
+	if (mineable_fields_count > 0) {
+		score += 1;
+	}
+
+	// here we check for surface stones + trees
+	std::vector<ImmovableFound> immovables;
+	// Search in a radius of range
+	map.find_immovables(Area<FCoords>(map.get_fcoords(candidate_spot), 10), &immovables);
+
+	int32_t const stone_attr = MapObjectDescr::get_attribute_id("granite");
+	uint16_t stones = 0;
+	int32_t const tree_attr = MapObjectDescr::get_attribute_id("tree");
+	uint16_t trees = 0;
+
+	for (uint32_t j = 0; j < immovables.size(); ++j) {
+		if (immovables.at(j).object->has_attribute(stone_attr)) {
+			++stones;
+		}
+		if (immovables.at(j).object->has_attribute(tree_attr)) {
+			++trees;
+		}
+	}
+	if (stones > 1) {
+		score += 1;
+	}
+	if (trees > 1) {
+		score += 1;
+	}
+
+	return score;
+}
+
+// this is called whenever ship received a notification that requires
+// navigation decisions (these notifiation are processes not in 'real time')
+void DefaultAI::expedition_management(ShipObserver& so) {
+
+	Map& map = game().map();
+	const int32_t gametime = game().get_gametime();
+
+	// first we put current spot into visited_spots_
+	bool first_time_here = false;
+	if (so.visited_spots_.count(coords_hash(so.ship->get_position())) == 0) {
+		first_time_here = true;
+		so.visited_spots_.insert(coords_hash(so.ship->get_position()));
+	}
+
+	// If we have portspace following options are avaiable:
+	// 1. Build a port there
+	if (so.ship->exp_port_spaces()->size() > 0) {  // making sure we have possible portspaces
+
+		// we score the place
+		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));
+			game().send_player_ship_construct_port(*so.ship, so.ship->exp_port_spaces()->front());
+			so.last_command_time = gametime;
+			so.waiting_for_command_ = false;
+			// blocking the area for some time to save AI from idle attempts to built there
+			// buildings
+			// TODO(TiborB): how long it takes to build a port?
+			// I used 5 minutes
+			MapRegion<Area<FCoords>> mr(
+			   game().map(), Area<FCoords>(map.get_fcoords(so.ship->exp_port_spaces()->front()), 8));
+			do {
+				BlockedField blocked2(
+				   map.get_fcoords(*(mr.location().field)), gametime + 5 * 60 * 1000);
+				blocked_fields.push_back(blocked2);
+			} while (mr.advance(map));
+
+			return;
+		}
+
+		// decreasing colony_scan_area_
+		if (colony_scan_area_ > 15 && gametime % 10 == 0) {
+			colony_scan_area_ -= 1;
+		}
+	}
+
+	// if we are here, port was not ordered above
+	// 2. Go on with expedition
+
+	if (first_time_here) {
+		game().send_player_ship_explore_island(*so.ship, so.island_circ_direction);
+		so.last_command_time = gametime;
+		so.waiting_for_command_ = false;
+
+		// we was here but to add randomnes we might continue with expedition
+	} else if (gametime % 2 == 0) {
+		game().send_player_ship_explore_island(*so.ship, so.island_circ_direction);
+		so.last_command_time = gametime;
+		so.waiting_for_command_ = false;
+	} else {
+		// get swimable directions
+		std::vector<Direction> possible_directions;
+		for (Direction dir = FIRST_DIRECTION; dir <= LAST_DIRECTION; ++dir) {
+
+			// testing distance of 8 fields
+			// this would say there is an 'open sea' there
+			Widelands::FCoords tmp_fcoords = map.get_fcoords(so.ship->get_position());
+			for (int8_t i = 0; i < 8; ++i) {
+				tmp_fcoords = map.get_neighbour(tmp_fcoords, dir);
+				if (tmp_fcoords.field->nodecaps() & MOVECAPS_SWIM) {
+					if (i == 7) {
+						possible_directions.push_back(dir);
+						break;  // not needed but.....
+					}
+				} else {
+					break;
+				}
+			}
+		}
+
+		// we test if there is open sea
+		if (possible_directions.empty()) {
+			// 2.A No there is no open sea
+			game().send_player_ship_explore_island(*so.ship, so.island_circ_direction);
+			so.last_command_time = gametime;
+			so.waiting_for_command_ = false;
+			;
+		} else {
+			// 2.B Yes, pick one of avaiable directions
+			const Direction final_direction =
+			   possible_directions.at(gametime % possible_directions.size());
+			game().send_player_ship_scout_direction(*so.ship, final_direction);
+			so.last_command_time = gametime;
+			so.waiting_for_command_ = false;
+		}
+	}
+	return;
+}
+
 // this is called whenever we gain a new building
 void DefaultAI::gain_building(Building& b) {
 	BuildingObserver& bo = get_building_observer(b.descr().name().c_str());
 
 	if (bo.type == BuildingObserver::CONSTRUCTIONSITE) {
 		BuildingObserver& target_bo =
-		   get_building_observer(dynamic_cast<ConstructionSite&>(b).building().name().c_str());
+		   get_building_observer(dynamic_cast<const ConstructionSite&>(b).building().name().c_str());
 		++target_bo.cnt_under_construction_;
 		++num_constructionsites_;
 		if (target_bo.type == BuildingObserver::PRODUCTIONSITE) {
@@ -3031,6 +3647,10 @@
 			productionsites.back().unoccupied_till_ = game().get_gametime();
 			productionsites.back().stats_zero_ = 0;
 			productionsites.back().no_resources_count = 0;
+			if (bo.is_shipyard_) {
+				marineTaskQueue_.push_back(kStopShipyard);
+				marineTaskQueue_.push_back(kReprioritize);
+			}
 
 			for (uint32_t i = 0; i < bo.outputs_.size(); ++i)
 				++wares.at(bo.outputs_.at(i)).producers_;
@@ -3055,8 +3675,19 @@
 			militarysites.back().checks = bo.desc->get_size();
 			militarysites.back().enemies_nearby_ = true;
 
+		} else if (bo.type == BuildingObserver::TRAININGSITE) {
+			trainingsites.push_back(TrainingSiteObserver());
+			trainingsites.back().site = &dynamic_cast<TrainingSite&>(b);
+			trainingsites.back().bo = &bo;
+
 		} else if (bo.type == BuildingObserver::WAREHOUSE) {
 			++numof_warehouses_;
+			warehousesites.push_back(WarehouseSiteObserver());
+			warehousesites.back().site = &dynamic_cast<Warehouse&>(b);
+			warehousesites.back().bo = &bo;
+			if (bo.is_port_) {
+				++num_ports;
+			}
 		}
 	}
 }
@@ -3066,8 +3697,8 @@
 	BuildingObserver& bo = get_building_observer(b.descr().name().c_str());
 
 	if (bo.type == BuildingObserver::CONSTRUCTIONSITE) {
-		BuildingObserver& target_bo = get_building_observer(
-			dynamic_cast<const ConstructionSite&>(b).building().name().c_str());
+		BuildingObserver& target_bo =
+		   get_building_observer(dynamic_cast<const ConstructionSite&>(b).building().name().c_str());
 		--target_bo.cnt_under_construction_;
 		--num_constructionsites_;
 		if (target_bo.type == BuildingObserver::PRODUCTIONSITE) {
@@ -3082,11 +3713,11 @@
 
 		if (bo.type == BuildingObserver::PRODUCTIONSITE) {
 
-			for (std::list<ProductionSiteObserver>::iterator i = productionsites.begin();
-			     i != productionsites.end();
-			     ++i)
-				if (i->site == &b) {
-					productionsites.erase(i);
+			for (std::list<ProductionSiteObserver>::iterator prod_site_observer_it = productionsites.begin();
+				  prod_site_observer_it != productionsites.end();
+				  ++prod_site_observer_it)
+				if (prod_site_observer_it->site == &b) {
+					productionsites.erase(prod_site_observer_it);
 					break;
 				}
 
@@ -3098,10 +3729,10 @@
 				--wares.at(bo.inputs_.at(i)).consumers_;
 			}
 		} else if (bo.type == BuildingObserver::MINE) {
-			for (std::list<ProductionSiteObserver>::iterator i = mines_.begin(); i != mines_.end();
-			     ++i) {
-				if (i->site == &b) {
-					mines_.erase(i);
+			for (std::list<ProductionSiteObserver>::iterator mines_observer_it = mines_.begin(); mines_observer_it != mines_.end();
+				  ++mines_observer_it) {
+				if (mines_observer_it->site == &b) {
+					mines_.erase(mines_observer_it);
 					break;
 				}
 			}
@@ -3115,17 +3746,39 @@
 			}
 		} else if (bo.type == BuildingObserver::MILITARYSITE) {
 
-			for (std::list<MilitarySiteObserver>::iterator i = militarysites.begin();
-			     i != militarysites.end();
-			     ++i) {
-				if (i->site == &b) {
-					militarysites.erase(i);
+			for (std::list<MilitarySiteObserver>::iterator militarysite_observer_it = militarysites.begin();
+				  militarysite_observer_it != militarysites.end();
+				  ++militarysite_observer_it) {
+				if (militarysite_observer_it->site == &b) {
+					militarysites.erase(militarysite_observer_it);
+					break;
+				}
+			}
+		} else if (bo.type == BuildingObserver::TRAININGSITE) {
+
+			for (std::list<TrainingSiteObserver>::iterator trainingsite_observer_it = trainingsites.begin();
+				  trainingsite_observer_it != trainingsites.end();
+				  ++trainingsite_observer_it) {
+				if (trainingsite_observer_it->site == &b) {
+					trainingsites.erase(trainingsite_observer_it);
 					break;
 				}
 			}
 		} else if (bo.type == BuildingObserver::WAREHOUSE) {
 			assert(numof_warehouses_ > 0);
 			--numof_warehouses_;
+			if (bo.is_port_) {
+				--num_ports;
+			}
+
+			for (std::list<WarehouseSiteObserver>::iterator warehouse_observer_it = warehousesites.begin();
+				  warehouse_observer_it != warehousesites.end();
+				  ++warehouse_observer_it) {
+				if (warehouse_observer_it->site == &b) {
+					warehousesites.erase(warehouse_observer_it);
+					break;
+				}
+			}
 		}
 	}
 
@@ -3134,7 +3787,7 @@
 }
 
 // Checks that supply line exists for given building.
-// Recurcsively verify that all inputs_ have a producer.
+// Recursively verify that all inputs_ have a producer.
 // TODO(unknown): this function leads to periodic freezes of ~1 second on big games on my system.
 // TODO(unknown): It needs profiling and optimization.
 // NOTE: This is not needed anymore and it seems it is not missed neither
@@ -3165,7 +3818,7 @@
 
 bool DefaultAI::consider_attack(int32_t const gametime) {
 
-	// we presume that we are not attacking so we extend waitperiod
+	// we assume that we are not attacking so we extend waitperiod
 	// in case of attack the variable will be decreased below
 	// this is intended to save some CPU and add randomness in attacking
 	// and also differentiate according to type
@@ -3248,13 +3901,13 @@
 			if (genstats.at(j - 1).miltary_strength.empty()) {
 				log("ComputerPlayer(%d): miltary_strength is empty\n", player_number());
 				player_attackable.at(j - 1) = false;
-			// Avoid division by zero
+				// Avoid division by zero
 			} else if (genstats.at(j - 1).miltary_strength.back() == 0) {
 				player_attackable.at(j - 1) = true;
 				any_attackable = true;
-			// Check threshold
+				// Check threshold
 			} else if ((genstats.at(pn - 1).miltary_strength.back() * 100 /
-							genstats.at(j - 1).miltary_strength.back()) > treshold_ratio) {
+			            genstats.at(j - 1).miltary_strength.back()) > treshold_ratio) {
 				player_attackable.at(j - 1) = true;
 				any_attackable = true;
 			} else {
@@ -3262,7 +3915,8 @@
 			}
 		} catch (const std::out_of_range&) {
 			log("ComputerPlayer(%d): genstats entry missing - size :%d\n",
-				 player_number(), static_cast<unsigned int>(genstats.size()));
+			    player_number(),
+			    static_cast<unsigned int>(genstats.size()));
 			player_attackable.at(j - 1) = false;
 		}
 	}
@@ -3288,13 +3942,13 @@
 
 	for (uint32_t position = gametime % test_every; position < militarysites.size();
 	     position += test_every) {
-		// checked_own_ms_tmp += 1;
-		std::list<MilitarySiteObserver>::iterator mso = militarysites.begin();
-		std::advance(mso, position);
-
-		MilitarySite* ms = mso->site;
-
-		if (!mso->enemies_nearby_) {
+
+		std::list<MilitarySiteObserver>::iterator militarysite_observer_it = militarysites.begin();
+		std::advance(militarysite_observer_it, position);
+
+		MilitarySite* ms = militarysite_observer_it->site;
+
+		if (!militarysite_observer_it->enemies_nearby_) {
 			continue;
 		}
 
@@ -3308,10 +3962,8 @@
 		for (uint32_t j = 0; j < immovables.size(); ++j) {
 
 			// skip if in irrelevant_immovables
-			const uint32_t hash = immovables.at(j).coords.x << 16 | immovables.at(j).coords.y;
-			if (irrelevant_immovables.count(hash) > 0) {
-				continue;
-			} else {
+			const uint32_t hash = coords_hash(immovables.at(j).coords);
+			if (irrelevant_immovables.count(hash) == 0) {
 				irrelevant_immovables.insert(hash);
 			}
 
@@ -3334,7 +3986,6 @@
 						continue;
 					}
 
-					// target_buildings.push_back(immovables.at(j));
 					const int32_t soldiers_difference =
 					   player_->find_attack_soldiers(bld->base_flag()) - bld->present_soldiers().size();
 
@@ -3379,7 +4030,7 @@
 		}
 	}
 
-	// we allways try to attack warehouse first
+	// we always try to attack warehouse first
 	if (best_wh_target != nullptr && gametime % 2 == 0) {
 		// attacking with all attack-ready soldiers
 		int32_t attackers = player_->find_attack_soldiers(best_wh_target->base_flag());
@@ -3413,6 +4064,34 @@
 	}
 }
 
+// This runs once in 15 minutes, and adjust wares targets based on number of
+// productionsites and ports
+void DefaultAI::review_wares_targets(int32_t const gametime) {
+
+	player_ = game().get_player(player_number());
+	tribe_ = &player_->tribe();
+
+	// to avoid floats real multiplicator is multiplicator/10
+	uint16_t multiplicator = 10;
+	if ((productionsites.size() + num_ports * 5) > 50) {
+		multiplicator = (productionsites.size() + num_ports * 5) / 5;
+	}
+
+	for (EconomyObserver* observer : economies) {
+		WareIndex nritems = observer->economy.owner().tribe().get_nrwares();
+		for (Widelands::WareIndex id = 0; id < nritems; ++id) {
+			const uint16_t default_target = tribe_->get_ware_descr(id)->default_target_quantity();
+
+			game().send_player_command(*new Widelands::CmdSetWareTargetQuantity(
+			                              gametime,
+			                              player_number(),
+			                              player_->get_economy_number(&observer->economy),
+			                              id,
+			                              default_target * multiplicator / 10));
+		}
+	}
+}
+
 // This is used for profiling, so usually this is not used :)
 void DefaultAI::print_land_stats() {
 	// this will just print statistics of land size

=== modified file 'src/ai/defaultai.h'
--- src/ai/defaultai.h	2014-10-17 19:13:39 +0000
+++ src/ai/defaultai.h	2014-12-20 20:51:12 +0000
@@ -22,11 +22,14 @@
 
 #include <map>
 #include <memory>
+#include <unordered_set>
+
 
 #include "ai/ai_help_structs.h"
 #include "ai/computer_player.h"
 #include "base/i18n.h"
 #include "logic/immovable.h"
+#include "logic/ship.h"
 
 namespace Widelands {
 struct Road;
@@ -130,6 +133,18 @@
 
 	bool construct_building(int32_t);
 
+	uint32_t coords_hash(Widelands::Coords coords) {
+		uint32_t hash = coords.x << 16 | coords.y;
+		return hash;
+	}
+
+	Widelands::Coords coords_unhash(uint32_t hash) {
+		Widelands::Coords coords;
+		coords.x = hash >> 16;  // is cast needed here???
+		coords.y = hash;
+		return coords;
+	}
+
 	// all road management is invoked by function improve_roads()
 	// if needed it calls create_shortcut_road() with a flag from which
 	// new road should be considered (or is needed)
@@ -139,18 +154,25 @@
 	bool dispensable_road_test(const Widelands::Road&);
 	bool check_economies();
 	bool check_productionsites(int32_t);
+	bool check_trainingsites(int32_t);
 	bool check_mines_(int32_t);
 	bool check_militarysites(int32_t);
+	bool marine_main_decisions(uint32_t);
+	bool check_ships(uint32_t);
 	uint32_t get_stocklevel_by_hint(size_t);
 	uint32_t get_stocklevel(BuildingObserver&);
+	uint32_t get_warehoused_stock(Widelands::WareIndex wt);
 	uint32_t get_stocklevel(Widelands::WareIndex);  // count all direct outputs_
 	void check_helpersites(int32_t);
+	void review_wares_targets(int32_t);
 
 	int32_t recalc_with_border_range(const BuildableField&, int32_t);
 	int32_t calculate_need_for_ps(BuildingObserver&, int32_t);
 
 	void
 	consider_productionsite_influence(BuildableField&, Widelands::Coords, const BuildingObserver&);
+	// considering wood, stones, mines, water, fishes for candidate for colonization (new port)
+	uint8_t spot_scoring(Widelands::Coords candidate_spot);
 
 	EconomyObserver* get_economy_observer(Widelands::Economy&);
 	BuildingObserver& get_building_observer(char const*);
@@ -159,6 +181,7 @@
 	void lose_immovable(const Widelands::PlayerImmovable&);
 	void gain_building(Widelands::Building&);
 	void lose_building(const Widelands::Building&);
+	void expedition_management(ShipObserver&);
 	void out_of_resources_site(const Widelands::ProductionSite&);
 
 	bool check_supply(const BuildingObserver&);
@@ -181,10 +204,14 @@
 	uint32_t num_constructionsites_;
 	uint32_t num_milit_constructionsites;
 	uint32_t num_prod_constructionsites;
+	uint32_t num_ports;
 
 	std::list<Widelands::FCoords> unusable_fields;
 	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;
@@ -193,6 +220,9 @@
 	std::list<ProductionSiteObserver> productionsites;
 	std::list<ProductionSiteObserver> mines_;
 	std::list<MilitarySiteObserver> militarysites;
+	std::list<WarehouseSiteObserver> warehousesites;
+	std::list<TrainingSiteObserver> trainingsites;
+	std::list<ShipObserver> allships;
 
 	std::vector<WareObserver> wares;
 
@@ -203,9 +233,12 @@
 	int32_t next_productionsite_check_due_;
 	int32_t next_mine_check_due_;
 	int32_t next_militarysite_check_due_;
+	uint32_t next_ship_check_due;
+	uint32_t next_marine_decisions_due;
 	int32_t next_attack_consideration_due_;
-	int32_t next_helpersites_check_due_;
+	int32_t next_trainingsites_check_due_;
 	int32_t next_bf_check_due_;
+	int32_t next_wares_review_due_;
 	int32_t inhibit_road_building_;
 	int32_t time_of_last_construction_;
 	int32_t enemy_last_seen_;
@@ -232,13 +265,20 @@
 	Widelands::Coords
 	   last_attack_target_;         // flag to abuilding (position) that was attacked last time
 	int32_t next_attack_waittime_;  // second till the next attack consideration
-	int32_t spots_;                 // sum of buildable fields
+	bool seafaring_economy;  // false by default, until first port space is found
+	uint32_t colony_scan_area_;  // distance from a possible port that is scanned for owned territory
+	// it decreases with failed scans
+	int32_t spots_;  // sum of buildable fields
+
+	enum {kReprioritize, kStopShipyard, kStapShipyard};
+	std::vector<int16_t> marineTaskQueue_;
 
 	std::unique_ptr<Notifications::Subscriber<Widelands::NoteFieldPossession>>
 	   field_possession_subscriber_;
 	std::unique_ptr<Notifications::Subscriber<Widelands::NoteImmovable>> immovable_subscriber_;
 	std::unique_ptr<Notifications::Subscriber<Widelands::NoteProductionSiteOutOfResources>>
 	   outofresource_subscriber_;
+	std::unique_ptr<Notifications::Subscriber<Widelands::NoteShipMessage>> shipnotes_subscriber_;
 };
 
 #endif  // end of include guard: WL_AI_DEFAULTAI_H

=== modified file 'src/economy/portdock.cc'
--- src/economy/portdock.cc	2014-12-11 21:32:41 +0000
+++ src/economy/portdock.cc	2014-12-20 20:51:12 +0000
@@ -21,6 +21,8 @@
 
 #include <memory>
 
+#include <boost/format.hpp>
+
 #include "base/log.h"
 #include "base/macros.h"
 #include "economy/fleet.h"
@@ -165,8 +167,13 @@
 }
 
 void PortDock::cleanup(EditorGameBase& egbase) {
+
+	Warehouse* wh = nullptr;
+
 	if (egbase.objects().object_still_available(m_warehouse)) {
-		// Transfer all our wares into the warehouse.
+
+		wh = m_warehouse;
+
 		if (upcast(Game, game, &egbase)) {
 			for (ShippingItem& shipping_item : m_waiting) {
 				WareInstance* ware;
@@ -180,6 +187,7 @@
 				}
 			}
 		}
+
 		m_waiting.clear();
 		m_warehouse->m_portdock = nullptr;
 	}
@@ -203,6 +211,20 @@
 	}
 
 	PlayerImmovable::cleanup(egbase);
+
+	if (wh) {
+		if (upcast(Game, game, &egbase)) {
+			if (game->is_loaded()) {
+				Player& player = owner();
+				log("Message: Portdock lost, trying to restore it (player %d)\n",
+				    player.player_number());
+				wh->restore_portdock_or_destroy(egbase);
+				return;
+			}
+		}
+		// this is not a (running) game, destroying the port
+		wh->destroy(egbase);
+	}
 }
 
 /**

=== modified file 'src/logic/player.cc'
--- src/logic/player.cc	2014-12-16 21:39:00 +0000
+++ src/logic/player.cc	2014-12-20 20:51:12 +0000
@@ -56,6 +56,7 @@
 #include "sound/sound_handler.h"
 #include "wui/interactive_player.h"
 
+namespace Widelands {
 
 namespace {
 
@@ -90,11 +91,43 @@
 	}
 }
 
-
-
-}
-
-namespace Widelands {
+/**
+* Sort soldiers on priority, most wanted soldiers first.
+* On return, \param soldiers is filled with up to \param max soldiers.
+*/
+struct SoldierPriority {
+	Soldier* soldier;
+	int priority;  // (strength + 1) * health - position in building.
+};
+
+void sort_soldiers(std::vector<SoldierPriority>* soldiers,
+                          uint32_t max = std::numeric_limits<uint32_t>::max()) {
+	std::vector<SoldierPriority> temp;
+	SoldierPriority soldier;
+	uint32_t left = soldiers->size();
+
+	while (left) {
+		int32_t maxlevel = -1;
+		uint32_t pos = 0;
+		uint32_t maxpos = 0;
+		for (const SoldierPriority& soldier_priority : *soldiers) {
+			const int32_t level = soldier_priority.priority;
+			if (level > maxlevel) {
+				maxlevel = level;
+				maxpos = pos;
+				soldier.soldier = soldier_priority.soldier;
+				soldier.priority = level;
+			}
+			pos++;
+		}
+		temp.push_back(soldier);
+		soldiers->erase(soldiers->begin() + maxpos);
+		left--;
+	}
+	soldiers->insert(soldiers->end(), temp.begin(), temp.begin() + std::min<int>(max, temp.size()));
+}
+
+}
 
 const RGBColor Player::Colors[MAX_PLAYERS] = {
 	RGBColor(2,     2, 198),  // blue
@@ -879,57 +912,73 @@
 */
 
 /**
- * Get a list of soldiers that this player can use to attack the
- * building at the given flag.
- *
- * The default attack should just take the first N soldiers of the
- * returned array.
- */
-// TODO(unknown): Perform a meaningful sort on the soldiers array.
-uint32_t Player::find_attack_soldiers
-	(Flag & flag, std::vector<Soldier *> * soldiers, uint32_t nr_wanted)
-{
-	uint32_t count = 0;
+* Return the number of soldiers that can attack the building at the
+* given flag, limited to \param nr_wanted.
+*
+* If \param soldiers != NULL it will be filled with soldiers selected
+* on health and strength while trying to select the soldiers from
+* multiple buildings.
+*/
+uint32_t
+Player::find_attack_soldiers(Flag& flag, std::vector<Soldier*>* soldiers, uint32_t nr_wanted) {
+	std::vector<SoldierPriority> attackers_all;
+	uint32_t nr_available = 0;
 
 	if (soldiers)
 		soldiers->clear();
 
-	Map & map = egbase().map();
-	std::vector<BaseImmovable *> flags;
+	Map& map = egbase().map();
+	std::vector<BaseImmovable*> flags;
 
-	map.find_reachable_immovables_unique
-		(Area<FCoords>(map.get_fcoords(flag.get_position()), 25),
-		 flags,
-		 CheckStepDefault(MOVECAPS_WALK),
-		 FindFlagOf(FindImmovablePlayerMilitarySite(*this)));
+	map.find_reachable_immovables_unique(Area<FCoords>(map.get_fcoords(flag.get_position()), 25),
+	                                     flags,
+	                                     CheckStepDefault(MOVECAPS_WALK),
+	                                     FindFlagOf(FindImmovablePlayerMilitarySite(*this)));
 
 	if (flags.empty())
 		return 0;
 
-	for (BaseImmovable * temp_flag : flags) {
-		upcast(Flag, attackerflag, temp_flag);
-		upcast(MilitarySite, ms, attackerflag->get_building());
-		std::vector<Soldier *> const present = ms->present_soldiers();
-		uint32_t const nr_staying = ms->min_soldier_capacity();
-		uint32_t const nr_present = present.size();
+	// Count (and if necessary collect) available soldiers.
+	for (const BaseImmovable* base_immovable : flags) {
+		const Flag* attackerflag = static_cast<const Flag*>(base_immovable);
+		const MilitarySite* ms = static_cast<MilitarySite*>(attackerflag->get_building());
+		std::vector<Soldier*> present = ms->present_soldiers();
+		const uint32_t nr_staying = ms->min_soldier_capacity();
+		const uint32_t nr_present = present.size();
 		if (nr_staying < nr_present) {
-			uint32_t const nr_taken =
-				std::min(nr_wanted, nr_present - nr_staying);
-			if (soldiers)
-				soldiers->insert
-					(soldiers->end(),
-					 present.begin(), present.begin() + nr_taken);
-			count     += nr_taken;
-			nr_wanted -= nr_taken;
-			if (!nr_wanted)
-				break;
+			const uint32_t nr_taken = nr_present - nr_staying;
+			std::vector<SoldierPriority> attackers;
+			if (soldiers) {
+				SoldierPriority temp;
+				for (Soldier* soldier : present) {
+					temp.soldier = soldier;
+					temp.priority =
+					   (soldier->get_level(atrTotal) + 1) * soldier->get_current_hitpoints();
+					attackers.push_back(temp);
+				}
+				sort_soldiers(&attackers, nr_taken);  // Leave weakest soldier behind.
+				int32_t pos = 0;
+				for (SoldierPriority& soldier_priority : attackers) {
+					soldier_priority.priority += pos--;  // Small penalty for position.
+				}
+				attackers_all.insert(attackers_all.end(), attackers.begin(), attackers.end());
+			}
+			nr_available += nr_taken;
+		}
+	}
+	const uint32_t count = std::min(nr_available, nr_wanted);
+
+	if (soldiers) {
+		// Sort soldiers and remove surplus.
+		sort_soldiers(&attackers_all, count);
+		for (const SoldierPriority& soldier_priority : attackers_all) {
+			soldiers->push_back(soldier_priority.soldier);
 		}
 	}
 
 	return count;
 }
 
-
 // TODO(unknown): Clean this mess up. The only action we really have right now is
 // to attack, so pretending we have more types is pointless.
 void Player::enemyflagaction

=== modified file 'src/logic/ship.cc'
--- src/logic/ship.cc	2014-12-12 22:59:39 +0000
+++ src/logic/ship.cc	2014-12-20 20:51:12 +0000
@@ -107,6 +107,7 @@
 void Ship::init(EditorGameBase& egbase) {
 	Bob::init(egbase);
 	init_fleet(egbase);
+	Notifications::publish(NoteShipMessage(this, NoteShipMessage::Message::kGained));
 }
 
 /**
@@ -132,6 +133,8 @@
 		m_items.pop_back();
 	}
 
+	Notifications::publish(NoteShipMessage(this, NoteShipMessage::Message::kLost));
+
 	Bob::cleanup(egbase);
 }
 
@@ -162,10 +165,10 @@
  * ivar1 = helper flag for coordination of mutual evasion of ships
  */
 const Bob::Task Ship::taskShip = {
-   "ship",
-   static_cast<Bob::Ptr>(&Ship::ship_update),
-   nullptr,
-   nullptr,
+	"ship",
+	static_cast<Bob::Ptr>(&Ship::ship_update),
+	nullptr,
+	nullptr,
 	true  // unique task
 };
 
@@ -452,6 +455,9 @@
 			send_message(game, "exp_port_space", msg_head, msg_body, "port.png");
 		}
 		m_expedition->seen_port_buildspaces.swap(temp_port_buildspaces);
+		if (new_port_space) {
+			Notifications::publish(NoteShipMessage(this, NoteShipMessage::Message::kWaitingForCommand));
+		}
 	}
 }
 
@@ -564,6 +570,10 @@
 						send_message(
 						   game, "exp_island", msg_head, msg_body, "ship_explore_island_cw.png");
 						m_ship_state = EXP_WAITING;
+
+						Notifications::publish(
+						   NoteShipMessage(this, NoteShipMessage::Message::kWaitingForCommand));
+
 						return start_task_idle(game, descr().main_animation(), 1500);
 					}
 				}
@@ -620,6 +630,9 @@
 			std::string msg_body =
 			   _("An expedition ship reached a coast and is waiting for further commands.");
 			send_message(game, "exp_coast", msg_head, msg_body, "ship_explore_island_cw.png");
+
+			Notifications::publish(NoteShipMessage(this, NoteShipMessage::Message::kWaitingForCommand));
+
 			return;
 		}
 	}
@@ -627,45 +640,66 @@
 		assert(m_expedition->seen_port_buildspaces && !m_expedition->seen_port_buildspaces->empty());
 		BaseImmovable* baim =
 		   game.map()[m_expedition->seen_port_buildspaces->front()].get_immovable();
-		assert(baim);
-		upcast(ConstructionSite, cs, baim);
+		if (baim) {
+			upcast(ConstructionSite, cs, baim);
 
-		for (int i = m_items.size() - 1; i >= 0; --i) {
-			WareInstance* ware;
-			Worker* worker;
-			m_items.at(i).get(game, &ware, &worker);
-			if (ware) {
-				// no, we don't transfer the wares, we create new ones out of air and remove the old
-				// ones ;)
-				WaresQueue& wq = cs->waresqueue(ware->descr_index());
-				const uint32_t max = wq.get_max_fill();
-				const uint32_t cur = wq.get_filled();
-				assert(max > cur);
-				wq.set_filled(cur + 1);
-				m_items.at(i).remove(game);
-				m_items.resize(i);
-				break;
-			} else {
-				assert(worker);
-				worker->set_economy(nullptr);
-				worker->set_location(cs);
-				worker->set_position(game, cs->get_position());
-				worker->reset_tasks(game);
-				PartiallyFinishedBuilding::request_builder_callback(
-				   game, *cs->get_builder_request(), worker->descr().worker_index(), worker, *cs);
-				m_items.resize(i);
+			for (int i = m_items.size() - 1; i >= 0; --i) {
+				WareInstance* ware;
+				Worker* worker;
+				m_items.at(i).get(game, &ware, &worker);
+				if (ware) {
+					// no, we don't transfer the wares, we create new ones out of air and remove the old
+					// ones ;)
+					WaresQueue& wq = cs->waresqueue(ware->descr_index());
+					const uint32_t max = wq.get_max_fill();
+					const uint32_t cur = wq.get_filled();
+					assert(max > cur);
+					wq.set_filled(cur + 1);
+					m_items.at(i).remove(game);
+					m_items.resize(i);
+					break;
+				} else {
+					assert(worker);
+					worker->set_economy(nullptr);
+					worker->set_location(cs);
+					worker->set_position(game, cs->get_position());
+					worker->reset_tasks(game);
+					PartiallyFinishedBuilding::request_builder_callback(
+					   game, *cs->get_builder_request(), worker->descr().worker_index(), worker, *cs);
+					m_items.resize(i);
+				}
 			}
+		} else {  // it seems that port constructionsite has dissapeared
+			// Send a message to the player, that a port constructionsite is gone
+			std::string msg_head = _("New port constructionsite is gone");
+			std::string msg_body = _("Unloading of wares failed, expedition is cancelled now.");
+			send_message(game, "exp_port_space", msg_head, msg_body, "port.png");
+			send_signal(game, "cancel_expedition");
 		}
-		if (m_items.empty()) {
+
+		if (m_items.empty() || !baim) {  // we are done, either way
 			m_ship_state = TRANSPORT;  // That's it, expedition finished
 
+			// Bring us back into a fleet and a economy.
 			init_fleet(game);
+
+			// for case that there are any workers left on board
+			// (applicable when port construction space is kLost)
+			Worker* worker;
+			for (ShippingItem& item : m_items) {
+				item.get(game, nullptr, &worker);
+				if (worker) {
+					worker->reset_tasks(game);
+					worker->start_task_shipping(game, nullptr);
+				}
+			}
+
 			m_expedition.reset(nullptr);
 
 			if (upcast(InteractiveGameBase, igb, game.get_ibase()))
 				refresh_window(*igb);
+			return start_task_idle(game, descr().main_animation(), 1500);
 		}
-		return start_task_idle(game, descr().main_animation(), 1500);  // unload the next item
 	}
 
 	default: {
@@ -785,6 +819,7 @@
 	const std::string msg_head = _("Expedition Ready");
 	const std::string msg_body = _("An expedition ship is waiting for your commands.");
 	send_message(game, "exp_ready", msg_head, msg_body, "start_expedition.png");
+	Notifications::publish(NoteShipMessage(this, NoteShipMessage::Message::kWaitingForCommand));
 }
 
 /// Initializes / changes the direction of scouting to @arg direction
@@ -820,6 +855,7 @@
 void Ship::exp_cancel(Game& game) {
 	// Running colonization has the highest priority before cancelation
 	// + cancelation only works if an expedition is actually running
+
 	if ((m_ship_state == EXP_COLONIZING) || !state_is_expedition())
 		return;
 	send_signal(game, "cancel_expedition");
@@ -900,11 +936,11 @@
                         const std::string& picture) {
 	std::string rt_description;
 	if (picture.size() > 3) {
-		rt_description = (boost::format("<rt image=pics/%s><p font-face=serif font-size=14>")
-								% picture).str();
-	} else {
-		rt_description = "<rt><p font-face=serif font-size=14>";
-	}
+		rt_description = "<rt image=pics/";
+		rt_description += picture;
+		rt_description += "><p font-size=14 font-face=DejaVuSerif>";
+	} else
+		rt_description = "<rt><p font-size=14 font-face=DejaVuSerif>";
 	rt_description += description;
 	rt_description += "</p></rt>";
 

=== modified file 'src/logic/ship.h'
--- src/logic/ship.h	2014-09-10 08:55:04 +0000
+++ src/logic/ship.h	2014-12-20 20:51:12 +0000
@@ -37,6 +37,19 @@
 struct Fleet;
 class PortDock;
 
+struct NoteShipMessage {
+	CAN_BE_SEND_AS_NOTE(NoteId::ShipMessage)
+
+	Ship* ship;
+
+	enum class Message {kLost, kGained, kWaitingForCommand};
+	Message message;
+
+	NoteShipMessage(Ship* const init_ship, Message const init_message)
+	   : ship(init_ship), message(init_message) {
+	}
+};
+
 struct ShipDescr : BobDescr {
 	ShipDescr
 		(char const * name, char const * descname,

=== modified file 'src/logic/warehouse.cc'
--- src/logic/warehouse.cc	2014-12-12 22:59:39 +0000
+++ src/logic/warehouse.cc	2014-12-20 20:51:12 +0000
@@ -438,7 +438,9 @@
 	Map& map = egbase.map();
 	std::vector<Coords> dock = map.find_portdock(get_position());
 	if (dock.empty()) {
-		log("Attempting to setup port without neighboring water.\n");
+		log("Attempting to setup port without neighboring water (coords: %3dx%3d).\n",
+		    get_position().x,
+		    get_position().y);
 		return;
 	}
 
@@ -460,10 +462,26 @@
 	Building::destroy(egbase);
 }
 
+// if the port still exists and we are in game we first try to restore the portdock
+void Warehouse::restore_portdock_or_destroy(EditorGameBase& egbase) {
+	// re-init the portdock
+	Warehouse::init_portdock(egbase);
+	if (!m_portdock) {
+		log(" Portdock lost, removing the port now (coords: %3dx%3d)\n",
+		    get_position().x,
+		    get_position().y);
+		Building::destroy(egbase);
+	}
+}
+
 /// Destroy the warehouse.
 void Warehouse::cleanup(EditorGameBase& egbase) {
+
+	// storing object of the portdock if exists
+	PortDock* pd = nullptr;
+
 	if (egbase.objects().object_still_available(m_portdock)) {
-		m_portdock->remove(egbase);
+		pd = m_portdock;
 		m_portdock = nullptr;
 	}
 
@@ -497,7 +515,23 @@
 	Player& player = owner();
 	player.unsee_area(Area<FCoords>(map.get_fcoords(get_position()), descr().vision_range()));
 
+	if (upcast(Game, game, &egbase)) {
+		log("Message: removing %s (player %i)\n",
+		    to_string(descr().type()).c_str(),
+		    player.player_number());
+		send_message(*game,
+		             "warehouse",
+		             descr().descname(),
+		             (boost::format(_("A %s was destroyed.")) % descr().descname().c_str()).str(),
+		             true);
+	}
+
 	Building::cleanup(egbase);
+
+	// if there was a portdock, removing it now
+	if (pd) {
+		pd->remove(egbase);
+	}
 }
 
 /// Act regularly to create workers of buildable types without cost. According

=== modified file 'src/logic/warehouse.h'
--- src/logic/warehouse.h	2014-09-19 12:54:54 +0000
+++ src/logic/warehouse.h	2014-12-20 20:51:12 +0000
@@ -136,6 +136,8 @@
 
 	void destroy(EditorGameBase &) override;
 
+	void restore_portdock_or_destroy(EditorGameBase &);
+
 	void act(Game & game, uint32_t data) override;
 
 	void set_economy(Economy *) override;

=== modified file 'src/notifications/note_ids.h'
--- src/notifications/note_ids.h	2014-11-23 14:34:38 +0000
+++ src/notifications/note_ids.h	2014-12-20 20:51:12 +0000
@@ -32,8 +32,9 @@
 	FieldPossession,
 	FieldTransformed,
 	ProductionSiteOutOfResources,
-
+	ShipMessage,
 	GraphicResolutionChanged,
+
 };
 
 #endif  // end of include guard: WL_NOTIFICATIONS_NOTE_IDS_H


Follow ups