← Back to team overview

widelands-dev team mailing list archive

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

 

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

Requested reviews:
  Widelands Developers (widelands-dev)

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

Here I reworked positioning of new militarysites and dismantling of old ones. I made the code cleaner and I hope better to understand. AI now builds more big buildings.
Also I did some smaller tweaks where needed. But everything was purely AI stuff.
-- 
Your team Widelands Developers is requested to review the proposed merge of lp:~widelands-dev/widelands/militarysites_tweaks into lp:widelands.
=== modified file 'src/ai/ai_hints.cc'
--- src/ai/ai_hints.cc	2015-03-26 06:59:37 +0000
+++ src/ai/ai_hints.cc	2015-04-02 19:22:42 +0000
@@ -48,7 +48,8 @@
 		} else {
 			if (!strcmp(section ? section->get_string("trainingsite_type", "basic") : "basic", "basic")) {
 				trainingsite_type_ =  TrainingSiteType::kBasic;
-			} else if (!strcmp(section ? section->get_string("trainingsite_type", "basic") : "basic", "advanced")) {
+			} else if (!strcmp(section ? section->get_string("trainingsite_type", "basic") :
+				"basic", "advanced")) {
 				trainingsite_type_ =  TrainingSiteType::kAdvanced;
 			} else {
 				trainingsite_type_ = TrainingSiteType::kNoTS;

=== modified file 'src/ai/defaultai.cc'
--- src/ai/defaultai.cc	2015-03-26 20:35:19 +0000
+++ src/ai/defaultai.cc	2015-04-02 19:22:42 +0000
@@ -904,14 +904,13 @@
 		// stones are not renewable, we will count them only if previous state si nonzero
 		if (field.stones_nearby_ > 0 && gametime % 3 == 0) {
 
-			int32_t const stone_attr = MapObjectDescr::get_attribute_id("granite");
-			field.stones_nearby_ = 0;
+			field.stones_nearby_ =
+				map.find_immovables(Area<FCoords>(map.get_fcoords(field.coords), 6),
+					nullptr,
+		            FindImmovableAttribute(MapObjectDescr::get_attribute_id("granite")));
 
-			for (uint32_t j = 0; j < immovables.size(); ++j) {
-				if (immovables.at(j).object->has_attribute(stone_attr)) {
-					++field.stones_nearby_;
-				}
-			}
+			//adding 10 if stones found
+			field.stones_nearby_ = (field.stones_nearby_ > 0) ? field.stones_nearby_ + 10:0;
 		}
 
 		// ground water is not renewable and its amount can only fall, we will count them only if
@@ -964,7 +963,9 @@
 					if (radius > dist) {
 						field.area_military_capacity_ +=
 						   target_ms_d->get_max_number_of_soldiers() / 2 + 1;
-						field.military_loneliness_ *= static_cast<double_t>(dist) / radius;
+						if (field.coords != immovables.at(i).coords) {
+							field.military_loneliness_ *= static_cast<double_t>(dist) / radius;
+						}
 						field.military_in_constr_nearby_ += 1;
 					}
 				}
@@ -985,7 +986,9 @@
 						field.military_stationed_ += 1;
 					}
 
-					field.military_loneliness_ *= static_cast<double_t>(dist) / radius;
+					if (field.coords != immovables.at(i).coords) {
+						field.military_loneliness_ *= static_cast<double_t>(dist) / radius;
+					}
 				}
 			}
 		}
@@ -1196,7 +1199,7 @@
 	// sometimes there is too many military buildings in construction, so we must
 	// prevent initialization of further buildings start
 	const int32_t vacant_plus_in_construction_minus_prod =
-	   vacant_mil_positions_ + 2 * num_milit_constructionsites - productionsites.size() / 15;
+	   vacant_mil_positions_ + 2 * num_milit_constructionsites - productionsites.size() / 7;
 	if (vacant_plus_in_construction_minus_prod > 20) {
 		expansion_mode = MilitaryStrategy::kNoNewMilitary;
 	} else if (vacant_plus_in_construction_minus_prod > 13) {
@@ -1275,9 +1278,8 @@
 		// 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) {
+			// shortage = less then 1 items in warehouses
+			if (get_warehoused_stock(wt) < 3) {
 				bo.build_material_shortage_ = true;
 			}
 		}
