From b9f26a43646be6ae36452254e2294b5d5ad8525b Mon Sep 17 00:00:00 2001 From: mattsc Date: Wed, 11 Apr 2018 16:54:00 -0700 Subject: [PATCH] AI recruitment: fix units on recall list interfering with recruiting Units on the recall list are treated as recruits by the AI. The code previously did not check whether a unit it worth being recalled until after it makes the decision which unit type to recruit/recall. If it then can only recall, but not recruit units of that type and all of them are deemed not worth it, the entire recruitment CA is disabled (via black listing), meaning recruiting is abandoned also. This commit fixes this by checking the unit value vs. the recall cost before putting recalls on the recruitment list. (cherry picked from commit 1597a2ce273e2f6f89221fc9fa10590892f43043) --- src/ai/default/recruitment.cpp | 54 ++++++++++++++++++++-------------- src/ai/default/recruitment.hpp | 1 + 2 files changed, 33 insertions(+), 22 deletions(-) diff --git a/src/ai/default/recruitment.cpp b/src/ai/default/recruitment.cpp index 763c99b9e4fa..feacc0f6e24f 100644 --- a/src/ai/default/recruitment.cpp +++ b/src/ai/default/recruitment.cpp @@ -262,6 +262,10 @@ void recruitment::execute() { if (!ufilt(*recall, map_location::null_location())) { continue; } + const double recall_value = recruitment::recall_unit_value(recall); + if (recall_value < 0) { + continue; // Unit is not worth to get recalled. + } data.recruits.insert(recall->type_id()); data.scores[recall->type_id()] = 0.0; global_recruits.insert(recall->type_id()); @@ -474,6 +478,33 @@ action_result_ptr recruitment::execute_recruit(const std::string& type, data& le * If this value is less then the recall cost, we dismiss the unit. * The unit with the highest value will be returned. */ + +double recruitment::recall_unit_value(const unit_const_ptr & recall_unit) const { + double average_cost_of_advanced_unit = 0; + int counter = 0; + for (const std::string& advancement : recall_unit->advances_to()) { + const unit_type* advancement_type = unit_types.find(advancement); + if (!advancement_type) { + continue; + } + average_cost_of_advanced_unit += advancement_type->cost(); + ++counter; + } + if (counter > 0) { + average_cost_of_advanced_unit /= counter; + } else { + // Unit don't have advancements. Use cost of unit itself. + average_cost_of_advanced_unit = recall_unit->cost(); + } + double xp_quantity = static_cast(recall_unit->experience()) / + recall_unit->max_experience(); + double recall_value = recall_unit->cost() + xp_quantity * average_cost_of_advanced_unit; + if (recall_value < current_team().recall_cost()) { + recall_value = -1; // Unit is not worth to get recalled. + } + return recall_value; +} + const std::string* recruitment::get_appropriate_recall(const std::string& type, const data& leader_data) const { const std::string* best_recall_id = nullptr; @@ -488,28 +519,7 @@ const std::string* recruitment::get_appropriate_recall(const std::string& type, LOG_AI_RECRUITMENT << "Refused recall because of filter: " << recall_unit->id() << "\n"; continue; } - double average_cost_of_advanced_unit = 0; - int counter = 0; - for (const std::string& advancement : recall_unit->advances_to()) { - const unit_type* advancement_type = unit_types.find(advancement); - if (!advancement_type) { - continue; - } - average_cost_of_advanced_unit += advancement_type->cost(); - ++counter; - } - if (counter > 0) { - average_cost_of_advanced_unit /= counter; - } else { - // Unit don't have advancements. Use cost of unit itself. - average_cost_of_advanced_unit = recall_unit->cost(); - } - double xp_quantity = static_cast(recall_unit->experience()) / - recall_unit->max_experience(); - double recall_value = recall_unit->cost() + xp_quantity * average_cost_of_advanced_unit; - if (recall_value < current_team().recall_cost()) { - continue; // Unit is not worth to get recalled. - } + const double recall_value = recruitment::recall_unit_value(recall_unit); if (recall_value > best_recall_value) { best_recall_id = &recall_unit->id(); best_recall_value = recall_value; diff --git a/src/ai/default/recruitment.hpp b/src/ai/default/recruitment.hpp index b4084cbb1f2c..d407a68a8b14 100644 --- a/src/ai/default/recruitment.hpp +++ b/src/ai/default/recruitment.hpp @@ -174,6 +174,7 @@ class recruitment : public candidate_action { // Helper functions for execute() action_result_ptr execute_recall(const std::string& id, data& leader_data); action_result_ptr execute_recruit(const std::string& type, data& leader_data); + double recall_unit_value(const unit_const_ptr & recall_unit) const; const std::string* get_appropriate_recall(const std::string& type, const data& leader_data) const; data* get_best_leader_from_ratio_scores(std::vector& leader_data,