← Back to team overview

widelands-dev team mailing list archive

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

 

TiborB has proposed merging lp:~widelands-dev/widelands/ai_ship_tweaks into lp:widelands.

Requested reviews:
  Widelands Developers (widelands-dev)

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

Initial goal of this branch is to improve management of expeditions and buildings of new ships. This also makes use of data saving available to AI.

AI now calculates utilization of ships and orders new ones based on this. But I run into two issues:
- serial number of a ship is changed after save/load - this made the code a bit complicated
- termination of expedition is somehow broken. I was unable to make AI terminate it. Maybe I will look at it later.

Additional issues fixed
- Management of trainingsites was broken by changes to AI scheduler made lately
- Upgrading of buildings was too aggressive leading to too many upgraded buildings 
-- 
Your team Widelands Developers is requested to review the proposed merge of lp:~widelands-dev/widelands/ai_ship_tweaks into lp:widelands.
=== modified file 'src/ai/defaultai.cc'
--- src/ai/defaultai.cc	2015-12-06 19:57:49 +0000
+++ src/ai/defaultai.cc	2015-12-10 20:18:09 +0000
@@ -29,6 +29,7 @@
 #include "ai/ai_hints.h"
 #include "base/log.h"
 #include "base/macros.h"
+#include "base/time_string.h"
 #include "economy/economy.h"
 #include "economy/flag.h"
 #include "economy/portdock.h"
@@ -62,23 +63,30 @@
 constexpr int kMinMFCheckInterval = 19 * 1000;
 constexpr int kShipCheckInterval = 5 * 1000;
 constexpr int kMarineDecisionInterval = 20 * 1000;
-constexpr int kTrainingSitesCheckInterval = 45 * 1000;
+constexpr int kTrainingSitesCheckInterval = 15 * 1000;
 
-// least radius to scan terrain when considering colonization port
+// handfull of constants used for expeditions/colonization
+constexpr int kColonyScanStartArea = 35;
 constexpr int kColonyScanMinArea = 10;
+constexpr int kExpeditionMaxDuration = 90 * 60 * 1000;
+constexpr uint32_t kNoShip = std::numeric_limits<uint32_t>::max();
+const uint32_t kNoExpedition = 0;
 
 // this is intended for map developers, by default should be off
 constexpr bool kPrintStats = false;
 
-constexpr int kPersistentData  = 0; //int16_t
+constexpr int kPersistentData  = 0; //int16_t & bools
 constexpr int kMilitLoneliness = 1;
 constexpr int kAttacker        = 2;
+constexpr int kShipUtil        = 3;
+constexpr int kNoExpeditions   = 4;
 constexpr int kAttackMargin    = 0; //uint32_t
 constexpr int kLastAttack      = 1;
 constexpr int kProdRatio       = 2;
 constexpr int kColonyScan      = 3;
 constexpr int kTreesAround     = 4;
 constexpr int kEarlyMilitary   = 5;
+constexpr int kExpStartTime    = 6;
 constexpr int kWoodDiff        = 0; //int32_t
 constexpr int kTargetMilit     = 1;
 constexpr int kLeastMilit      = 2;
@@ -126,7 +134,11 @@
      military_last_dismantle_(0),
      military_last_build_(0),
      seafaring_economy(false),
-     colony_scan_area_(35),
+     colony_scan_area_(kColonyScanStartArea),
+     expedition_start_time_(kNoExpedition),
+     no_more_expeditions_(false),
+     expedition_ship_(kNoShip),
+     ships_utilization_(200),
      spots_(0),
      vacant_mil_positions_(0),
      ts_basic_count_(0),
@@ -134,6 +146,7 @@
      ts_advanced_count_(0),
      ts_advanced_const_count_(0),
      ts_without_trainers_(0),
+     highest_nonmil_prio_(0),
      scheduler_delay_counter_(0),
      ai_personality_military_loneliness_(0),
      ai_personality_attack_margin_(0),
@@ -312,6 +325,7 @@
 
 	// Pool of tasks to be executed this run. In ideal situation it will consist of one task only.
 	std::vector<SchedulerTask> current_task_queue;