@@ -1454,7 +1456,9 @@
 					}
 					prio = bf->stones_nearby_;
 
-					if (prio <= 0) {
+					// value is initialized with 1 but minimal value that can be
+					// calculated is 11
+					if (prio <= 1) {
 						continue;
 					}
 
@@ -1550,8 +1554,8 @@
 							continue;
 						}
 
-						// sometimes all area is blocked by trees so this is to prevent this
-						if (buildable_fields.size() < 4 && bo.total_count() > 0) {
+						// for small starting spots - to prevent crowding by rangers and trees
+						if (spots_ < (10 * bo.total_count()) && bo.total_count() > 0) {
 							continue;
 						}
 
@@ -1578,9 +1582,6 @@
 						        bf->producers_nearby_.at(bo.production_hint_) * 5 -
 						        new_buildings_stop_ * 15;
 
-						// considering space consumers nearby
-						prio -= bf->space_consumers_nearby_ * 5;
-
 					} else {  // FISH BREEDERS and GAME KEEPERS
 						if (new_buildings_stop_ && (bo.total_count() - bo.unconnected_) > 0) {
 							continue;
@@ -1666,7 +1667,8 @@
 
 						// we attempt to cluster space consumers together
 						if (bo.space_consumer_) {  // need to consider trees nearby
-							prio += bf->space_consumers_nearby_ * 2;
+							prio += bf->space_consumers_nearby_ * 10;
+							prio += (bf->space_consumers_nearby_ > 2)?2:bf->space_consumers_nearby_ * 2;
 						}
 
 						if (bo.space_consumer_ && !bf->water_nearby_) {  // not close to water
@@ -1682,7 +1684,6 @@
 							prio -= bf->producers_nearby_.at(bo.outputs_.at(0)) * 20;
 						}  // leave some free space between them
 
-						prio -= bf->space_consumers_nearby_ * 3;
 					}
 
 					else if (bo.is_shipyard_) {
@@ -1725,14 +1726,8 @@
 				}
 			}  // production sites done
 			else if (bo.type == BuildingObserver::MILITARYSITE) {
-				// we allow 1 exemption from big buildings prohibition
-				if (bo.build_material_shortage_ &&
-				    (bo.cnt_under_construction_ > 0 || !(bf->enemy_nearby_))) {
-					continue;
-				}
 
 				if (!bf->unowned_land_nearby_) {
-
 					continue;
 				}
 
@@ -1740,6 +1735,48 @@
 					continue;
 				}
 
+				prio = 0;
+
+				// calculating some sub-scores, some of them are prohibitive
+				// decreasing score if some critical materials are missing
+				// (relevant for medium and big buildings)
+				int32_t prio_for_mat_shortage = 0;
+				if (bf->enemy_nearby_) {
+					prio_for_mat_shortage =
+					   -bo.cnt_under_construction_ * bo.build_material_shortage_ * 50;
+				} else {
+					prio_for_mat_shortage = -bo.cnt_under_construction_ * bo.build_material_shortage_ *
+					                        1000;  // = prohibitive
+				}
+
+				// decreasing score if other militarysites constuctions
+				// are nearby
+				int32_t prio_for_in_constr = 0;
+				prio_for_in_constr -= 700 *
+				                      (((static_cast<int32_t>(num_milit_constructionsites) - 2) < 0) ?
+				                          0 :
+				                          (num_milit_constructionsites - 2)) /
+				                      (militarysites.size() + 2);
+				if (!bf->enemy_nearby_) {
+					prio_for_in_constr *= 3;
+				}
+
+				// similarly if unmanned militarysites are nearby
+				int32_t prio_for_unmanned_nearby = 0;
+				if (bf->enemy_nearby_) {
+					prio_for_unmanned_nearby -=
+					   (bf->military_in_constr_nearby_ + bf->military_unstationed_) * 20;
+				} else {
+					prio_for_unmanned_nearby -=
+					   (bf->military_in_constr_nearby_ + bf->military_unstationed_) * 1000;
+				}
+
+				// not continuing if score too low
+				if (prio_for_in_constr + prio_for_mat_shortage + prio_for_unmanned_nearby <= -1000) {
+					continue;
+				}
+
+				// is the building suitable for the situation?
 				if (expansion_mode == MilitaryStrategy::kNoNewMilitary) {
 					continue;
 				}
