49 #define LOG_AI_RECRUITMENT LOG_STREAM(info, log_ai_recruitment)
50 #define ERR_AI_RECRUITMENT LOG_STREAM(err, log_ai_recruitment)
53 #define ERR_WML LOG_STREAM(err, log_wml)
57 namespace default_recruitment {
66 const static int SAVE_GOLD_FORECAST_TURNS = 5;
69 const static unsigned int UNIT_THRESHOLD = 5;
73 const static double MAP_BORDER_THICKNESS = 2.0;
74 const static double MAP_BORDER_WIDTH = 0.2;
80 const static int MAP_OFFENSIVE_SHIFT = 0;
83 const static int MAP_VILLAGE_NEARNESS_THRESHOLD = 3;
86 const static int MAP_VILLAGE_SURROUNDING = 1;
91 const static double COMBAT_SCORE_POWER = 1.;
96 const static double COMBAT_CACHE_TOLERANCY = 0.5;
100 const static double VILLAGE_PER_SCOUT_MULTIPLICATOR = 2.;
105 s <<
"---------------Content of leader data---------------\n";
106 s <<
"For leader: " <<
leader->name() <<
"\n";
109 for (
const score_map::value_type& entry :
scores) {
110 s << std::setw(20) << entry.first <<
111 " score: " << std::setw(7) << entry.second <<
"\n";
113 s <<
"----------------------------------------------------\n";
120 important_terrain_(),
121 own_units_in_combat_counter_(0),
122 average_local_cost_(),
123 cheapest_unit_costs_(),
125 recruit_situation_change_observer_(),
126 average_lawful_bonus_(0.0),
127 recruitment_instructions_(),
128 recruitment_instructions_turn_(-1),
133 if (cfg[
"state"] ==
"save_gold") {
135 }
else if (cfg[
"state"] ==
"spend_all_gold") {
145 cfg[
"state"] =
"save_gold";
147 cfg[
"state"] =
"spend_all_gold";
149 cfg[
"state"] =
"normal";
193 if (
current_team().gold() < cheapest_unit_cost && cheapest_unit_cost > 0) {
221 std::vector<data> leader_data;
223 std::set<std::string> global_recruits;
240 if (
current_team().gold() < cheapest_unit_cost && cheapest_unit_cost > 0) {
250 for (
const std::string& recruit :
current_team().recruits()) {
252 lg::log_to_chat() <<
"Unit-type \"" << recruit <<
"\" doesn't exist.\n";
253 ERR_WML <<
"Unit-type \"" << recruit <<
"\" doesn't exist.";
257 global_recruits.insert(recruit);
261 for (
const std::string& recruit : leader->recruits()) {
263 lg::log_to_chat() <<
"Unit-type \"" << recruit <<
"\" doesn't exist.\n";
264 ERR_WML <<
"Unit-type \"" << recruit <<
"\" doesn't exist.";
268 global_recruits.insert(recruit);
281 if (recall_value < 0) {
286 global_recruits.insert(recall->type_id());
299 leader_data.push_back(
data);
302 if (leader_data.empty()) {
307 if (global_recruits.empty()) {
338 for (
const data&
data : leader_data) {
347 for (
const data&
data : leader_data) {
366 bool save_gold_active = save_gold_turn > 0 && save_gold_turn <= current_turn;
379 if (!best_leader_data) {
390 if (best_recruit.empty()) {
416 if (!job->operator[](
"total").to_bool(
false)) {
417 job->operator[](
"number") = job->operator[](
"number").to_int(99999) - 1;
454 if (job && no_gold) {
465 leader_data.
leader->get_location());
479 leader_data.
leader->get_location());
498 double average_cost_of_advanced_unit = 0;
500 for (
const std::string& advancement :
recall_unit->advances_to()) {
502 if (!advancement_type) {
505 average_cost_of_advanced_unit += advancement_type->
cost();
509 average_cost_of_advanced_unit /= counter;
512 average_cost_of_advanced_unit =
recall_unit->cost();
514 double xp_quantity =
static_cast<double>(
recall_unit->experience()) /
516 double recall_value =
recall_unit->cost() + xp_quantity * average_cost_of_advanced_unit;
521 if (recall_value < cost) {
528 const data& leader_data)
const {
529 const std::string* best_recall_id =
nullptr;
530 double best_recall_value = -1;
542 if (recall_value > best_recall_value) {
544 best_recall_value = recall_value;
547 return best_recall_id;
555 const config* job)
const {
558 int total_recruit_count = 0;
559 double ratio_score_sum = 0.0;
560 for (
const data&
data : leader_data) {
564 assert(ratio_score_sum > 0.0);
570 data* best_leader_data =
nullptr;
571 double biggest_difference = -99999.;
576 double desired_ammount =
data.
ratio_score / ratio_score_sum * (total_recruit_count + 1);
578 double difference = desired_ammount - current_ammount;
579 if (difference > biggest_difference) {
580 biggest_difference = difference;
581 best_leader_data = &
data;
584 return best_leader_data;
596 if (!pattern_type.empty()) {
599 std::string best_recruit =
"";
600 double biggest_difference = -99999.;
602 const std::string&
unit =
i.first;
603 const double score =
i.second;
608 if (!pattern_type.empty()) {
620 double difference = desired_ammount - current_ammount;
624 if (difference > biggest_difference) {
625 biggest_difference = difference;
646 typedef std::map<map_location, double> border_cost_map;
647 border_cost_map important_hexes_candidates;
648 double smallest_border_movecost = 999999;
649 double biggest_border_movecost = 0;
654 if (my_cost_average == -1 || enemy_cost_average == -1) {
659 if (std::abs(my_cost_average - MAP_OFFENSIVE_SHIFT - enemy_cost_average) <
661 double border_movecost = (my_cost_average + enemy_cost_average) / 2;
662 important_hexes_candidates[loc] = border_movecost;
664 if (border_movecost < smallest_border_movecost) {
665 smallest_border_movecost = border_movecost;
667 if (border_movecost > biggest_border_movecost) {
668 biggest_border_movecost = border_movecost;
674 double threshold = (biggest_border_movecost - smallest_border_movecost) *
675 MAP_BORDER_WIDTH + smallest_border_movecost;
676 for (
const border_cost_map::value_type& candidate : important_hexes_candidates) {
677 if (candidate.second < threshold) {
693 long summed_defense = 0;
694 int total_terrains = 0;
697 int count = entry.second;
699 summed_defense +=
static_cast<long>(defense) * count;
700 total_terrains += count;
702 double average_defense = (total_terrains == 0) ? 0.0 :
703 static_cast<double>(summed_defense) / total_terrains;
704 return average_defense;
721 unsigned int unit_count = 0;
732 if (unit_count < UNIT_THRESHOLD) {
733 std::vector<unit_map::const_iterator> leaders = units.
find_leaders(side);
741 for (
const std::string& recruit : leader->recruits()) {
772 sum += time.lawful_bonus;
789 for(
int x = 0; x < map.
w(); ++x) {
790 for (
int y = 0; y < map.
h(); ++y) {
833 std::vector<map_location> surrounding;
836 std::copy(surrounding.begin(), surrounding.end(),
861 std::vector<map_location> important_villages;
863 std::vector<map_location> surrounding;
867 important_villages.push_back(village);
872 for (
const map_location& village : important_villages) {
874 std::vector<map_location> surrounding;
895 if (!type_a || !type_b) {
907 double damage_to_a = 0.0;
908 double damage_to_b = 0.0;
911 simulate_attack(type_a, type_b, defense_a, defense_b, &damage_to_a, &damage_to_b);
913 simulate_attack(type_b, type_a, defense_b, defense_a, &damage_to_b, &damage_to_a);
915 int a_cost = (type_a->
cost() > 0) ? type_a->
cost() : 1;
916 int b_cost = (type_b->
cost() > 0) ? type_b->
cost() : 1;
923 if (damage_to_a <= 0 && damage_to_b <= 0) {
925 }
else if (damage_to_a <= 0) {
927 }
else if (damage_to_b <= 0) {
931 double value_of_a = damage_to_b / (b_max_hp * a_cost);
932 double value_of_b = damage_to_a / (a_max_hp * b_cost);
934 if (value_of_a > value_of_b) {
935 retval = value_of_a / value_of_b;
936 }
else if (value_of_a < value_of_b) {
937 retval = -value_of_b / value_of_a;
961 typedef std::vector<std::pair<std::string, int>> unit_hp_vector;
962 unit_hp_vector enemy_units;
969 if (enemy_units.size() < UNIT_THRESHOLD) {
975 std::set<std::string> possible_recruits;
981 possible_recruits.insert(leader->recruits().begin(), leader->recruits().end());
984 for (
const std::string& possible_recruit : possible_recruits) {
988 enemy_units.emplace_back(possible_recruit, hp);
994 for (
data& leader : *leader_data) {
995 if (leader.recruits.empty()) {
998 typedef std::map<std::string, double> simple_score_map;
999 simple_score_map temp_scores;
1001 for (
const unit_hp_vector::value_type& entry : enemy_units) {
1002 const std::string& enemy_unit = entry.first;
1003 int enemy_unit_hp = entry.second;
1004 for (
const std::string& recruit : leader.recruits) {
1006 score *= enemy_unit_hp;
1007 score = std::pow(score, COMBAT_SCORE_POWER);
1008 temp_scores[recruit] += score;
1012 if (temp_scores.empty()) {
1016 double max = -99999.;
1018 for (
const simple_score_map::value_type& entry : temp_scores) {
1019 double score = entry.second;
1025 double average = sum / temp_scores.size();
1031 double new_100 = max;
1033 if (score_threshold <= 0) {
1034 score_threshold = 0.0001;
1036 double new_0 = max - (score_threshold * (max - average));
1037 if (new_100 == new_0) {
1042 for (
const simple_score_map::value_type& entry : temp_scores) {
1043 const std::string& recruit = entry.first;
1044 double score = entry.second;
1049 double normalized_score = 100 * ((score - new_0) / (new_100 - new_0));
1050 if (normalized_score < 0) {
1051 normalized_score = 0;
1053 leader.scores[recruit] += normalized_score;
1064 double a_defense,
double b_defense) {
1065 double best_distance = 999;
1066 const double* best_value =
nullptr;
1067 const std::set<cached_combat_value>& cache =
combat_cache_[a][
b];
1069 double distance_a = std::abs(entry.a_defense - a_defense);
1070 double distance_b = std::abs(entry.b_defense - b_defense);
1071 if (distance_a <= COMBAT_CACHE_TOLERANCY && distance_b <= COMBAT_CACHE_TOLERANCY) {
1072 if(distance_a + distance_b <= best_distance) {
1073 best_distance = distance_a + distance_b;
1074 best_value = &entry.value;
1095 double attacker_defense,
double defender_defense,
1097 int average_lawful_bonus) :
1101 std::round(defender_defense), average_lawful_bonus),
1102 defender_stats(defender, def_weapon, false, attacker, att_weapon,
1103 std::round(attacker_defense), average_lawful_bonus),
1138 avg_hp = std::max(0., avg_hp);
1151 double attacker_defense,
double defender_defense,
1152 double* damage_to_attacker,
double* damage_to_defender)
const {
1153 if(!attacker || !defender || !damage_to_attacker || !damage_to_defender) {
1160 std::shared_ptr<attack_simulation> best_att_attack;
1163 for (
const attack_type& att_weapon : attacker_weapons) {
1164 std::shared_ptr<attack_simulation> best_def_response;
1166 for (
const attack_type& def_weapon : defender_weapons) {
1167 if (att_weapon.range() != def_weapon.range()) {
1170 auto simulation = std::make_shared<attack_simulation>(
1172 attacker_defense, defender_defense,
1174 if (!best_def_response || simulation->better_result(best_def_response.get(),
true)) {
1175 best_def_response = simulation;
1179 if (!best_def_response) {
1183 attacker_defense, defender_defense,
1186 if (!best_att_attack || best_def_response->better_result(best_att_attack.get(),
false)) {
1187 best_att_attack = best_def_response;
1191 if (!best_att_attack) {
1195 *damage_to_defender += (defender->
hitpoints() - best_att_attack->get_avg_hp_of_defender());
1196 *damage_to_attacker += (attacker->
hitpoints() - best_att_attack->get_avg_hp_of_attacker());
1204 config* most_important_job =
nullptr;
1205 int most_important_importance = -1;
1206 int biggest_number = -1;
1211 int importance = job[
"importance"].to_int(1);
1212 int number = job[
"number"].to_int(99999);
1213 bool total = job[
"total"].to_bool(
false);
1219 const std::string&
unit_type = entry.first;
1220 const int count = entry.second;
1222 number = number - count;
1229 if (importance > most_important_importance ||
1230 (importance == most_important_importance && biggest_number > number)) {
1231 most_important_job = &job;
1232 most_important_importance = importance;
1233 biggest_number = number;
1236 return most_important_job;
1245 const config* job)
const {
1246 std::string choosen_type;
1247 if (job->operator[](
"pattern").to_bool(
false)) {
1248 std::vector<std::string> job_types =
utils::split(job->operator[](
"type"));
1250 if (job_types.empty()) {
1254 std::back_inserter(job_types));
1263 while (job_types_it != job_types.end()) {
1264 bool type_ok =
false;
1265 for (
const std::string& recruit : leader_data.
recruits) {
1276 job_types_it = job_types.erase(job_types_it);
1280 if (!job_types.empty()) {
1285 return choosen_type;
1294 if (recruitment_pattern.empty()) {
1299 std::stringstream
s;
1300 for (std::vector<std::string>::const_iterator
type = recruitment_pattern.begin();
1301 type != recruitment_pattern.end(); ++
type) {
1303 if (
type != recruitment_pattern.end() - 1) {
1307 job[
"type"] =
s.str();
1308 job[
"number"] = 99999;
1309 job[
"pattern"] =
true;
1310 job[
"blocker"] =
true;
1311 job[
"total"] =
false;
1312 job[
"importance"] = 1;
1325 for (
const std::string& recruit : leader_data.
recruits) {
1335 std::vector<std::string> ids =
utils::split(job->operator[](
"leader_id"));
1340 return (std::find(ids.begin(), ids.end(), leader_data.
leader->id()) != ids.end());
1352 for (
const config& limit :
aspect.child_range(
"limit")) {
1353 std::vector<std::string> types =
utils::split(limit[
"type"]);
1359 const std::string&
unit = entry.first;
1360 int number = entry.second;
1366 if (count >= limit[
"max"].to_int(0)) {
1380 std::vector<std::string> job_types =
utils::split(job->operator[](
"type"));
1390 if (!recruit_type) {
1394 if (recruit_type->
id() ==
type) {
1402 std::stringstream
s;
1403 s << recruit_type->
level();
1404 if (
s.str() ==
type) {
1415 const std::vector<std::string>& types)
const {
1417 if (types.empty()) {
1420 for (
const std::string&
type : types) {
1433 if ((*job)[
"blocker"].to_bool(
true)) {
1451 const std::size_t own_villages =
team.
villages().size();
1455 double total_income = 0;
1456 for (
int i = 1;
i <= turns; ++
i) {
1460 double resulting_income =
team.
base_income() + income - std::max(0., upkeep);
1461 total_income += resulting_income;
1463 return total_income;
1480 int neutral_villages = 0;
1495 double own_total_value = 0.;
1496 double team_total_value = 0.;
1497 double enemy_total_value = 0.;
1505 enemy_total_value += value;
1507 team_total_value += value;
1509 own_total_value += value;
1513 int allies_count = 0;
1521 if ((own_total_value == 0. || team_total_value == 0) && enemy_total_value == 0.) {
1523 }
else if (enemy_total_value == 0.) {
1531 double own_ratio = (own_total_value / enemy_total_value) * allies_count;
1532 double team_ratio = team_total_value / enemy_total_value;
1533 return std::min<double>(own_ratio, team_ratio);
1546 if (spend_all_gold > 0 &&
current_team().gold() >= spend_all_gold) {
1552 double income_estimation = 1.;
1563 if (
state_ ==
NORMAL && ratio > save_gold_begin && income_estimation > 0) {
1581 for (score_map::value_type& entry :
data.
scores) {
1582 double& score = entry.second;
1607 typedef std::map<std::string, int> similarity_map;
1608 similarity_map similarities;
1609 for (
const score_map::value_type& entry :
data.
scores) {
1610 const std::string& recruit = entry.first;
1612 if (!recruit_type) {
1615 for (
const std::string& advanced_type : recruit_type->
advancement_tree()) {
1617 ++similarities[recruit];
1618 ++similarities[advanced_type];
1623 for (score_map::value_type& entry :
data.
scores) {
1624 const std::string& recruit = entry.first;
1625 double& score = entry.second;
1626 score /= (similarities[recruit] + 1);
1635 std::map<std::size_t, int>::const_iterator it =
cheapest_unit_costs_.find(leader->underlying_id());
1640 int cheapest_cost = 999999;
1643 for (
const std::string& recruit :
current_team().recruits()) {
1648 if (
info->cost() < cheapest_cost) {
1649 cheapest_cost =
info->cost();
1653 for (
const std::string& recruit : leader->recruits()) {
1658 if (
info->cost() < cheapest_cost) {
1659 cheapest_cost =
info->cost();
1668 return cheapest_cost;
1681 for (score_map::value_type& entry :
data.
scores) {
1682 const std::string& recruit = entry.first;
1683 double& score = entry.second;
1698 std::vector<map_location> surrounding;
1700 if (surrounding.empty()) {
1705 if(enemy_it == units.
end()) {
1708 if (!
current_team().is_enemy(enemy_it->side()) || enemy_it->incapacitated()) {
1744 int neutral_villages = 0;
1752 double our_share =
static_cast<double>(neutral_villages) /
resources::gameboard->teams().size();
1760 scouts_wanted_ = (villages_per_scout > 0) ? std::round(our_share / villages_per_scout) : 0;
1768 const std::string&
unit_type = entry.first;
1769 const int count = entry.second;
1780 : recruit_list_changed_(false), gamestate_changed_(0) {
1786 const std::string& event) {
1787 if (event ==
"ai_recruit_list_changed") {
1789 set_recruit_list_changed(
true);
1791 ++gamestate_changed_;
1801 return recruit_list_changed_;
1805 recruit_list_changed_ = changed;
1809 return gamestate_changed_;
1813 gamestate_changed_ = 0;
1822 parsed_cfg[
"pattern"] =
true;
1823 parsed_cfg.
add_child(
"recruit", std::move(pattern));
1826 parsed_cfg[
"total"] =
true;
1827 parsed_cfg.
add_child(
"recruit", std::move(total));
1841 std::function<void(std::vector<std::shared_ptr<recruit_job>>&,
const config&)> factory_jobs =
1843 std::function<void(std::vector<std::shared_ptr<recruit_limit>>&,
const config&)> factory_limits =
1851 for (
const std::shared_ptr<recruit_job>& job :
jobs_) {
1852 cfg.
add_child(
"recruit", job->to_config());
1854 for (
const std::shared_ptr<recruit_limit>& lim :
limits_) {
1855 cfg.
add_child(
"limit", lim->to_config());
1862 jobs.emplace_back(std::make_shared<recruit_job>(
1864 job[
"leader_id"], job[
"id"],
1865 job[
"number"].to_int(-1), job[
"importance"].to_int(1),
1866 job[
"total"].to_bool(
false),
1867 job[
"blocker"].to_bool(
true),
1868 job[
"pattern"].to_bool(
true)
1873 limits.emplace_back(std::make_shared<recruit_limit>(
1876 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.
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.
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, 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