+	assert (current_task_queue.empty());
 	// Here we push SchedulerTask members into the temporary queue, providing that a task is due now and
 	// the limit (jobs_to_run_count) is not exceeded
 	for (uint8_t i = 0; i < jobs_to_run_count; i += 1) {
@@ -851,12 +865,12 @@
 
 	// Here the AI persistent data either exists - then they are read
 	// or does not exist, then they are created and saved
-	int16_t persistent_data_exists_ = 0;
+	bool persistent_data_exists_;
 	player_->get_ai_data(&persistent_data_exists_, kPersistentData);
 
-	// 0 implies no saved data exits yet
-	if (persistent_data_exists_ == 0) {
-		player_->set_ai_data(static_cast<int16_t>(1), kPersistentData);
+	// if false, generate new values
+	if (!persistent_data_exists_) {
+		player_->set_ai_data(true, kPersistentData);
 
 		// these random values to make some small differences between players
 		// they are immediately saved
@@ -878,6 +892,9 @@
 
 		// same defaults are directly saved to avoid inconsistency
 		player_->set_ai_data(colony_scan_area_, kColonyScan);
+		player_->set_ai_data(expedition_start_time_, kExpStartTime);
+		player_->set_ai_data(ships_utilization_, kShipUtil);
+		player_->set_ai_data(no_more_expeditions_, kNoExpeditions);
 		player_->set_ai_data(last_attacked_player_, kLastAttack);
 		player_->set_ai_data(least_military_score_, kLeastMilit);
 		player_->set_ai_data(target_military_score_, kTargetMilit);
@@ -911,6 +928,14 @@
 		player_->get_ai_data(&colony_scan_area_, kColonyScan);
 		check_range<uint32_t>(colony_scan_area_, kColonyScanMinArea, 50, "colony_scan_area_");
 
+		player_->get_ai_data(&expedition_start_time_, kExpStartTime);
+		check_range<uint32_t>(expedition_start_time_, kExpStartTime, gametime, "expedition_start_time_");
+
+		player_->get_ai_data(&ships_utilization_, kShipUtil);
+		check_range<uint16_t>(ships_utilization_, 0, 10000, "ships_utilization_");
+
+		player_->get_ai_data(&no_more_expeditions_, kNoExpeditions);
+
 		player_->get_ai_data(&trees_around_cutters_, kTreesAround);
 
 		player_->get_ai_data(&least_military_score_, kLeastMilit);
@@ -1520,6 +1545,11 @@
 	} else {
 		needed_spots = 1300 + (productionsites.size() - 200) * 20;
 	}
+	const bool has_enough_space = (spots_ > needed_spots);
+
+	//This is a replacement for simple count of mines
+	const int32_t virtual_mines =
+	   mines_.size() + mineable_fields.size() / 25;
 
 	// *_military_scores are used as minimal score for a new military building
 	// to be built. As AI does not traverse all building fields at once, these thresholds
@@ -1533,7 +1563,18 @@
 	// least_military_score_ is allowed to get bellow 100 only if there is no military site in construction
 	// right now in order to (try to) avoid expansion lockup
 
-	// this is just helpers to improve readability of code
+	// Bools below are helpers to improve readability of code
+
+	// Military sites have generally higher scores so this is a helper to boost economy
+	bool needs_boost_economy = false;
+	if (highest_nonmil_prio_ > 10
+		&& has_enough_space
+		&& virtual_mines >= 5){
+			needs_boost_economy = true;
+		}
+	//resetting highest_nonmil_prio_ so it can be recalculated anew
+	highest_nonmil_prio_ = 0;
+
 	const bool too_many_ms_constructionsites =
 		(pow(msites_in_constr(), 2) > militarysites.size());
 	const bool too_many_vacant_mil =
@@ -1541,7 +1582,7 @@
 	const int32_t kUpperLimit = 275;
 	const int32_t kBottomLimit = 40; // to prevent too dense militarysites
 	// modifying least_military_score_, down if more military sites are needed and vice versa
-	if (too_many_ms_constructionsites || too_many_vacant_mil) {
+	if (too_many_ms_constructionsites || too_many_vacant_mil || needs_boost_economy) {
 		if (least_military_score_ < kUpperLimit) { //no sense to let it grow too hight
 			least_military_score_ += 2;
 		}
@@ -1580,7 +1621,7 @@
 			new_buildings_stop_ = true;
 	}
 	// 2. to not exhaust all free spots
-	if (spots_ < needed_spots) {
+	if (!has_enough_space) {
 		new_buildings_stop_ = true;
 	}
 	// 3. too keep some proportions production sites vs military sites
@@ -1616,8 +1657,7 @@
 	// set necessity for mines
 	// we use 'virtual mines', because also mine spots can be changed
 	// to mines when AI decides so
-	const int32_t virtual_mines =
-	   mines_.size() + mineable_fields.size() / 25;
+
 	resource_necessity_mines_ = 100 * (15 - virtual_mines) / 15;
 	resource_necessity_mines_ = (resource_necessity_mines_ > 100) ? 100 : resource_necessity_mines_;
 	resource_necessity_mines_ = (resource_necessity_mines_ < 20) ? 10 : resource_necessity_mines_;
@@ -1674,9 +1714,15 @@
 		// checking we have enough critical material on stock
 		for (uint32_t m = 0; m < bo.critical_built_mat_.size(); ++m) {
 			DescriptionIndex wt(static_cast<size_t>(bo.critical_built_mat_.at(m)));
-			// shortage = less then 3 items in warehouses
-			if (get_warehoused_stock(wt) < 3) {
+			uint32_t treshold = 3;
+			//generally trainingsites are more important
+			if (bo.type == BuildingObserver::TRAININGSITE) {
+				treshold = 2;
+			}
+
+			if (get_warehoused_stock(wt) < treshold) {
 				bo.build_material_shortage_ = true;
+				break;
 			}
 		}
 	}
@@ -1763,10 +1809,18 @@
 
 		} else if (bo.type == BuildingObserver::MILITARYSITE) {
 			bo.new_building_ = check_building_necessity(bo.desc->get_size(), gametime);
-		} else if  (bo.type == BuildingObserver::TRAININGSITE
-			&& // if we dont have enough build material or are above target of current ai mode
-			(bo.build_material_shortage_ || bo.aimode_limit_achieved())) {
-				bo.new_building_ = BuildingNecessity::kNotNeeded;
+		} else if  (bo.type == BuildingObserver::TRAININGSITE){
+			if (bo.forced_after_ < gametime && bo.total_count() == 0) {
+				bo.new_building_ = BuildingNecessity::kForced;
+			} else if (ts_without_trainers_ || (ts_basic_const_count_ + ts_advanced_const_count_) > 0) {
+				bo.new_building_ = BuildingNecessity::kNotNeeded;
+			} else if (bo.prohibited_till_ > gametime) {
+				bo.new_building_ = BuildingNecessity::kNotNeeded;
+			} else if (bo.build_material_shortage_ || bo.aimode_limit_achieved()) {
+				bo.new_building_ = BuildingNecessity::kNotNeeded;
+			} else {
+				bo.new_building_ = BuildingNecessity::kAllowed;
+			}
 		} else if (bo.aimode_limit_achieved()) {
 			bo.new_building_ = BuildingNecessity::kNotNeeded;
 		} else {
@@ -2280,53 +2334,45 @@
 
 			} else if (bo.type == BuildingObserver::TRAININGSITE) {
 
-				assert(!bo.build_material_shortage_);
+				prio = 30;
+
+				if (bo.new_building_ == BuildingNecessity::kForced) {
+					prio += 30;
+				}
+
+				if (bo.trainingsite_type_ == TrainingSiteType::kBasic){
+					prio = static_cast<int32_t>(militarysites.size())
+						- 40 * static_cast<int32_t>(ts_basic_count_);
+				}
+
+				if (bo.trainingsite_type_ == TrainingSiteType::kAdvanced) {
+					prio = static_cast<int32_t>(militarysites.size())
+						- 50 * static_cast<int32_t>(ts_advanced_count_);
+				}
 
 				// exclude spots on border
 				if (bf->near_border_) {
-					continue;
-				}
-
-				// it is a bit difficult to get a new trainer.....
-				if (ts_without_trainers_) {
-					continue;
-				}
-
-				// target is only one for both types
-				if ((ts_basic_const_count_ + ts_advanced_const_count_) > 0) {
-					continue;
-				}
-
-				// we build one basic training site for 50 militarysites
-				if (bo.trainingsite_type_ == TrainingSiteType::kBasic &&
-				    militarysites.size() / 50 < static_cast<int32_t>(ts_basic_count_)) {
-					continue;
-				}
-				// we build one advanced training site for 75 militarysites
-				if (bo.trainingsite_type_ == TrainingSiteType::kAdvanced &&
-				    militarysites.size() / 75 < static_cast<int32_t>(ts_advanced_count_)) {
-					continue;
-				}
+					prio -= 5;
+				}
+
 
 				// for type1 we need 15 productionsties
 				if (bo.trainingsite_type_ == TrainingSiteType::kBasic && productionsites.size() < 15) {
-					continue;
+					prio -= 15;
 				}
 
 				// for type2 we need 4 mines
 				if (bo.trainingsite_type_ == TrainingSiteType::kAdvanced && virtual_mines < 4) {
-					continue;
+					prio -= 15;;
 				}
 
-				prio = 10;
-
 				// take care about borders and enemies
 				if (bf->enemy_nearby_) {
-					prio /= 2;
+					prio -= 10;
 				}
 
 				if (bf->unowned_land_nearby_) {
-					prio -= bf->unowned_land_nearby_ / 10;
+					prio -= 5;
 				}
 			}
 
@@ -2369,6 +2415,10 @@
 				prio *= 2;
 			}
 
+			if (bo.type != BuildingObserver::MILITARYSITE && highest_nonmil_prio_ < prio) {
+				highest_nonmil_prio_ = prio;
+			}
+
 			if (prio > proposed_priority) {
 				best_building = &bo;
 				proposed_priority = prio;
@@ -2495,6 +2545,10 @@
 						proposed_coords = mf->coords;
 						mine = true;
 					}
+
+					if (prio > highest_nonmil_prio_) {
+						highest_nonmil_prio_ = prio;
+					}
 				}  // end of evaluation of field
 			}
 