@@ -1771,37 +1808,64 @@
 				} else {
 					continue;
 				}  // 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) {
-					continue;
-				}
+
+
+				// calculating other sub scores
+				// for resources (mines, water, stones)
+				int32_t prio_for_resources = 0;
+				prio_for_resources +=
+				   2 * (bf->unowned_mines_pots_nearby_ * resource_necessity_mines_) / 100 +
+				   bf->stones_nearby_ + (bf->water_nearby_ * resource_necessity_water_) / 100;
+				// special bonus due to remote water for atlanteans
+				if (resource_necessity_water_needed_) {
+					prio_for_resources += (bf->distant_water_ * resource_necessity_water_) / 100 / 3;
+				}
+				// reducing score if too little unowned land
+				if (bf->unowned_land_nearby_ < 10) {
+					prio_for_resources = prio_for_resources * bf->unowned_land_nearby_ / 10;
+				}
+				if (bf->enemy_nearby_) {  // not important when fighting enemies
+					prio_for_resources /= 5;
+				}
+
+				//for unowned land nearby
+				int32_t prio_for_unowned_land = 0;
+				if (expansion_mode == MilitaryStrategy::kExpansion ||
+				    expansion_mode == MilitaryStrategy::kPushExpansion) {
+					prio_for_unowned_land +=
+					   (bf->unowned_land_nearby_ * resource_necessity_territory_) / 100;
+				}
+
+				//for distance to nearest military sites
+				int32_t prio_for_loneliness = bf->military_loneliness_;
+				if (!bf->enemy_nearby_) {
+					prio_for_loneliness /= 10;
+				}
+
+				//additional score for bigger buildings
+				int32_t prio_for_size = 0;
+				if (bf->enemy_nearby_) {
+					prio_for_size += (bo.desc->get_size() - 1) * 30;
+				} else {
+					prio_for_size += (bo.desc->get_size() - 1) * 15;
+				}
+
+				//additional score if enemy is nearby
+				int32_t prio_for_enemy = 0;
+				if (bf->enemy_nearby_) {
+					prio_for_enemy += 50;
+				}
+
 				// a boost to prevent an expansion halt
 				int32_t local_boost = 0;
 				if (expansion_mode == MilitaryStrategy::kPushExpansion) {
 					local_boost = 200;
 				}
 
-				// priority based on basic resources
-				prio = ((bf->unowned_mines_pots_nearby_ * resource_necessity_mines_) / 100 +
-				        bf->stones_nearby_ + bf->military_loneliness_ / 10 - 40 + local_boost +
-				        (bf->water_nearby_ * resource_necessity_water_) / 100);
-
-				// Depending on wheter resource only are considered or no
-				if (expansion_mode == MilitaryStrategy::kResourcesOrDefense) {
-					prio *= 2;
-					prio += bf->unowned_land_nearby_ * resource_necessity_territory_ / 100 / 2;
-				} else {  // addding score for territory
-					prio += (bf->unowned_land_nearby_ * resource_necessity_territory_) / 100 * 3 / 2;
-				}
-
-				// adding score for distance to other military sites
-				prio += bf->military_loneliness_ / 10 - 40;
-
-				// special bonus due to remote water for atlanteans
-				if (resource_necessity_water_needed_) {
-					prio += (bf->distant_water_ * resource_necessity_water_) / 100 / 2;
-				}
+				// summing
+				prio += prio_for_mat_shortage + prio_for_in_constr + prio_for_unmanned_nearby +
+				        prio_for_resources + prio_for_unowned_land + prio_for_loneliness +
+				        prio_for_size + local_boost + prio_for_enemy;
 
 				// special bonus if a portspace is close
 				if (bf->portspace_nearby_ == ExtendedBool::kTrue) {
@@ -1812,28 +1876,78 @@
 					}
 				}
 
