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.";
257 data.
scores[recruit] = 0.0;
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.";
268 data.
scores[recruit] = 0.0;
269 global_recruits.insert(recruit);
282 if (recall_value < 0) {
285 data.
recruits.insert(recall->type_id());
286 data.
scores[recall->type_id()] = 0.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()) {
409 if (action_result->is_ok()) {
417 if (!job->operator[](
"total").to_bool(
false)) {
418 job->operator[](
"number") = job->operator[](
"number").to_int(99999) - 1;
440 }
while((action_result && action_result->is_ok()) || !action_result);
450 int status = (action_result) ? action_result->get_status() : -1;
455 if (job && no_gold) {
466 leader_data.
leader->get_location());
467 if (recall_result->is_ok()) {
468 recall_result->execute();
471 return recall_result;
480 leader_data.
leader->get_location());
482 if (recruit_result->is_ok()) {
483 recruit_result->execute();
487 return recruit_result;
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()) /
516 recall_unit->max_experience();
517 double recall_value = recall_unit->cost() + xp_quantity * average_cost_of_advanced_unit;
519 if (recall_unit->recall_cost() > -1) {
520 cost=recall_unit->recall_cost();
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);
737 for (
const std::string& recruit : team.
recruits()) {
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) {
795 for (
const std::string& recruit : team.
recruits()) {
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;
980 const std::vector<unit_map::const_iterator> leaders = units.find_leaders(
team.
side());
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) :
1099 attacker_type(attacker),
1100 defender_type(defender),
1101 attacker_stats(attacker, att_weapon, true, defender, def_weapon,
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),
1105 attacker_combatant(attacker_stats),
1106 defender_combatant(defender_stats)
1108 attacker_combatant.
fight(defender_combatant);
1115 defender_combatant, attacker_combatant,
1119 attacker_combatant, defender_combatant,
1125 return get_avg_hp_of_combatant(
false);
1129 return get_avg_hp_of_combatant(
true);
1139 avg_hp = std::max(0., avg_hp);
1140 avg_hp = std::min(static_cast<double>(unit_type->
hitpoints()), 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());
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;
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;
1680 for (
const std::string&
type : aspect) {
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()) {
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") {
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));
1832 if (!parsed_cfg.has_child(
"recruit")) {
1833 parsed_cfg.add_child(
"recruit",
config {
"importance", 0});
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)
std::shared_ptr< action_result > action_result_ptr
int defense_modifier(const t_translation::terrain_code &terrain) const
Returns the defensive value of the indicated terrain.
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_avg_hp_of_combatant(bool attacker) const
config & child(config_key_type key, int n=0)
Returns the nth child with the given key, or a reference to an invalid config if there is none...
::tod_manager * tod_manager
virtual int get_villages_per_scout() const override
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)
count_map own_units_count_
std::vector< unit_iterator > find_leaders(int side)
double get_average_defense(const std::string &unit_type) const
For Map Analysis.
static display * get_singleton()
Returns the display object if a display object exists.
void reset_gamestate_changed()
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.
bool recruit_list_changed_
virtual const unit_map & units() const override
double get_avg_hp_of_defender() const
void clear_children(T... keys)
void update_average_local_cost()
For Map Analysis.
This class represents a single unit of a specific type.
const std::string & type_id() const
The id of this unit's type.
double get_estimated_unit_gain() const
For Aspect "recruitment_save_gold".
bool remove_job_if_no_blocker(config *job)
For Configuration / Aspect "recruitment-instructions".
terrain_count_map important_terrain_
map_location find_vacant_castle(const unit &leader)
Wrapper for find_vacant_tile() when looking for a vacant castle tile near a leader.
bool better_result(const attack_simulation *other, bool for_defender)
static manager & get_singleton()
virtual void execute()
Execute the candidate action.
#define ERR_AI_RECRUITMENT
Various functions that implement attacks and attack calculations.
virtual const config get_recruitment_save_gold() const override
#define LOG_AI_RECRUITMENT
static bool better_combat(const combatant &us_a, const combatant &them_a, const combatant &us_b, const combatant &them_b, double harm_weight)
void create_job(std::vector< std::shared_ptr< recruit_job >> &jobs, const config &job)
int cost(const t_translation::terrain_code &terrain, bool slowed=false) const
Returns the cost associated with the given terrain.
Managing the AI-Game interaction - AI actions and their results.
int hitpoints() const
The current number of hitpoints this unit has.
bool has_child(config_key_type key) const
Determine whether a config has a child or not.
virtual int get_recruitment_randomness() const override
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...
property_handler_map & property_handlers()
void create_limit(std::vector< std::shared_ptr< recruit_limit >> &limits, const config &lim)
child_itors child_range(config_key_type key)
double get_random_double()
This helper method returns a floating-point number in the range [0,1[.
std::map< map_location, double > average_local_cost_
double average_hp(unsigned int healing=0) const
What's the average hp (weighted average of hp_dist).
void update_important_hexes()
For Map Analysis.
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.
virtual const gamemap & map() const override
std::vector< std::shared_ptr< recruit_job > > jobs_
A terrain string which is converted to a terrain is a string with 1 or 2 layers the layers are separa...
unit_type_data unit_types
void update_scouts_wanted()
This function will use the aspect villages_per_scout to decide how many scouts we want to recruit...
std::set< std::string > advancement_tree() const
Get the advancement tree.
const std::string * get_appropriate_recall(const std::string &type, const data &leader_data) const
std::shared_ptr< recruit_result > recruit_result_ptr
void update_own_units_count()
int get_cheapest_unit_cost_for_leader(const unit_map::const_iterator &leader)
Called at the beginning and whenever the recruitment list changes.
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)
std::shared_ptr< config > value_
const std::string get_best_recruit_from_scores(const data &leader_data, const config *job)
A helper function for execute().
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...
recruit_situation_change_observer recruit_situation_change_observer_
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)
int cost() const
How much gold is required to recruit this unit.
A single unit type that the player may recruit.
void do_similarity_penalty(std::vector< data > *leader_data) const
Will give a penalty to similar units.
std::set< map_location > important_hexes_
double compare_unit_types(const std::string &a, const std::string &b)
For Combat Analysis.
void show_important_hexes() const
For Map Analysis.
double get_average_cost_at(map_location loc) const
Accessor for the costs.
const battle_context_unit_stats attacker_stats
virtual const std::vector< std::string > get_recruitment_more() const override
int average_lawful_bonus_
void handle_generic_event(const std::string &event)
double get_estimated_income(int turns) const
For Aspect "recruitment_save_gold".
combatant defender_combatant
std::shared_ptr< const unit > unit_const_ptr
Object which defines a time of day with associated bonuses, image, sounds etc.
double get_unit_ratio() const
For Aspect "recruitment_save_gold".
This class stores all the data for a single 'side' (in game nomenclature).
A small explanation about what's going on here: Each action has access to two game_info objects First...
void remove_gamestate_observer(events::observer *event_observer)
Removes an observer of game events except ai_user_interact event and ai_sync_network event...
std::shared_ptr< recall_result > recall_result_ptr
void update_average_lawful_bonus()
Calculates a average lawful bonus, so Combat Analysis will work better in caves and custom time of da...
int w() const
Effective map width.
const movetype & movement_type() const
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="")
void handle_recruitment_more(std::vector< data > *leader_data) const
For Aspect "recruitment_more".
void for_each_walkable_loc(const F &f) const
cache_table combat_cache_
const terrain_costs & get_movement() const
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
bool is_allowed_unit(const unit &u) const
Flag indicating whether unit may be used by this candidate action.
void integrate_recruitment_pattern_in_recruitment_instructions()
For Configuration / Aspect "recruitment_pattern" Converts the (old) recruitment_pattern into a recrui...
const std::string & usage() const
int side_upkeep(int side_num) const
const pathfind::full_cost_map get_cost_map_of_side(int side) const
For Map Analysis.
virtual double get_recruitment_diversity() const override
config * get_most_important_job()
For Configuration / Aspect "recruitment-instructions" We call a [recruit] tag a "job".
Encapsulates the map of the game.
score_map get_normalized_scores() const
bool limit_ok(const std::string &recruit) const
For Configuration / Aspect "recruitment-instructions" Checks if a recruit-type can be recruited accor...
bool is_enemy(int n) const
void fight(combatant &opponent, bool levelup_considered=true)
Simulate a fight! Can be called multiple times for cumulative calculations.
virtual const move_map & get_enemy_dstsrc() const override
const std::string & id() const
The id for this unit_type.
Managing the AIs lifecycle - headers TODO: Refactor history handling and internal commands...
map_display and display: classes which take care of displaying the map and game-data on the screen...
virtual const std::vector< std::string > get_recruitment_pattern() const override
Structure describing the statistics of a unit involved in the battle.
Recruitment Engine by flix See https://wiki.wesnoth.org/AI_Recruitment.
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...
double get_estimated_village_gain() const
For Aspect "recruitment_save_gold".
void do_combat_analysis(std::vector< data > *leader_data)
Combat Analysis.
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
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.
double recall_unit_value(const unit_const_ptr &recall_unit) const
A helper function for execute().
const unit_type * attacker_type
action_result_ptr execute_recall(const std::string &id, data &leader_data)
A helper function for execute().
Encapsulates the map of the game.
std::string to_string() const
unit_iterator find(std::size_t id)
~recruit_situation_change_observer()
data * get_best_leader_from_ratio_scores(std::vector< data > &leader_data, const config *job) const
A helper function for execute().
virtual const team & current_team() const override
int max_hitpoints() const
The max number of hitpoints this unit can have.
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...
combatant attacker_combatant
virtual config to_config() const
serialize
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...
static map_location::DIRECTION s
Structure which uses find_routes() to build a cost map This maps each hex to a the movements a unit w...
bool can_recruit() const
Whether this unit can recruit other units - ie, are they a leader unit.
bool is_enemy_in_radius(const map_location &loc, int radius) const
Helper function.
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.
action_result_ptr execute_recruit(const std::string &type, data &leader_data)
A helper function for execute().
void add_recruit_list_changed_observer(events::observer *event_observer)
Adds an observer of 'ai_recruit_list_changed' event.
virtual side_number get_side() const override
Get the side number.
bool on_board(const map_location &loc) const
Tell if a location is on the map.
std::vector< std::shared_ptr< recruit_limit > > limits_
int get_random_int(int min, int max)
This helper method provides a random int from the underlying generator, using results of next_random...
bool recruit_list_changed()
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 ...
void set_recruit_list_changed(bool changed)
rng * generator
This generator is automatically synced during synced context.
config & add_child(config_key_type key)
double get_avg_hp_of_attacker() const
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...
const unit_type * defender_type
std::vector< std::string > split(const config_attribute_value &val)
config recruitment_instructions_
recruitment(rca_context &context, const config &cfg)
const std::vector< map_location > & villages() const
Return a list of the locations of villages on the map.
const map_location & get_location() const
The current map location this unit is at.
void add_gamestate_observer(events::observer *event_observer)
Adds observer of game events except ai_user_interact event and ai_sync_network event.
A variable-expanding proxy for the config class.
static lg::log_domain log_ai_recruitment("ai/recruitment")
Standard logging facilities (interface).
static const map_location & null_location()
recruitment_aspect(readonly_context &context, const config &cfg, const std::string &id)
virtual const config get_recruitment_instructions() const override
static const double BAD_SCORE
Container associating units to locations.
bool incapacitated() const
Check if the unit has been petrified.
int total_movement() const
The maximum moves this unit has.
config to_config() const
serialize
static lg::log_domain log_wml("wml")
retval
Default window/dialog return values.
int side() const
The side this unit belongs to.
std::vector< game_tip > shuffle(const std::vector< game_tip > &tips)
Shuffles the tips.
unit_map::const_iterator leader
const_attack_itors attacks() const
boost::iterator_range< boost::indirect_iterator< attack_list::const_iterator > > const_attack_itors
recruit_situation_change_observer()
Observer Code.
A config object defines a single node in a WML file, with access to child nodes.
virtual double evaluate()
Evaluate the candidate action, resetting the internal state of the action.
void do_randomness(std::vector< data > *leader_data) const
Will add a random value between 0 and "recruitment_randomness" to all recruits.
std::shared_ptr< const attack_type > const_attack_ptr
void update_state()
For Aspect "recruitment_save_gold".
int recruitment_instructions_turn_
double get_score() const
Get the usual score of the candidate action without re-evaluation.
int h() const
Effective map height.
const std::set< map_location > & villages() const
This module contains various pathfinding functions and utilities.
static rng & default_instance()
const battle_context_unit_stats defender_stats
void remove_recruit_list_changed_observer(events::observer *event_observer)
Deletes an observer of 'ai_recruit_list_changed' event.
std::string::const_iterator iterator
std::set< std::string > recruits
double poisoned
Resulting chance we are poisoned.
int own_units_in_combat_counter_
const std::set< std::string > & recruits() const
std::stringstream & log_to_chat()
Use this to show WML errors in the ingame chat.
candidate action framework
int get_cost_at(map_location loc) const
Accessor for the costs.
std::map< std::size_t, int > cheapest_unit_costs_