@@ -3156,26 +3210,26 @@
 						doing_upgrade = true;
 					}
 
-					// if the decision was not made yet, consider normal upgrade
-					if (!doing_upgrade) {
-						// compare the performance %
-						if (en_bo.current_stats_ - site.bo->current_stats_
-							> static_cast<uint32_t>(20)) {
-								doing_upgrade = true;
-						}
-
-						if ((static_cast<int32_t>(en_bo.current_stats_) > 85 &&
-						     en_bo.total_count() * 2 < site.bo->total_count()) ||
-						    (static_cast<int32_t>(en_bo.current_stats_) > 50 &&
-						     en_bo.total_count() * 4 < site.bo->total_count())) {
-
-								doing_upgrade = true;
-						}
-
-						// Dont forget about limitation of number of buildings
-						if (en_bo.cnt_limit_by_aimode_ <= en_bo.total_count() - en_bo.unconnected_count_) {
-							doing_upgrade = false;
-						}
+					if (en_bo.total_count() == 1) {
+						//if the upgrade itself can be upgradeed futher, we are more willing to upgrade 2nd building
+						if (en_bo.upgrade_extends_ || en_bo.upgrade_substitutes_) {
+							if (en_bo.current_stats_ > 30) {
+								doing_upgrade = true;
+							}
+						} else if (en_bo.current_stats_ > 50) {
+							doing_upgrade = true;
+						}
+					}
+
+					if (en_bo.total_count() > 1) {
+						if (en_bo.current_stats_ > 80) {
+								doing_upgrade = true;
+						}
+					}
+
+					// Dont forget about limitation of number of buildings
+					if (en_bo.cnt_limit_by_aimode_ <= en_bo.total_count() - en_bo.unconnected_count_) {
+						doing_upgrade = false;
 					}
 				}
 			}
