← Back to team overview

widelands-dev team mailing list archive

[Merge] lp:~widelands-dev/widelands/bug-1523165 into lp:widelands

 

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

Requested reviews:
  Widelands Developers (widelands-dev)
Related bugs:
  Bug #1523165 in widelands: "ai malfunctions after introduction of difficulty levels"
  https://bugs.launchpad.net/widelands/+bug/1523165

For more details, see:
https://code.launchpad.net/~widelands-dev/widelands/bug-1523165/+merge/280397

This is part of changes I made in ai_ship_fix - fixing upgrading of productionsites and management of trainingsites.

I will keep working on ai_ship_tweaks branch, but this can be approved and merged indepedently of ship-related stuff.
-- 
Your team Widelands Developers is requested to review the proposed merge of lp:~widelands-dev/widelands/bug-1523165 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-12 20:55:58 +0000
@@ -70,7 +70,7 @@
 // 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 kAttackMargin    = 0; //uint32_t
@@ -134,6 +134,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 +313,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 +853,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
@@ -1520,6 +1522,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 +1540,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 +1559,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 +1598,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 +1634,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 +1691,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 +1786,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 +2311,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 +2392,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 +2522,10 @@
 						proposed_coords = mf->coords;
 						mine = true;
 					}
+
+					if (prio > highest_nonmil_prio_) {
+						highest_nonmil_prio_ = prio;
+					}
 				}  // end of evaluation of field
 			}
 
@@ -3156,26 +3187,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;
 					}
 				}
 			}
@@ -4155,6 +4186,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 +4196,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);

=== modified file 'src/ai/defaultai.h'
--- src/ai/defaultai.h	2015-12-06 12:37:51 +0000
+++ src/ai/defaultai.h	2015-12-12 20:55:58 +0000
@@ -335,6 +335,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/logic/player.cc'
--- src/logic/player.cc	2015-11-21 11:34:10 +0000
+++ src/logic/player.cc	2015-12-12 20:55:58 +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-12 20:55:58 +0000
@@ -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 '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-12 20:55:58 +0000
@@ -37,6 +37,7 @@
 
    aihints = {
       trainingsite_type = "advanced",
+      prohibited_till = 1500,
       very_weak_ai_limit = 0,
       weak_ai_limit = 1
    },

=== 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-12 20:55:58 +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-12 20:55:58 +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-12 20:55:58 +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-12 20:55:58 +0000
@@ -41,6 +41,7 @@
 
    aihints = {
       trainingsite_type = "basic",
+      prohibited_till = 900,
       very_weak_ai_limit = 1,
       weak_ai_limit = 2
    },

=== 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-12 20:55:58 +0000
@@ -35,6 +35,7 @@
 
    aihints = {
       trainingsite_type = "basic",
+      prohibited_till = 1200,
       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-12 20:55:58 +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