-				//special bonus for bigger buildings if enemy is nearby
-				if (bf->enemy_nearby_) {
-					prio += (bo.desc->get_size() - 1) * 25;
-				}
-
+				// penalty if we build lesser then possible building
 				if (bo.desc->get_size() < maxsize) {
 					prio = prio - 5;
-				}  // penalty
-
-				// we need to prefer military building near to borders
-				// with enemy
-				// Note: if we dont have enough mines, we cannot afford
-				// full-power defense (we need to preserve material and soldiers
-				// for expansion)
-				const int16_t bottom_treshold =
-				   15 - ((virtual_mines <= 4) ? (5 - virtual_mines) * 2 : 0);
-				if (bf->enemy_nearby_ && bf->area_military_capacity_ < bottom_treshold) {
-					prio += 50 + (bottom_treshold - bf->area_military_capacity_) * 20;
-				}
-
-				if (bf->enemy_nearby_ && bf->area_military_capacity_ > bottom_treshold + 4) {
-					prio -= (bf->area_military_capacity_ - (bottom_treshold + 4)) * 5;
+				}
+
+				// just generally prevent too many buildings
+				prio -= 40;
+
+			} else if (bo.type == BuildingObserver::WAREHOUSE) {
+
+				// exclude spots on border
+				if (bf->near_border_ && !bo.is_port_) {
+					continue;
+				}
+
+				if (!bf->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
+				//  chance for a warehouses (containing waiting soldiers or wares
+				//  needed for soldier training) near the frontier.
+				if ((static_cast<int32_t>(productionsites.size() + mines_.size()) + 20) / 35 >
+				       static_cast<int32_t>(numof_warehouses_) &&
+				    bo.cnt_under_construction_ == 0) {
+					prio = 20;
+					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 &&
+				    !bf->enemy_nearby_ && bf->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(bf->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 (bf->enemy_nearby_) {
+					prio /= 4;
+				}
+
+				if (bf->unowned_land_nearby_ && !bo.is_port_) {
+					prio /= 2;
 				}
 
 			} else if (bo.type == BuildingObserver::WAREHOUSE) {
@@ -1953,7 +2067,9 @@
 			}
 
 			// think of space consuming buildings nearby like farms or vineyards
-			prio -= bf->space_consumers_nearby_ * 10;
+			if (bo.type != BuildingObserver::MILITARYSITE) {
+				prio -= bf->space_consumers_nearby_ * 10;
+			}
 
 			// Stop here, if priority is 0 or less.
 			if (prio <= 0) {
@@ -3577,7 +3693,7 @@
 
 				int16_t score = 0;
 				score += (bf.area_military_capacity_ > 6);
-				score += (bf.area_military_capacity_ > 18);
+				score += (bf.area_military_capacity_ > 22);
 				score += (bf.area_military_presence_ > 4);
 				score += (bf.military_loneliness_ < 180);
 				score += (bf.military_stationed_ > 2);

=== modified file 'tribes/atlanteans/castle/conf'
--- tribes/atlanteans/castle/conf	2014-07-29 20:48:19 +0000
+++ tribes/atlanteans/castle/conf	2015-04-02 19:22:42 +0000
@@ -13,7 +13,7 @@
 expansion=true
 fighting=true
 mountain_conqueror=true
-prohibited_till=1800
+prohibited_till=1500
 
 [buildcost]
 planks=4

=== modified file 'tribes/barbarians/donjon/conf'
--- tribes/barbarians/donjon/conf	2014-07-29 20:48:19 +0000
+++ tribes/barbarians/donjon/conf	2015-04-02 19:22:42 +0000
@@ -14,7 +14,7 @@
 expansion=true
 fighting=true
 mountain_conqueror=true
-prohibited_till=1500
+prohibited_till=1200
 
 [buildcost]
 blackwood=7

=== modified file 'tribes/barbarians/fortress/conf'
--- tribes/barbarians/fortress/conf	2014-07-29 20:48:19 +0000
+++ tribes/barbarians/fortress/conf	2015-04-02 19:22:42 +0000
@@ -14,7 +14,7 @@
 expansion=true
 fighting=true
 mountain_conqueror=true
-prohibited_till=1800
+prohibited_till=1500
 
 [buildcost]
 blackwood=9


Follow ups