50 #define LOG_AI_RECRUITMENT LOG_STREAM(info, log_ai_recruitment)
51 #define ERR_AI_RECRUITMENT LOG_STREAM(err, log_ai_recruitment)
54 #define ERR_WML LOG_STREAM(err, log_wml)
58 namespace default_recruitment {
67 const static int SAVE_GOLD_FORECAST_TURNS = 5;
70 const static unsigned int UNIT_THRESHOLD = 5;
74 const static double MAP_BORDER_THICKNESS = 2.0;
75 const static double MAP_BORDER_WIDTH = 0.2;
81 const static int MAP_OFFENSIVE_SHIFT = 0;
84 const static int MAP_VILLAGE_NEARNESS_THRESHOLD = 3;
87 const static int MAP_VILLAGE_SURROUNDING = 1;
92 const static double COMBAT_SCORE_POWER = 1.;
97 const static double COMBAT_CACHE_TOLERANCY = 0.5;
101 const static double VILLAGE_PER_SCOUT_MULTIPLICATOR = 2.;
106 s <<
"---------------Content of leader data---------------\n";
107 s <<
"For leader: " <<
leader->name() <<
"\n";
110 for (
const score_map::value_type& entry :
scores) {
111 s << std::setw(20) << entry.first <<
112 " score: " << std::setw(7) << entry.second <<
"\n";
114 s <<
"----------------------------------------------------\n";
121 important_terrain_(),
122 own_units_in_combat_counter_(0),
123 average_local_cost_(),
124 cheapest_unit_costs_(),
126 recruit_situation_change_observer_(),
127 average_lawful_bonus_(0.0),
128 recruitment_instructions_(),
129 recruitment_instructions_turn_(-1),
134 if (cfg[
"state"] ==
"save_gold") {
136 }
else if (cfg[
"state"] ==
"spend_all_gold") {
146 cfg[
"state"] =
"save_gold";
148 cfg[
"state"] =
"spend_all_gold";
150 cfg[
"state"] =
"normal";
194 if (
current_team().gold() < cheapest_unit_cost && cheapest_unit_cost > 0) {
222 std::vector<data> leader_data;
224 std::set<std::string> global_recruits;
241 if (
current_team().gold() < cheapest_unit_cost && cheapest_unit_cost > 0) {
251 for (
const std::string& recruit :
current_team().recruits()) {
253 lg::log_to_chat() <<
"Unit-type \"" << recruit <<
"\" doesn't exist.\n";
254 ERR_WML <<
"Unit-type \"" << recruit <<
"\" doesn't exist.";
258 global_recruits.insert(recruit);
262 for (
const std::string& recruit : leader->recruits()) {
264 lg::log_to_chat() <<
"Unit-type \"" << recruit <<
"\" doesn't exist.\n";
265 ERR_WML <<
"Unit-type \"" << recruit <<
"\" doesn't exist.";
269 global_recruits.insert(recruit);
282 if (recall_value < 0) {
287 global_recruits.insert(recall->type_id());
300 leader_data.push_back(
data);
303 if (leader_data.empty()) {
308 if (global_recruits.empty()) {
339 for (
const data&
data : leader_data) {
348 for (
const data&
data : leader_data) {
367 bool save_gold_active = save_gold_turn > 0 && save_gold_turn <= current_turn;
380 if (!best_leader_data) {
391 if (best_recruit.empty()) {
417 if (!job->operator[](
"total").to_bool(
false)) {
418 job->operator[](
"number") = job->operator[](
"number").to_int(99999) - 1;
455 if (job && no_gold) {
466 leader_data.
leader->get_location());
480 leader_data.
leader->get_location());
499 double average_cost_of_advanced_unit = 0;
501 for (
const std::string& advancement :
recall_unit->advances_to()) {
503 if (!advancement_type) {
506 average_cost_of_advanced_unit += advancement_type->
cost();
510 average_cost_of_advanced_unit /= counter;
513 average_cost_of_advanced_unit =
recall_unit->cost();
515 double xp_quantity =
static_cast<double>(
recall_unit->experience()) /
517 double recall_value =
recall_unit->cost() + xp_quantity * average_cost_of_advanced_unit;
522 if (recall_value < cost) {
529 const data& leader_data)
const {
530 const std::string* best_recall_id =
nullptr;
531 double best_recall_value = -1;
543 if (recall_value > best_recall_value) {
545 best_recall_value = recall_value;
548 return best_recall_id;
556 const config* job)
const {
559 int total_recruit_count = 0;
560 double ratio_score_sum = 0.0;
561 for (
const data&
data : leader_data) {
565 assert(ratio_score_sum > 0.0);
571 data* best_leader_data =
nullptr;
572 double biggest_difference = -99999.;
577 double desired_ammount =
data.
ratio_score / ratio_score_sum * (total_recruit_count + 1);
579 double difference = desired_ammount - current_ammount;
580 if (difference > biggest_difference) {
581 biggest_difference = difference;
582 best_leader_data = &
data;
585 return best_leader_data;
597 if (!pattern_type.empty()) {
600 std::string best_recruit =
"";
601 double biggest_difference = -99999.;
603 const std::string&
unit =
i.first;
604 const double score =
i.second;
609 if (!pattern_type.empty()) {
621 double difference = desired_ammount - current_ammount;
625 if (difference > biggest_difference) {
626 biggest_difference = difference;
647 typedef std::map<map_location, double> border_cost_map;
648 border_cost_map important_hexes_candidates;
649 double smallest_border_movecost = 999999;
650 double biggest_border_movecost = 0;
655 if (my_cost_average == -1 || enemy_cost_average == -1) {
660 if (std::abs(my_cost_average - MAP_OFFENSIVE_SHIFT - enemy_cost_average) <
662 double border_movecost = (my_cost_average + enemy_cost_average) / 2;
663 important_hexes_candidates[loc] = border_movecost;
665 if (border_movecost < smallest_border_movecost) {
666 smallest_border_movecost = border_movecost;
668 if (border_movecost > biggest_border_movecost) {
669 biggest_border_movecost = border_movecost;
675 double threshold = (biggest_border_movecost - smallest_border_movecost) *
676 MAP_BORDER_WIDTH + smallest_border_movecost;
677 for (
const border_cost_map::value_type& candidate : important_hexes_candidates) {
678 if (candidate.second < threshold) {
694 long summed_defense = 0;
695 int total_terrains = 0;
698 int count = entry.second;
700 summed_defense += defense * count;
701 total_terrains += count;
703 double average_defense = (total_terrains == 0) ? 0.0 :
704 static_cast<double>(summed_defense) / total_terrains;
705 return average_defense;
722 unsigned int unit_count = 0;
733 if (unit_count < UNIT_THRESHOLD) {
734 std::vector<unit_map::const_iterator> leaders = units.
find_leaders(side);
742 for (
const std::string& recruit : leader->recruits()) {
773 sum += time.lawful_bonus;
790 for(
int x = 0; x < map.
w(); ++x) {
791 for (
int y = 0; y < map.
h(); ++y) {
834 std::vector<map_location> surrounding;
837 std::copy(surrounding.begin(), surrounding.end(),
862 std::vector<map_location> important_villages;
864 std::vector<map_location> surrounding;
868 important_villages.push_back(village);
873 for (
const map_location& village : important_villages) {
875 std::vector<map_location> surrounding;
896 if (!type_a || !type_b) {
908 double damage_to_a = 0.0;
909 double damage_to_b = 0.0;
912 simulate_attack(type_a, type_b, defense_a, defense_b, &damage_to_a, &damage_to_b);
914 simulate_attack(type_b, type_a, defense_b, defense_a, &damage_to_b, &damage_to_a);
916 int a_cost = (type_a->
cost() > 0) ? type_a->
cost() : 1;
917 int b_cost = (type_b->
cost() > 0) ? type_b->
cost() : 1;
924 if (damage_to_a <= 0 && damage_to_b <= 0) {
926 }
else if (damage_to_a <= 0) {
928 }
else if (damage_to_b <= 0) {
932 double value_of_a = damage_to_b / (b_max_hp * a_cost);
933 double value_of_b = damage_to_a / (a_max_hp * b_cost);
935 if (value_of_a > value_of_b) {
936 return value_of_a / value_of_b;
937 }
else if (value_of_a < value_of_b) {
938 return -value_of_b / value_of_a;
962 typedef std::vector<std::pair<std::string, int>> unit_hp_vector;
963 unit_hp_vector enemy_units;
970 if (enemy_units.size() < UNIT_THRESHOLD) {
976 std::set<std::string> possible_recruits;
982 possible_recruits.insert(leader->recruits().begin(), leader->recruits().end());
985 for (
const std::string& possible_recruit : possible_recruits) {
989 enemy_units.emplace_back(possible_recruit, hp);
995 for (
data& leader : *leader_data) {
996 if (leader.recruits.empty()) {
999 typedef std::map<std::string, double> simple_score_map;
1000 simple_score_map temp_scores;
1002 for (
const unit_hp_vector::value_type& entry : enemy_units) {
1003 const std::string& enemy_unit = entry.first;
1004 int enemy_unit_hp = entry.second;
1005 for (
const std::string& recruit : leader.recruits) {
1007 score *= enemy_unit_hp;
1008 score = std::pow(score, COMBAT_SCORE_POWER);
1009 temp_scores[recruit] += score;
1013 if (temp_scores.empty()) {
1017 double max = -99999.;
1019 for (
const simple_score_map::value_type& entry : temp_scores) {
1020 double score = entry.second;
1026 double average = sum / temp_scores.size();
1032 double new_100 = max;
1034 if (score_threshold <= 0) {
1035 score_threshold = 0.0001;
1037 double new_0 = max - (score_threshold * (max - average));
1038 if (new_100 == new_0) {
1043 for (
const simple_score_map::value_type& entry : temp_scores) {
1044 const std::string& recruit = entry.first;
1045 double score = entry.second;
1050 double normalized_score = 100 * ((score - new_0) / (new_100 - new_0));
1051 if (normalized_score < 0) {
1052 normalized_score = 0;
1054 leader.scores[recruit] += normalized_score;
1065 double a_defense,
double b_defense) {
1066 double best_distance = 999;
1067 const double* best_value =
nullptr;
1070 double distance_a = std::abs(entry.a_defense - a_defense);
1071 double distance_b = std::abs(entry.b_defense - b_defense);
1072 if (distance_a <= COMBAT_CACHE_TOLERANCY && distance_b <= COMBAT_CACHE_TOLERANCY) {
1073 if(distance_a + distance_b <= best_distance) {
1074 best_distance = distance_a + distance_b;
1075 best_value = &entry.value;
1096 double attacker_defense,
double defender_defense,
1098 int average_lawful_bonus) :
1102 std::round(defender_defense), average_lawful_bonus),
1103 defender_stats(defender, def_weapon, false, attacker, att_weapon,
1104 std::round(attacker_defense), average_lawful_bonus),
1139 avg_hp = std::max(0., avg_hp);
1152 double attacker_defense,
double defender_defense,
1153 double* damage_to_attacker,
double* damage_to_defender)
const {
1154 if(!attacker || !defender || !damage_to_attacker || !damage_to_defender) {
1161 std::shared_ptr<attack_simulation> best_att_attack;
1164 for (
const attack_type& att_weapon : attacker_weapons) {
1165 std::shared_ptr<attack_simulation> best_def_response;
1167 for (
const attack_type& def_weapon : defender_weapons) {
1168 if (att_weapon.range() != def_weapon.range()) {
1171 auto simulation = std::make_shared<attack_simulation>(
1173 attacker_defense, defender_defense,
1175 if (!best_def_response || simulation->better_result(best_def_response.get(),
true)) {
1176 best_def_response = simulation;
1180 if (!best_def_response) {
1184 attacker_defense, defender_defense,
1187 if (!best_att_attack || best_def_response->better_result(best_att_attack.get(),
false)) {
1188 best_att_attack = best_def_response;
1192 if (!best_att_attack) {
1196 *damage_to_defender += (defender->
hitpoints() - best_att_attack->get_avg_hp_of_defender());
1197 *damage_to_attacker += (attacker->
hitpoints() - best_att_attack->get_avg_hp_of_attacker());
1205 config* most_important_job =
nullptr;
1206 int most_important_importance = -1;
1207 int biggest_number = -1;
1212 int importance = job[
"importance"].to_int(1);
1213 int number = job[
"number"].to_int(99999);
1214 bool total = job[
"total"].to_bool(
false);
1220 const std::string&
unit_type = entry.first;
1221 const int count = entry.second;
1223 number = number - count;
1230 if (importance > most_important_importance ||
1231 (importance == most_important_importance && biggest_number > number)) {
1232 most_important_job = &job;
1233 most_important_importance = importance;
1234 biggest_number = number;
1237 return most_important_job;
1246 const config* job)
const {
1247 std::string choosen_type;
1248 if (job->operator[](
"pattern").to_bool(
false)) {
1249 std::vector<std::string> job_types =
utils::split(job->operator[](
"type"));
1251 if (job_types.empty()) {
1255 std::back_inserter(job_types));
1264 while (job_types_it != job_types.end()) {
1265 bool type_ok =
false;
1266 for (
const std::string& recruit : leader_data.
recruits) {
1277 job_types_it = job_types.erase(job_types_it);
1281 if (!job_types.empty()) {
1286 return choosen_type;
1295 if (recruitment_pattern.empty()) {
1300 std::stringstream
s;
1301 for (std::vector<std::string>::const_iterator
type = recruitment_pattern.begin();
1302 type != recruitment_pattern.end(); ++
type) {
1304 if (
type != recruitment_pattern.end() - 1) {
1308 job[
"type"] =
s.str();
1309 job[
"number"] = 99999;
1310 job[
"pattern"] =
true;
1311 job[
"blocker"] =
true;
1312 job[
"total"] =
false;
1313 job[
"importance"] = 1;
1326 for (
const std::string& recruit : leader_data.
recruits) {
1336 std::vector<std::string> ids =
utils::split(job->operator[](
"leader_id"));
1341 return (std::find(ids.begin(), ids.end(), leader_data.
leader->id()) != ids.end());
1353 for (
const config& limit :
aspect.child_range(
"limit")) {
1354 std::vector<std::string> types =
utils::split(limit[
"type"]);
1360 const std::string&
unit = entry.first;
1361 int number = entry.second;
1367 if (count >= limit[
"max"].to_int(0)) {
1381 std::vector<std::string> job_types =
utils::split(job->operator[](
"type"));
1391 if (!recruit_type) {
1395 if (recruit_type->
id() ==
type) {
1403 std::stringstream
s;
1404 s << recruit_type->
level();
1405 if (
s.str() ==
type) {
1416 const std::vector<std::string>& types)
const {
1418 if (types.empty()) {
1421 for (
const std::string&
type : types) {
1434 if ((*job)[
"blocker"].to_bool(
true)) {
1452 const std::size_t own_villages =
team.
villages().size();
1456 double total_income = 0;
1461 double resulting_income =
team.
base_income() + income - std::max(0., upkeep);
1462 total_income += resulting_income;
1464 return total_income;
1481 int neutral_villages = 0;
1496 double own_total_value = 0.;
1497 double team_total_value = 0.;
1498 double enemy_total_value = 0.;
1506 enemy_total_value += value;
1508 team_total_value += value;
1510 own_total_value += value;
1514 int allies_count = 0;
1522 if ((own_total_value == 0. || team_total_value == 0) && enemy_total_value == 0.) {
1524 }
else if (enemy_total_value == 0.) {
1532 double own_ratio = (own_total_value / enemy_total_value) * allies_count;
1533 double team_ratio = team_total_value / enemy_total_value;
1534 return std::min<double>(own_ratio, team_ratio);
1547 if (spend_all_gold > 0 &&
current_team().gold() >= spend_all_gold) {
1553 double income_estimation = 1.;
1564 if (
state_ ==
NORMAL && ratio > save_gold_begin && income_estimation > 0) {
1582 for (score_map::value_type& entry :
data.
scores) {
1583 double& score = entry.second;
1608 typedef std::map<std::string, int> similarity_map;
1609 similarity_map similarities;
1610 for (
const score_map::value_type& entry :
data.
scores) {
1611 const std::string& recruit = entry.first;
1613 if (!recruit_type) {
1616 for (
const std::string& advanced_type : recruit_type->
advancement_tree()) {
1618 ++similarities[recruit];
1619 ++similarities[advanced_type];
1624 for (score_map::value_type& entry :
data.
scores) {
1625 const std::string& recruit = entry.first;
1626 double& score = entry.second;
1627 score /= (similarities[recruit] + 1);
1636 std::map<std::size_t, int>::const_iterator it =
cheapest_unit_costs_.find(leader->underlying_id());
1641 int cheapest_cost = 999999;
1644 for (
const std::string& recruit :
current_team().recruits()) {
1649 if (
info->cost() < cheapest_cost) {
1650 cheapest_cost =
info->cost();
1654 for (
const std::string& recruit : leader->recruits()) {
1659 if (
info->cost() < cheapest_cost) {
1660 cheapest_cost =
info->cost();
1669 return cheapest_cost;
1682 for (score_map::value_type& entry :
data.
scores) {
1683 const std::string& recruit = entry.first;
1684 double& score = entry.second;
1699 std::vector<map_location> surrounding;
1701 if (surrounding.empty()) {
1706 if(enemy_it == units.
end()) {
1709 if (!
current_team().is_enemy(enemy_it->side()) || enemy_it->incapacitated()) {
1745 int neutral_villages = 0;
1753 double our_share =
static_cast<double>(neutral_villages) /
resources::gameboard->teams().size();
1761 scouts_wanted_ = (villages_per_scout > 0) ? std::round(our_share / villages_per_scout) : 0;
1769 const std::string&
unit_type = entry.first;
1770 const int count = entry.second;
1781 : recruit_list_changed_(false), gamestate_changed_(0) {
1787 const std::string& event) {
1788 if (event ==
"ai_recruit_list_changed") {
1790 set_recruit_list_changed(
true);
1792 ++gamestate_changed_;
1802 return recruit_list_changed_;
1806 recruit_list_changed_ = changed;
1810 return gamestate_changed_;
1814 gamestate_changed_ = 0;
1823 parsed_cfg[
"pattern"] =
true;
1824 parsed_cfg.
add_child(
"recruit", std::move(pattern));
1827 parsed_cfg[
"total"] =
true;
1828 parsed_cfg.
add_child(
"recruit", std::move(total));
1842 std::function<void(std::vector<std::shared_ptr<recruit_job>>&,
const config&)> factory_jobs =
1844 std::function<void(std::vector<std::shared_ptr<recruit_limit>>&,
const config&)> factory_limits =
1852 for (
const std::shared_ptr<recruit_job>& job :
jobs_) {
1853 cfg.
add_child(
"recruit", job->to_config());
1855 for (
const std::shared_ptr<recruit_limit>& lim :
limits_) {
1856 cfg.
add_child(
"limit", lim->to_config());
1863 jobs.emplace_back(std::make_shared<recruit_job>(
1865 job[
"leader_id"], job[
"id"],
1866 job[
"number"].to_int(-1), job[
"importance"].to_int(1),
1867 job[
"total"].to_bool(
false),
1868 job[
"blocker"].to_bool(
true),
1869 job[
"pattern"].to_bool(
true)
1874 limits.emplace_back(std::make_shared<recruit_limit>(
1877 lim[
"max"].to_int(0)
Various functions that implement attacks and attack calculations.
Managing the AI-Game interaction - AI actions and their results.
Managing the AIs lifecycle - headers TODO: Refactor history handling and internal commands.
boost::iterator_range< boost::indirect_iterator< attack_list::const_iterator > > const_attack_itors
static const double BAD_SCORE
bool is_allowed_unit(const unit &u) const
Flag indicating whether unit may be used by this candidate action.
virtual config to_config() const
serialize
double get_score() const
Get the usual score of the candidate action without re-evaluation.
property_handler_map & property_handlers()
~recruit_situation_change_observer()
void handle_generic_event(const std::string &event)
void reset_gamestate_changed()
bool recruit_list_changed()
void set_recruit_list_changed(bool changed)
recruit_situation_change_observer()
Observer Code.
void create_job(std::vector< std::shared_ptr< recruit_job >> &jobs, const config &job)
std::vector< std::shared_ptr< recruit_limit > > limits_
recruitment_aspect(readonly_context &context, const config &cfg, const std::string &id)
void create_limit(std::vector< std::shared_ptr< recruit_limit >> &limits, const config &lim)
std::vector< std::shared_ptr< recruit_job > > jobs_
double get_estimated_unit_gain() const
For Aspect "recruitment_save_gold".
bool leader_matches_job(const data &leader_data, const config *job) const
For Configuration / Aspect "recruitment-instructions" Checks if a given leader is specified in the "l...
void update_own_units_count()
void update_average_local_cost()
For Map Analysis.
std::map< std::size_t, int > cheapest_unit_costs_
config to_config() const
serialize
virtual void execute()
Execute the candidate action.
config * get_most_important_job()
For Configuration / Aspect "recruitment-instructions" We call a [recruit] tag a "job".
std::set< map_location > important_hexes_
void compare_cost_maps_and_update_important_hexes(const pathfind::full_cost_map &my_cost_map, const pathfind::full_cost_map &enemy_cost_map)
For Map Analysis Computes from our cost map and the combined cost map of all enemies the important he...
void do_combat_analysis(std::vector< data > *leader_data)
Combat Analysis.
int average_lawful_bonus_
const std::string * get_appropriate_recall(const std::string &type, const data &leader_data) const
void show_important_hexes() const
For Map Analysis.
int recruitment_instructions_turn_
void integrate_recruitment_pattern_in_recruitment_instructions()
For Configuration / Aspect "recruitment_pattern" Converts the (old) recruitment_pattern into a recrui...
bool recruit_matches_job(const std::string &recruit, const config *job) const
For Configuration / Aspect "recruitment-instructions" Checks if a given recruit-type is specified in ...
action_result_ptr execute_recall(const std::string &id, data &leader_data)
A helper function for execute().
double get_estimated_village_gain() const
For Aspect "recruitment_save_gold".
bool recruit_matches_types(const std::string &recruit, const std::vector< std::string > &types) const
For Configuration / Aspect "recruitment-instructions" Checks if a given recruit-type matches one of t...
void update_average_lawful_bonus()
Calculates a average lawful bonus, so Combat Analysis will work better in caves and custom time of da...
cache_table combat_cache_
count_map own_units_count_
std::map< map_location, double > average_local_cost_
double compare_unit_types(const std::string &a, const std::string &b)
For Combat Analysis.
void handle_recruitment_more(std::vector< data > *leader_data) const
For Aspect "recruitment_more".
void update_important_hexes()
For Map Analysis.
action_result_ptr execute_recruit(const std::string &type, data &leader_data)
A helper function for execute().
bool is_enemy_in_radius(const map_location &loc, int radius) const
Helper function.
bool remove_job_if_no_blocker(config *job)
For Configuration / Aspect "recruitment-instructions".
terrain_count_map important_terrain_
recruitment(rca_context &context, const config &cfg)
const pathfind::full_cost_map get_cost_map_of_side(int side) const
For Map Analysis.
double get_estimated_income(int turns) const
For Aspect "recruitment_save_gold".
const std::string get_random_pattern_type_if_exists(const data &leader_data, const config *job) const
For Configuration / Aspect "recruitment-instructions" If the flag pattern is set, this method returns...
void simulate_attack(const unit_type *const attacker, const unit_type *const defender, double attacker_defense, double defender_defense, double *damage_to_attacker, double *damage_to_defender) const
For Combat Analysis.
virtual double evaluate()
Evaluate the candidate action, resetting the internal state of the action.
int get_cheapest_unit_cost_for_leader(const unit_map::const_iterator &leader)
Called at the beginning and whenever the recruitment list changes.
double recall_unit_value(const unit_const_ptr &recall_unit) const
A helper function for execute().
data * get_best_leader_from_ratio_scores(std::vector< data > &leader_data, const config *job) const
A helper function for execute().
void do_randomness(std::vector< data > *leader_data) const
Will add a random value between 0 and "recruitment_randomness" to all recruits.
void update_scouts_wanted()
This function will use the aspect villages_per_scout to decide how many scouts we want to recruit.
recruit_situation_change_observer recruit_situation_change_observer_
bool limit_ok(const std::string &recruit) const
For Configuration / Aspect "recruitment-instructions" Checks if a recruit-type can be recruited accor...
double get_unit_ratio() const
For Aspect "recruitment_save_gold".
void update_state()
For Aspect "recruitment_save_gold".
config recruitment_instructions_
int own_units_in_combat_counter_
bool recruit_matches_type(const std::string &recruit, const std::string &type) const
For Configuration / Aspect "recruitment-instructions" Checks if a given recruit-type matches one atom...
const double * get_cached_combat_value(const std::string &a, const std::string &b, double a_defense, double b_defense)
For Combat Analysis.
double get_average_defense(const std::string &unit_type) const
For Map Analysis.
void do_similarity_penalty(std::vector< data > *leader_data) const
Will give a penalty to similar units.
const std::string get_best_recruit_from_scores(const data &leader_data, const config *job)
A helper function for execute().
void remove_gamestate_observer(events::observer *event_observer)
Removes an observer of game events except ai_user_interact event and ai_sync_network event.
void add_gamestate_observer(events::observer *event_observer)
Adds observer of game events except ai_user_interact event and ai_sync_network event.
void add_recruit_list_changed_observer(events::observer *event_observer)
Adds an observer of 'ai_recruit_list_changed' event.
static manager & get_singleton()
void remove_recruit_list_changed_observer(events::observer *event_observer)
Deletes an observer of 'ai_recruit_list_changed' event.
virtual const team & current_team() const override
virtual const config get_recruitment_save_gold() const override
virtual double get_recruitment_diversity() const override
virtual recruit_result_ptr check_recruit_action(const std::string &unit_name, const map_location &where=map_location::null_location(), const map_location &from=map_location::null_location()) override
virtual int get_recruitment_randomness() const override
virtual const config get_recruitment_instructions() const override
virtual recall_result_ptr check_recall_action(const std::string &id, const map_location &where=map_location::null_location(), const map_location &from=map_location::null_location()) override
virtual double power_projection(const map_location &loc, const move_map &dstsrc) const override
Function which finds how much 'power' a side can attack a certain location with.
virtual const std::vector< std::string > get_recruitment_pattern() const override
virtual const std::vector< std::string > get_recruitment_more() const override
virtual int get_villages_per_scout() const override
virtual const move_map & get_enemy_dstsrc() const override
virtual side_number get_side() const override
Get the side number.
std::shared_ptr< T > value_
static bool better_combat(const combatant &us_a, const combatant &them_a, const combatant &us_b, const combatant &them_b, double harm_weight)
A config object defines a single node in a WML file, with access to child nodes.
config & mandatory_child(config_key_type key, int n=0)
Returns the nth child with the given key, or throws an error if there is none.
void clear_children(T... keys)
bool has_child(config_key_type key) const
Determine whether a config has a child or not.
child_itors child_range(config_key_type key)
config & add_child(config_key_type key)
int side_upkeep(int side_num) const
static display * get_singleton()
Returns the display object if a display object exists.
virtual const unit_map & units() const override
virtual const gamemap & map() const override
void for_each_walkable_loc(const F &f) const
int w() const
Effective map width.
int h() const
Effective map height.
bool on_board(const map_location &loc) const
Tell if a location is on the map.
Encapsulates the map of the game.
const std::vector< map_location > & villages() const
Return a list of the locations of villages on the map.
const terrain_label * set_label(const map_location &loc, const t_string &text, const int creator=-1, const std::string &team="", const color_t color=font::NORMAL_COLOR, const bool visible_in_fog=true, const bool visible_in_shroud=false, const bool immutable=false, const std::string &category="", const t_string &tooltip="")
int cost(const t_translation::terrain_code &terrain, bool slowed=false) const
Returns the cost associated with the given terrain.
int defense_modifier(const t_translation::terrain_code &terrain) const
Returns the defensive value of the indicated terrain.
const terrain_costs & get_movement() const
static rng & default_instance()
int get_random_int(int min, int max)
double get_random_double()
This helper method returns a floating-point number in the range [0,1[.
This class stores all the data for a single 'side' (in game nomenclature).
bool is_enemy(int n) const
const std::set< map_location > & villages() const
const std::set< std::string > & recruits() const
Container associating units to locations.
std::vector< unit_iterator > find_leaders(int side)
unit_iterator find(std::size_t id)
umap_retval_pair_t insert(unit_ptr p)
Inserts the unit pointed to by p into the map.
const unit_type * find(const std::string &key, unit_type::BUILD_STATUS status=unit_type::FULL) const
Finds a unit_type by its id() and makes sure it is built to the specified level.
A single unit type that the player may recruit.
const std::string & id() const
The id for this unit_type.
const movetype & movement_type() const
const_attack_itors attacks() const
const std::string & usage() const
std::set< std::string > advancement_tree() const
Get the advancement tree.
This class represents a single unit of a specific type.
A variable-expanding proxy for the config class.
int max_hitpoints() const
The max number of hitpoints this unit can have.
bool incapacitated() const
Check if the unit has been petrified.
int hitpoints() const
The current number of hitpoints this unit has.
int cost() const
How much gold is required to recruit this unit.
const std::string & type_id() const
The id of this unit's type.
bool can_recruit() const
Whether this unit can recruit other units - ie, are they a leader unit.
int side() const
The side this unit belongs to.
const map_location & get_location() const
The current map location this unit is at.
int total_movement() const
The maximum moves this unit has.
std::string id
Text to match against addon_info.tags()
Standard logging facilities (interface).
bool recall_unit(const std::string &id, team ¤t_team, const map_location &loc, const map_location &from, map_location::DIRECTION facing, bool show, bool use_undo)
Recalls the unit with the indicated ID for the provided team.
A small explanation about what's going on here: Each action has access to two game_info objects First...
std::shared_ptr< recruit_result > recruit_result_ptr
static void register_vector_property(property_handler_map &property_handlers, const std::string &property, std::vector< std::shared_ptr< X >> &values, std::function< void(std::vector< std::shared_ptr< X >> &, const config &)> construction_factory)
std::shared_ptr< action_result > action_result_ptr
std::shared_ptr< recall_result > recall_result_ptr
std::vector< game_tip > shuffle(const std::vector< game_tip > &tips)
Shuffles the tips.
retval
Default window/dialog return values.
std::stringstream & log_to_chat()
Use this to show WML errors in the ingame chat.
map_location find_vacant_castle(const unit &leader)
Wrapper for find_vacant_tile() when looking for a vacant castle tile near a leader.
rng * generator
This generator is automatically synced during synced context.
::tod_manager * tod_manager
std::size_t size(const std::string &str)
Length in characters of a UTF-8 string.
std::vector< std::string > split(const config_attribute_value &val)
std::string::const_iterator iterator
This module contains various pathfinding functions and utilities.
void get_tiles_in_radius(const map_location ¢er, const int radius, std::vector< map_location > &result)
Function that will add to result all locations within radius tiles of center (excluding center itself...
std::shared_ptr< const unit > unit_const_ptr
std::shared_ptr< const attack_type > const_attack_ptr
candidate action framework
static lg::log_domain log_ai_recruitment("ai/recruitment")
#define LOG_AI_RECRUITMENT
static lg::log_domain log_wml("wml")
#define ERR_AI_RECRUITMENT
Recruitment Engine by flix See https://wiki.wesnoth.org/AI_Recruitment.
combatant defender_combatant
bool better_result(const attack_simulation *other, bool for_defender)
const unit_type * attacker_type
const battle_context_unit_stats defender_stats
double get_avg_hp_of_attacker() const
const battle_context_unit_stats attacker_stats
combatant attacker_combatant
double get_avg_hp_of_defender() const
const unit_type * defender_type
double get_avg_hp_of_combatant(bool attacker) const
attack_simulation(const unit_type *attacker, const unit_type *defender, double attacker_defense, double defender_defense, const_attack_ptr att_weapon, const_attack_ptr def_weapon, int average_lawful_bonus)
unit_map::const_iterator leader
std::string to_string() const
std::set< std::string > recruits
score_map get_normalized_scores() const
Structure describing the statistics of a unit involved in the battle.
double poisoned
Resulting chance we are poisoned.
double average_hp(unsigned int healing=0) const
What's the average hp (weighted average of hp_dist).
void fight(combatant &opponent, bool levelup_considered=true)
Simulate a fight! Can be called multiple times for cumulative calculations.
Encapsulates the map of the game.
static const map_location & null_location()
Structure which uses find_routes() to build a cost map This maps each hex to a the movements a unit w...
double get_average_cost_at(map_location loc) const
Accessor for the costs.
void add_unit(const unit &u, bool use_max_moves=true)
Adds a units cost map to cost_map (increments the elements in cost_map)
int get_cost_at(map_location loc) const
Accessor for the costs.
A terrain string which is converted to a terrain is a string with 1 or 2 layers the layers are separa...
Object which defines a time of day with associated bonuses, image, sounds etc.
static map_location::DIRECTION s
unit_type_data unit_types