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)
131 , total_own_units_(0)
135 if (
cfg[
"state"] ==
"save_gold") {
137 }
else if (
cfg[
"state"] ==
"spend_all_gold") {
147 cfg[
"state"] =
"save_gold";
149 cfg[
"state"] =
"spend_all_gold";
151 cfg[
"state"] =
"normal";
196 if (
current_team().gold() < cheapest_unit_cost && cheapest_unit_cost > 0) {
224 std::vector<data> leader_data;
226 std::set<std::string> global_recruits;
243 if (
current_team().gold() < cheapest_unit_cost && cheapest_unit_cost > 0) {
253 for (
const std::string& recruit :
current_team().recruits()) {
255 lg::log_to_chat() <<
"Unit-type \"" << recruit <<
"\" doesn't exist.\n";
256 ERR_WML <<
"Unit-type \"" << recruit <<
"\" doesn't exist.";
260 global_recruits.insert(recruit);
264 for (
const std::string& recruit : leader->recruits()) {
266 lg::log_to_chat() <<
"Unit-type \"" << recruit <<
"\" doesn't exist.\n";
267 ERR_WML <<
"Unit-type \"" << recruit <<
"\" doesn't exist.";
271 global_recruits.insert(recruit);
284 if (recall_value < 0) {
289 global_recruits.insert(recall->type_id());
302 leader_data.push_back(
data);
305 if (leader_data.empty()) {
310 if (global_recruits.empty()) {
341 for (
const data&
data : leader_data) {
350 for (
const data&
data : leader_data) {
369 bool save_gold_active = save_gold_turn > 0 && save_gold_turn <= current_turn;
382 if (!best_leader_data) {
393 if (best_recruit.empty()) {
419 if (!job->operator[](
"total").to_bool(
false)) {
420 job->operator[](
"number") = job->operator[](
"number").to_int(99999) - 1;
457 if (job && no_gold) {
468 leader_data.
leader->get_location());
482 leader_data.
leader->get_location());
501 double average_cost_of_advanced_unit = 0;
503 for (
const std::string& advancement :
recall_unit->advances_to()) {
505 if (!advancement_type) {
508 average_cost_of_advanced_unit += advancement_type->
cost();
512 average_cost_of_advanced_unit /= counter;
515 average_cost_of_advanced_unit =
recall_unit->cost();
517 double xp_quantity =
static_cast<double>(
recall_unit->experience()) /
519 double recall_value =
recall_unit->cost() + xp_quantity * average_cost_of_advanced_unit;
524 if (recall_value < cost) {
531 const data& leader_data)
const {
532 const std::string* best_recall_id =
nullptr;
533 double best_recall_value = -1;
545 if (recall_value > best_recall_value) {
547 best_recall_value = recall_value;
550 return best_recall_id;
558 const config* job)
const {
561 int total_recruit_count = 0;
562 double ratio_score_sum = 0.0;
563 for (
const data&
data : leader_data) {
567 assert(ratio_score_sum > 0.0);
573 data* best_leader_data =
nullptr;
574 double biggest_difference = -99999.;
579 double desired_ammount =
data.
ratio_score / ratio_score_sum * (total_recruit_count + 1);
581 double difference = desired_ammount - current_ammount;
582 if (difference > biggest_difference) {
583 biggest_difference = difference;
584 best_leader_data = &
data;
587 return best_leader_data;
599 if (!pattern_type.empty()) {
602 std::string best_recruit =
"";
603 double biggest_difference = -99999.;
605 const std::string&
unit =
i.first;
606 const double score =
i.second;
611 if (!pattern_type.empty()) {
623 double difference = desired_ammount - current_ammount;
627 if (difference > biggest_difference) {
628 biggest_difference = difference;
649 typedef std::map<map_location, double> border_cost_map;
650 border_cost_map important_hexes_candidates;
651 double smallest_border_movecost = 999999;
652 double biggest_border_movecost = 0;
657 if (my_cost_average == -1 || enemy_cost_average == -1) {
662 if (std::abs(my_cost_average - MAP_OFFENSIVE_SHIFT - enemy_cost_average) <
664 double border_movecost = (my_cost_average + enemy_cost_average) / 2;
665 important_hexes_candidates[
loc] = border_movecost;
667 if (border_movecost < smallest_border_movecost) {
668 smallest_border_movecost = border_movecost;
670 if (border_movecost > biggest_border_movecost) {
671 biggest_border_movecost = border_movecost;
677 double threshold = (biggest_border_movecost - smallest_border_movecost) *
678 MAP_BORDER_WIDTH + smallest_border_movecost;
679 for (
const border_cost_map::value_type& candidate : important_hexes_candidates) {
680 if (candidate.second < threshold) {
696 long summed_defense = 0;
697 int total_terrains = 0;
700 int count = entry.second;
702 summed_defense +=
static_cast<long>(defense) * count;
703 total_terrains += count;
705 double average_defense = (total_terrains == 0) ? 0.0 :
706 static_cast<double>(summed_defense) / total_terrains;
707 return average_defense;
724 unsigned int unit_count = 0;
735 if (unit_count < UNIT_THRESHOLD) {
736 std::vector<unit_map::const_iterator> leaders = units.
find_leaders(side);
744 for (
const std::string& recruit : leader->recruits()) {
775 sum += time.lawful_bonus;
792 for(
int x = 0; x < map.
w(); ++x) {
793 for (
int y = 0; y < map.
h(); ++y) {
836 std::vector<map_location> surrounding;
839 std::copy(surrounding.begin(), surrounding.end(),
864 std::vector<map_location> important_villages;
866 std::vector<map_location> surrounding;
870 important_villages.push_back(village);
875 for (
const map_location& village : important_villages) {
877 std::vector<map_location> surrounding;
898 if (!type_a || !type_b) {
910 double damage_to_a = 0.0;
911 double damage_to_b = 0.0;
914 simulate_attack(type_a, type_b, defense_a, defense_b, &damage_to_a, &damage_to_b);
916 simulate_attack(type_b, type_a, defense_b, defense_a, &damage_to_b, &damage_to_a);
918 int a_cost = (type_a->
cost() > 0) ? type_a->
cost() : 1;
919 int b_cost = (type_b->
cost() > 0) ? type_b->
cost() : 1;
926 if (damage_to_a <= 0 && damage_to_b <= 0) {
928 }
else if (damage_to_a <= 0) {
930 }
else if (damage_to_b <= 0) {
934 double value_of_a = damage_to_b / (b_max_hp * a_cost);
935 double value_of_b = damage_to_a / (a_max_hp * b_cost);
937 if (value_of_a > value_of_b) {
938 retval = value_of_a / value_of_b;
939 }
else if (value_of_a < value_of_b) {
940 retval = -value_of_b / value_of_a;
964 typedef std::vector<std::pair<std::string, int>> unit_hp_vector;
965 unit_hp_vector enemy_units;
972 if (enemy_units.size() < UNIT_THRESHOLD) {
978 std::set<std::string> possible_recruits;
984 possible_recruits.insert(leader->recruits().begin(), leader->recruits().end());
987 for (
const std::string& possible_recruit : possible_recruits) {
991 enemy_units.emplace_back(possible_recruit, hp);
997 for (
data& leader : *leader_data) {
998 if (leader.recruits.empty()) {
1001 typedef std::map<std::string, double> simple_score_map;
1002 simple_score_map temp_scores;
1004 for (
const unit_hp_vector::value_type& entry : enemy_units) {
1005 const std::string& enemy_unit = entry.first;
1006 int enemy_unit_hp = entry.second;
1007 for (
const std::string& recruit : leader.recruits) {
1009 score *= enemy_unit_hp;
1010 score = std::pow(score, COMBAT_SCORE_POWER);
1011 temp_scores[recruit] += score;
1015 if (temp_scores.empty()) {
1019 double max = -99999.;
1021 for (
const simple_score_map::value_type& entry : temp_scores) {
1022 double score = entry.second;
1028 double average = sum / temp_scores.size();
1034 double new_100 = max;
1036 if (score_threshold <= 0) {
1037 score_threshold = 0.0001;
1039 double new_0 = max - (score_threshold * (max - average));
1040 if (new_100 == new_0) {
1045 for (
const simple_score_map::value_type& entry : temp_scores) {
1046 const std::string& recruit = entry.first;
1047 double score = entry.second;
1052 double normalized_score = 100 * ((score - new_0) / (new_100 - new_0));
1053 if (normalized_score < 0) {
1054 normalized_score = 0;
1056 leader.scores[recruit] += normalized_score;
1067 double a_defense,
double b_defense) {
1068 double best_distance = 999;
1069 const double* best_value =
nullptr;
1070 const std::set<cached_combat_value>& cache =
combat_cache_[a][
b];
1072 double distance_a = std::abs(entry.a_defense - a_defense);
1073 double distance_b = std::abs(entry.b_defense - b_defense);
1074 if (distance_a <= COMBAT_CACHE_TOLERANCY && distance_b <= COMBAT_CACHE_TOLERANCY) {
1075 if(distance_a + distance_b <= best_distance) {
1076 best_distance = distance_a + distance_b;
1077 best_value = &entry.value;
1086 if (i_wep < up->attacks().
size()) {
1087 return up->
attacks()[i_wep].shared_from_this();
1108 double attacker_defense,
double defender_defense,
1109 size_t i_att_weapon,
size_t i_def_weapon,
1110 int average_lawful_bonus) :
1114 std::round(defender_defense), average_lawful_bonus),
1116 std::round(attacker_defense), average_lawful_bonus),
1151 avg_hp = std::max(0., avg_hp);
1152 avg_hp = std::min(
static_cast<double>(u->max_hitpoints()), avg_hp);
1164 double attacker_defense,
double defender_defense,
1165 double* damage_to_attacker,
double* damage_to_defender)
const {
1166 if(!attacker_t || !defender_t || !damage_to_attacker || !damage_to_defender) {
1176 std::shared_ptr<attack_simulation> best_att_attack;
1179 for(
size_t i_att_weapon = 0; i_att_weapon < attacker_weapons.size(); ++i_att_weapon) {
1181 std::shared_ptr<attack_simulation> best_def_response;
1183 for(
size_t i_def_weapon = 0; i_def_weapon < defender_weapons.size(); ++i_def_weapon) {
1186 if (attacker_weapons[i_att_weapon].range() != defender_weapons[i_def_weapon].range()) {
1189 auto simulation = std::make_shared<attack_simulation>(
1191 attacker_defense, defender_defense,
1193 if (!best_def_response ||
simulation->better_result(best_def_response.get(),
true)) {
1198 if (!best_def_response) {
1202 attacker_defense, defender_defense,
1205 if (!best_att_attack || best_def_response->better_result(best_att_attack.get(),
false)) {
1206 best_att_attack = best_def_response;
1210 if (!best_att_attack) {
1214 *damage_to_defender += (defender->max_hitpoints() - best_att_attack->get_avg_hp_of_defender());
1215 *damage_to_attacker += (attacker->max_hitpoints() - best_att_attack->get_avg_hp_of_attacker());
1223 auto u = std::make_pair(
1237 config* most_important_job =
nullptr;
1238 int most_important_importance = -1;
1239 int biggest_number = -1;
1244 int importance = job[
"importance"].to_int(1);
1245 int number = job[
"number"].to_int(99999);
1246 bool total = job[
"total"].to_bool(
false);
1252 const std::string&
unit_type = entry.first;
1253 const int count = entry.second;
1255 number = number - count;
1262 if (importance > most_important_importance ||
1263 (importance == most_important_importance && biggest_number > number)) {
1264 most_important_job = &job;
1265 most_important_importance = importance;
1266 biggest_number = number;
1269 return most_important_job;
1278 const config* job)
const {
1279 std::string choosen_type;
1280 if (job->operator[](
"pattern").to_bool(
false)) {
1281 std::vector<std::string> job_types =
utils::split(job->operator[](
"type"));
1283 if (job_types.empty()) {
1287 std::back_inserter(job_types));
1296 while (job_types_it != job_types.end()) {
1297 bool type_ok =
false;
1298 for (
const std::string& recruit : leader_data.
recruits) {
1309 job_types_it = job_types.erase(job_types_it);
1313 if (!job_types.empty()) {
1318 return choosen_type;
1327 if (recruitment_pattern.empty()) {
1332 std::stringstream
s;
1333 for (std::vector<std::string>::const_iterator
type = recruitment_pattern.begin();
1334 type != recruitment_pattern.end(); ++
type) {
1336 if (
type != recruitment_pattern.end() - 1) {
1340 job[
"type"] =
s.str();
1341 job[
"number"] = 99999;
1342 job[
"pattern"] =
true;
1343 job[
"blocker"] =
true;
1344 job[
"total"] =
false;
1345 job[
"importance"] = 1;
1358 for (
const std::string& recruit : leader_data.
recruits) {
1368 std::vector<std::string> ids =
utils::split(job->operator[](
"leader_id"));
1385 for (
const config& limit :
aspect.child_range(
"limit")) {
1386 std::vector<std::string> types =
utils::split(limit[
"type"]);
1392 const std::string&
unit = entry.first;
1393 int number = entry.second;
1399 if (count >= limit[
"max"].to_int(0)) {
1413 std::vector<std::string> job_types =
utils::split(job->operator[](
"type"));
1423 if (!recruit_type) {
1427 if (recruit_type->
id() ==
type) {
1435 std::stringstream
s;
1436 s << recruit_type->
level();
1437 if (
s.str() ==
type) {
1448 const std::vector<std::string>& types)
const {
1450 if (types.empty()) {
1453 for (
const std::string&
type : types) {
1466 if ((*job)[
"blocker"].to_bool(
true)) {
1484 const std::size_t own_villages =
team.
villages().size();
1488 double total_income = 0;
1489 for (
int i = 1;
i <= turns; ++
i) {
1493 double resulting_income =
team.
base_income() + income - std::max(0., upkeep);
1494 total_income += resulting_income;
1496 return total_income;
1513 int neutral_villages = 0;
1528 double own_total_value = 0.;
1529 double team_total_value = 0.;
1530 double enemy_total_value = 0.;
1538 enemy_total_value += value;
1540 team_total_value += value;
1542 own_total_value += value;
1546 int allies_count = 0;
1554 if ((own_total_value == 0. || team_total_value == 0) && enemy_total_value == 0.) {
1556 }
else if (enemy_total_value == 0.) {
1564 double own_ratio = (own_total_value / enemy_total_value) * allies_count;
1565 double team_ratio = team_total_value / enemy_total_value;
1566 return std::min<double>(own_ratio, team_ratio);
1579 if (spend_all_gold > 0 &&
current_team().gold() >= spend_all_gold) {
1585 double income_estimation = 1.;
1596 if (
state_ ==
NORMAL && ratio > save_gold_begin && income_estimation > 0) {
1614 for (score_map::value_type& entry :
data.
scores) {
1615 double& score = entry.second;
1640 typedef std::map<std::string, int> similarity_map;
1641 similarity_map similarities;
1642 for (
const score_map::value_type& entry :
data.
scores) {
1643 const std::string& recruit = entry.first;
1645 if (!recruit_type) {
1648 for (
const std::string& advanced_type : recruit_type->
advancement_tree()) {
1650 ++similarities[recruit];
1651 ++similarities[advanced_type];
1656 for (score_map::value_type& entry :
data.
scores) {
1657 const std::string& recruit = entry.first;
1658 double& score = entry.second;
1659 score /= (similarities[recruit] + 1);
1668 std::map<std::size_t, int>::const_iterator it =
cheapest_unit_costs_.find(leader->underlying_id());
1673 int cheapest_cost = 999999;
1676 for (
const std::string& recruit :
current_team().recruits()) {
1681 if (
info->cost() < cheapest_cost) {
1682 cheapest_cost =
info->cost();
1686 for (
const std::string& recruit : leader->recruits()) {
1691 if (
info->cost() < cheapest_cost) {
1692 cheapest_cost =
info->cost();
1701 return cheapest_cost;
1714 for (score_map::value_type& entry :
data.
scores) {
1715 const std::string& recruit = entry.first;
1716 double& score = entry.second;
1731 std::vector<map_location> surrounding;
1733 if (surrounding.empty()) {
1738 if(enemy_it == units.
end()) {
1741 if (!
current_team().is_enemy(enemy_it->side()) || enemy_it->incapacitated()) {
1777 int neutral_villages = 0;
1785 double our_share =
static_cast<double>(neutral_villages) /
resources::gameboard->teams().size();
1793 scouts_wanted_ = (villages_per_scout > 0) ? std::round(our_share / villages_per_scout) : 0;
1801 const std::string&
unit_type = entry.first;
1802 const int count = entry.second;
1813 : recruit_list_changed_(false), gamestate_changed_(0) {
1819 const std::string& event) {
1820 if (event ==
"ai_recruit_list_changed") {
1822 set_recruit_list_changed(
true);
1824 ++gamestate_changed_;
1834 return recruit_list_changed_;
1838 recruit_list_changed_ = changed;
1842 return gamestate_changed_;
1846 gamestate_changed_ = 0;
1855 parsed_cfg[
"pattern"] =
true;
1856 parsed_cfg.
add_child(
"recruit", pattern);
1859 parsed_cfg[
"total"] =
true;
1876 [
this](
auto&&... args) {
create_job(args...); });
1884 for (
const std::shared_ptr<recruit_job>& job :
jobs_) {
1887 for (
const std::shared_ptr<recruit_limit>& lim :
limits_) {
1895 jobs.emplace_back(std::make_shared<recruit_job>(
1897 job[
"leader_id"], job[
"id"],
1898 job[
"number"].to_int(-1), job[
"importance"].to_int(1),
1899 job[
"total"].to_bool(
false),
1900 job[
"blocker"].to_bool(
true),
1901 job[
"pattern"].to_bool(
true)
1906 limits.emplace_back(std::make_shared<recruit_limit>(
1909 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...
std::pair< nonempty_unit_const_ptr, nonempty_unit_const_ptr > get_dummy_of_type(const unit_type *const attacker) const
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.
std::map< const unit_type *, std::pair< nonempty_unit_const_ptr, nonempty_unit_const_ptr > > combat_dummies_
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 & add_child(std::string_view key)
child_itors child_range(std::string_view key)
void clear_children(T... keys)
bool has_child(std::string_view key) const
Determine whether a config has a child or not.
config & mandatory_child(std::string_view key, int n=0)
Returns the nth child with the given key, or throws an error if there is none.
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(const 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 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.
static unit_ptr create(const config &cfg, bool use_traits=false, const vconfig *vcfg=nullptr)
Initializes a unit from a config.
A variable-expanding proxy for the config class.
map_display and display: classes which take care of displaying the map and game-data on the screen.
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.
attack_itors attacks()
Gets an iterator over this unit's attacks.
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)
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, Factory &&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(std::string_view str)
Length in characters of a UTF-8 string.
bool contains(const Container &container, const Value &value)
Returns true iff value is found in container.
std::vector< std::string > split(const config_attribute_value &val)
auto * find(Container &container, const Value &value)
Convenience wrapper for using find on a container without needing to comare to end()
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...
utils::shared_reference< const unit > nonempty_unit_const_ptr
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)
attack_simulation(nonempty_unit_const_ptr attacker, nonempty_unit_const_ptr defender, double attacker_defense, double defender_defense, size_t i_att_weapon, size_t i_def_weapon, int average_lawful_bonus)
const battle_context_unit_stats defender_stats
double get_avg_hp_of_attacker() const
const battle_context_unit_stats attacker_stats
combatant attacker_combatant
nonempty_unit_const_ptr attacker_u
double get_avg_hp_of_defender() const
double get_avg_hp_of_combatant(bool attacker) const
nonempty_unit_const_ptr defender_u
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.
map_location get_direction(direction dir, unsigned int n=1u) const
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