@@ -3502,7 +3556,7 @@
 			for (size_t i = 0; i < nr_warequeues; ++i) {
 				stocked_wares += warequeues[i]->get_filled();
 			}
-			if (stocked_wares == 16 && ps_obs.site->is_stopped()) {
+			if (stocked_wares == 16 && ps_obs.site->is_stopped() && ps_obs.site->can_start_working()) {
 				idle_shipyard_stocked = true;
 			}
 		}
@@ -3516,19 +3570,26 @@
 		}
 	}
 
+	assert (allships.size() >= expeditions_in_progress);
+
 	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()) >= ports_count) {
+	if (shipyards_count == 0 || !idle_shipyard_stocked || ports_count == 0) {
+		enough_ships = FleetStatus::kDoNothing;
+	// We allways need at least one ship in transport mode
+	} else if (allships.size() - expeditions_in_progress == 0) {
+		enough_ships = FleetStatus::kNeedShip;
+	// Otherwise depending on currents ships utilization
+	} else if (ships_utilization_ > 5000) {
+		enough_ships = FleetStatus::kNeedShip;
+	} else {
 		enough_ships = FleetStatus::kEnoughShips;
-	} else if (static_cast<float>(allships.size()) < ports_count) {
-		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) {
+	if (enough_ships == FleetStatus::kNeedShip) {
 
 		for (const ProductionSiteObserver& ps_obs : productionsites) {
 			if (ps_obs.bo->is_shipyard_ && ps_obs.site->can_start_working() &&
@@ -3552,15 +3613,18 @@
 	}
 
 	// 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 &&
+	if (idle_shipyard_stocked &&
+		!no_more_expeditions_ &&
+		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;
-			}
+			// 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;
@@ -3577,9 +3641,70 @@
 	bool action_taken = false;
 
 	if (!allships.empty()) {
-		// iterating over ships and executing what is needed
+		// iterating over ships and doing what is needed
 		for (std::list<ShipObserver>::iterator i = allships.begin(); i != allships.end(); ++i) {
 
+			const uint8_t ship_state = i->ship->get_ship_state();
+
+			// Here we manage duration of expedition and related variables
+			if (ship_state == Widelands::Ship::EXP_WAITING ||
+			    ship_state == Widelands::Ship::EXP_SCOUTING ||
+				ship_state == Widelands::Ship::EXP_FOUNDPORTSPACE) {
+
+					// consistency check
+					assert (expedition_ship_ == i->ship->serial() || expedition_ship_ == kNoShip);
+
+					// This is obviously new expedition
+					if (expedition_ship_ == kNoShip) {
+						assert (expedition_start_time_ == kNoExpedition);
+						expedition_start_time_ = gametime;
+						player_->set_ai_data(gametime, kExpStartTime);
+						expedition_ship_ = i->ship->serial();
+
+					// Already known expedition, all we do now, is decreasing colony_scan_area_
+					// based on lapsed time
+					} else if (gametime - expedition_start_time_ < kExpeditionMaxDuration) {
+						assert (expedition_start_time_ > kNoExpedition);
+						// remaining_time is a percent so in range 0-100
+						const uint32_t remaining_time
+							= 100 - ((gametime - expedition_start_time_) / (kExpeditionMaxDuration / 100));
+						assert (remaining_time <= 100);
+
+						// We calculate expected value and actual value (colony_scan_area_
+						// is changed only when needed)
+						const uint32_t expected_colony_scan = kColonyScanMinArea
+							+
+							(kColonyScanStartArea - kColonyScanMinArea) * remaining_time / 100;
+						assert (expected_colony_scan >= kColonyScanMinArea
+							&&
+							expected_colony_scan <= kColonyScanStartArea);
+
+						// So changing it if needed
+						if (expected_colony_scan < colony_scan_area_) {
+							colony_scan_area_ = expected_colony_scan;
+							player_->set_ai_data(colony_scan_area_, kColonyScan);
+						}
+
+					// Expedition overdue. Setting no_more_expeditions_=true
+					// But we do not cancel it, the code for cancellation does not work properly now
+					} else if (gametime - expedition_start_time_ >= kExpeditionMaxDuration) {
+						assert (expedition_start_time_ > 0);
+						colony_scan_area_ = kColonyScanMinArea;
+						player_->set_ai_data(kColonyScanMinArea, kColonyScan);
+						no_more_expeditions_ = true;
+						player_->set_ai_data(true, kNoExpeditions);
+					}
+
+
+			// We are not in expedition mode (or perhaps building a colonisation port)
+			// so resetting start time
+			} else if (expedition_ship_ == i->ship->serial()) {
+				// Obviously expedition just ended
+				expedition_start_time_ = kNoExpedition;
+				expedition_ship_ = kNoShip;
+				player_->set_ai_data(kNoExpedition, kExpStartTime);
+			}
+
 			// only two states need an attention
 			if ((i->ship->get_ship_state() == Widelands::Ship::EXP_WAITING ||
 			     i->ship->get_ship_state() == Widelands::Ship::EXP_FOUNDPORTSPACE) &&
@@ -3599,6 +3724,20 @@
 				expedition_management(*i);
 				action_taken = true;
 			}
+
+			// Checking utilization
+			if (i->ship->get_ship_state() == Widelands::Ship::TRANSPORT) {
+
+				// Good utilization is 10 pieces of ware onboard, to track utilization we use range 0-10000
+				// to avoid float or rounding errors if integers in range 0-100
+				const int16_t tmp_util = (i->ship->get_nritems() > 10) ? 10000 : i->ship->get_nritems() * 1000;
+				// This number is kind of average
+				ships_utilization_ = ships_utilization_ / 20 * 19 + tmp_util / 20;
+				player_->set_ai_data(ships_utilization_, kShipUtil);
+
+				// Arithmetics check
+				assert (ships_utilization_ >= 0 && ships_utilization_ <= 10000);
+			}
 		}
 	}
 
@@ -4155,6 +4294,7 @@
 	vacant_mil_positions_ = 0;
 	for (TrainingSiteObserver tso : trainingsites) {
 		vacant_mil_positions_ += 10 * (tso.site->soldier_capacity() - tso.site->stationed_soldiers().size());
+		vacant_mil_positions_ += (tso.site->can_start_working()) ? 0 : 10;
 	}
 	for (MilitarySiteObserver mso : militarysites) {
 		vacant_mil_positions_ += mso.site->soldier_capacity() - mso.site->stationed_soldiers().size();
@@ -4164,9 +4304,7 @@
 // this function only check with trainingsites
 // manipulates input queues and soldier capacity
 bool DefaultAI::check_trainingsites(uint32_t gametime) {
-	if (get_taskpool_task_time(SchedulerTaskId::kCheckTrainingsites) > gametime) {
-		return false;
-	}
+
 	if (trainingsites.empty()) {
 		set_taskpool_task_time(
 			gametime + 2 * kTrainingSitesCheckInterval, SchedulerTaskId::kCheckTrainingsites);
@@ -4500,12 +4638,6 @@
 // this is called whenever we gain ownership of a Ship
 void DefaultAI::gain_ship(Ship& ship, NewShip type) {
 
-	if (type == NewShip::kBuilt) {
-		marineTaskQueue_.push_back(kStopShipyard);
-	} else {
-		seafaring_economy = true;
-	}
-
 	allships.push_back(ShipObserver());
 	allships.back().ship = &ship;
 	if (game().get_gametime() % 2 == 0) {
@@ -4513,6 +4645,16 @@
 	} else {
 		allships.back().island_circ_direction = IslandExploreDirection::kCounterClockwise;
 	}
+
+	if (type == NewShip::kBuilt) {
+		marineTaskQueue_.push_back(kStopShipyard);
+	} else {
+		seafaring_economy = true;
+		if (ship.state_is_expedition()) {
+			assert (expedition_ship_ == kNoShip);
+			expedition_ship_ = ship.serial();
+		}
+	}
 }
 
 // this is called whenever we lose ownership of a PlayerImmovable
@@ -4745,7 +4887,7 @@
 	Map& map = game().map();
 	const int32_t gametime = game().get_gametime();
 
-	// first we put current spot into visited_spots_
+	// second 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;
@@ -4777,16 +4919,8 @@
 
 			return;
 		}
-
-		// decreasing colony_scan_area_
-		if (colony_scan_area_ > kColonyScanMinArea && gametime % 4 == 0) {
-			colony_scan_area_ -= 1;
-			player_->set_ai_data(colony_scan_area_, kColonyScan);
-		}
-		assert(colony_scan_area_ >= kColonyScanMinArea);
 	}
 
-	// if we are here, port was not ordered above
 	// 2. Go on with expedition
 
 	if (first_time_here) {

=== modified file 'src/ai/defaultai.h'
--- src/ai/defaultai.h	2015-12-06 12:37:51 +0000
+++ src/ai/defaultai.h	2015-12-10 20:18:09 +0000
@@ -326,6 +326,11 @@
 	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
+	uint32_t expedition_start_time_;
+	bool no_more_expeditions_;
+	uint32_t expedition_ship_;
+	int16_t ships_utilization_; //0-10000 to avoid floats, used for decision for building new ships
+
 	int32_t spots_;  // sum of buildable fields
 	int32_t vacant_mil_positions_;  // sum of vacant positions in militarysites and training sites
 	// statistics for training sites per type
@@ -335,6 +340,9 @@
 	uint8_t ts_advanced_const_count_;
 	uint8_t ts_without_trainers_;
 
+	// This stores highest priority for new buildings except for militarysites
+	int32_t highest_nonmil_prio_;
+
 	// this is helping counter to track how many scheduler tasks are too delayed
 	// the purpose is to print out a warning that the game is pacing too fast
 	int32_t scheduler_delay_counter_;

=== modified file 'src/game_io/game_player_info_packet.cc'
--- src/game_io/game_player_info_packet.cc	2015-10-25 09:53:21 +0000
+++ src/game_io/game_player_info_packet.cc	2015-12-10 20:18:09 +0000
@@ -30,7 +30,7 @@
 
 namespace Widelands {
 
-constexpr uint16_t kCurrentPacketVersion = 18;
+constexpr uint16_t kCurrentPacketVersion = 19;
 
 void GamePlayerInfoPacket::read
 	(FileSystem & fs, Game & game, MapObjectLoader *) {

=== modified file 'src/logic/player.cc'
--- src/logic/player.cc	2015-11-21 11:34:10 +0000
+++ src/logic/player.cc	2015-12-10 20:18:09 +0000
@@ -1324,6 +1324,15 @@
 	m_ai_data_int16[position] = value;
 }
 
+void Player::set_ai_data(bool value, uint32_t position) {
+	assert(position < kAIDataSize);
+	if (value) {
+		m_ai_data_int16[position] = 1;
+	} else {
+		m_ai_data_int16[position] = 0;
+	}
+}
+
 void Player::get_ai_data(int32_t * value, uint32_t position) {
 	assert(position < kAIDataSize);
 	*value = m_ai_data_int32[position];
@@ -1339,6 +1348,16 @@
 	*value = m_ai_data_int16[position];
 }
 
+void Player::get_ai_data(bool * value, uint32_t position) {
+	assert(position < kAIDataSize);
+	assert(m_ai_data_int16[position] == 0 || m_ai_data_int16[position] == 1);
+	if (m_ai_data_int16[position] == 1) {
+		*value = true;
+	} else {
+		*value = false;
+	}
+}
+
 /**
  * Read statistics data from a file.
  *

=== modified file 'src/logic/player.h'
--- src/logic/player.h	2015-11-11 09:53:54 +0000
+++ src/logic/player.h	2015-12-10 20:18:09 +0000
@@ -37,7 +37,7 @@
 // there are three arrays to be used by AI
 // their size is defined here
 // (all are of the same size)
-constexpr int kAIDataSize = 6;
+constexpr int kAIDataSize = 8;
 
 class Node;
 namespace Widelands {
@@ -518,9 +518,11 @@
 	void set_ai_data(int32_t value, uint32_t position);
 	void set_ai_data(uint32_t value, uint32_t position);
 	void set_ai_data(int16_t value, uint32_t position);
+	void set_ai_data(bool value, uint32_t position);
 	void get_ai_data(int32_t * value, uint32_t position);
 	void get_ai_data(uint32_t * value, uint32_t position);
 	void get_ai_data(int16_t * value, uint32_t position);
+	void get_ai_data(bool * value, uint32_t position);
 
 private:
 	BuildingStatsVector* get_mutable_building_statistics(const DescriptionIndex& i);

=== modified file 'src/logic/ship.cc'
--- src/logic/ship.cc	2015-11-21 11:34:10 +0000
+++ src/logic/ship.cc	2015-12-10 20:18:09 +0000
@@ -645,6 +645,18 @@
 					WaresQueue& wq = cs->waresqueue(ware->descr_index());
 					const uint32_t max = wq.get_max_fill();
 					const uint32_t cur = wq.get_filled();
+
+					// This is to help to debug the situation when colonization fails
+					if (max <= cur) {
+						log ("  %d: Colonization error: filling wares to future %s (owner %d) failed."
+						" Unloded wares: %d, capacity: %d\n",
+						get_owner()->player_number(),
+						cs->get_info().becomes->name().c_str(),
+						cs->get_owner()->player_number(),
+						cur,
+						max);
+					}
+
 					assert(max > cur);
 					wq.set_filled(cur + 1);
 					m_items.at(i).remove(game);

=== modified file 'tribes/buildings/trainingsites/atlanteans/dungeon/init.lua'
--- tribes/buildings/trainingsites/atlanteans/dungeon/init.lua	2015-12-08 15:48:26 +0000
+++ tribes/buildings/trainingsites/atlanteans/dungeon/init.lua	2015-12-10 20:18:09 +0000
@@ -37,8 +37,14 @@
 
    aihints = {
       trainingsite_type = "advanced",
+<<<<<<< TREE
       very_weak_ai_limit = 0,
       weak_ai_limit = 1
+=======
+      prohibited_till = 1500,
+      weak_ai_limit = 0,
+      normal_ai_limit = 1
+>>>>>>> MERGE-SOURCE
    },
 
    working_positions = {

=== modified file 'tribes/buildings/trainingsites/atlanteans/labyrinth/init.lua'
--- tribes/buildings/trainingsites/atlanteans/labyrinth/init.lua	2015-12-08 15:48:26 +0000
+++ tribes/buildings/trainingsites/atlanteans/labyrinth/init.lua	2015-12-10 20:18:09 +0000
@@ -36,6 +36,7 @@
 
    aihints = {
       prohibited_till=900,
+      forced_after_=1500,
       trainingsite_type = "basic",
       very_weak_ai_limit = 1,
       weak_ai_limit = 2

=== modified file 'tribes/buildings/trainingsites/barbarians/battlearena/init.lua'
--- tribes/buildings/trainingsites/barbarians/battlearena/init.lua	2015-12-08 15:48:26 +0000
+++ tribes/buildings/trainingsites/barbarians/battlearena/init.lua	2015-12-10 20:18:09 +0000
@@ -51,7 +51,8 @@
    },
 
    aihints = {
-      prohibited_till = 2700,
+      prohibited_till = 900,
+      forced_after_ = 1500,
       trainingsite_type = "basic",
       very_weak_ai_limit = 1,
       weak_ai_limit = 3

=== modified file 'tribes/buildings/trainingsites/barbarians/trainingcamp/init.lua'
--- tribes/buildings/trainingsites/barbarians/trainingcamp/init.lua	2015-12-08 15:48:26 +0000
+++ tribes/buildings/trainingsites/barbarians/trainingcamp/init.lua	2015-12-10 20:18:09 +0000
@@ -44,7 +44,7 @@
    },
 
    aihints = {
-      prohibited_till = 500,
+      prohibited_till = 1500,
       trainingsite_type = "advanced",
       very_weak_ai_limit = 0,
       weak_ai_limit = 1

=== modified file 'tribes/buildings/trainingsites/empire/arena/init.lua'
--- tribes/buildings/trainingsites/empire/arena/init.lua	2015-12-08 15:48:26 +0000
+++ tribes/buildings/trainingsites/empire/arena/init.lua	2015-12-10 20:18:09 +0000
@@ -41,8 +41,14 @@
 
    aihints = {
       trainingsite_type = "basic",
+<<<<<<< TREE
       very_weak_ai_limit = 1,
       weak_ai_limit = 2
+=======
+      prohibited_till = 900,
+      weak_ai_limit = 1,
+      normal_ai_limit = 2
+>>>>>>> MERGE-SOURCE
    },
 
    working_positions = {

=== modified file 'tribes/buildings/trainingsites/empire/colosseum/init.lua'
--- tribes/buildings/trainingsites/empire/colosseum/init.lua	2015-12-08 15:48:26 +0000
+++ tribes/buildings/trainingsites/empire/colosseum/init.lua	2015-12-10 20:18:09 +0000
@@ -34,6 +34,7 @@
    },
 
    aihints = {
+      prohibited_till = 1200,	      
       trainingsite_type = "basic",
       very_weak_ai_limit = 1,
       weak_ai_limit = 2

=== modified file 'tribes/buildings/trainingsites/empire/trainingcamp/init.lua'
--- tribes/buildings/trainingsites/empire/trainingcamp/init.lua	2015-12-08 15:48:26 +0000
+++ tribes/buildings/trainingsites/empire/trainingcamp/init.lua	2015-12-10 20:18:09 +0000
@@ -35,7 +35,7 @@
    },
 
    aihints = {
-      prohibited_till = 2700,
+      prohibited_till = 1500,
       trainingsite_type = "advanced",
       very_weak_ai_limit = 0,
       weak_ai_limit = 1


Follow ups