34 #include "formula/callable_objects.hpp"
39 #define LOG_AI LOG_STREAM(info, log_ai)
40 #define ERR_AI LOG_STREAM(err, log_ai)
49 const move_map& enemy_dstsrc,
double aggression)
52 assert(defend_it != units.
end());
57 for(tile = 0; tile < adj.size(); ++tile) {
68 target_value += (
static_cast<double>(defend_it->experience())/
69 static_cast<double>(defend_it->max_experience()))*
target_value;
71 defend_it->hitpoints();
78 double cost_sum = 0.0;
81 const double cost = att->cost();
94 double def_avg_experience = 0.0;
95 double first_chance_kill = 0.0;
97 double prob_dead_already = 0.0;
99 std::vector<std::pair<map_location,map_location>>::const_iterator m;
101 std::unique_ptr<battle_context> bc(
nullptr);
102 std::unique_ptr<battle_context> old_bc(
nullptr);
109 up->set_location(m->second);
111 double m_aggression = aggression;
113 if (up->can_recruit()) {
120 bool from_cache =
false;
129 const readonly_context::unit_stats_cache_t::key_type cache_key = std::pair(
target, &up->
type());
133 usc->second.first.attack_num <
134 static_cast<int>(up->attacks().size())) {
137 bc.reset(
new battle_context(usc->second.first, usc->second.second));
141 const combatant &att = bc->get_attacker_combatant(prev_def);
142 const combatant &def = bc->get_defender_combatant(prev_def);
144 prev_def = &bc->get_defender_combatant(prev_def);
147 old_bc.reset(
nullptr);
151 bc->get_attacker_stats(),
152 bc->get_defender_stats()
157 double prob_fought = (1.0 - prob_dead_already);
159 double prob_killed = def.
hp_dist[0] - prob_dead_already;
160 prob_dead_already = def.
hp_dist[0];
162 double prob_died = att.
hp_dist[0];
163 double prob_survived = (1.0 - prob_died) * prob_fought;
165 double cost = up->cost();
166 const bool on_village = map.
is_village(m->second);
168 cost += (
static_cast<double>(up->experience()) / up->max_experience())*cost;
175 if (!bc->get_defender_stats().is_poisoned) {
184 terrain_quality += (
static_cast<double>(bc->get_defender_stats().chance_to_hit)/100.0)*cost * (on_village ? 0.5 : 1.0);
186 double advance_prob = 0.0;
188 if (!up->advances_to().empty()) {
189 int xp_for_advance = up->experience_to_advance();
193 if (xp_for_advance == 0)
199 if (fight_xp >= xp_for_advance) {
200 advance_prob = prob_fought;
202 }
else if (
kill_xp >= xp_for_advance) {
203 advance_prob = prob_killed;
212 fight_xp * (prob_fought - prob_killed)
216 (
kill_xp * prob_killed + fight_xp * (prob_fought - prob_killed))
222 if (bc->get_attacker_stats().plagues) {
234 first_chance_kill = def.
hp_dist[0];
238 if (!defend_it->advances_to().empty() &&
239 def_avg_experience >= defend_it->experience_to_advance()) {
253 units.
move(m->second, m->first);
260 for(std::set<map_location>::const_iterator
i = attacks.begin();
i != attacks.end(); ++
i) {
290 LOG_AI <<
"attack option has base value " << value <<
" with exposure " << exposure <<
": "
292 value -= exposure*(1.0-aggression);
338 if(key ==
"target") {
340 }
else if(key ==
"movements") {
341 std::vector<variant> res;
343 auto item = std::make_shared<map_formula_callable>(
nullptr);
346 res.emplace_back(
item);
350 }
else if(key ==
"units") {
351 std::vector<variant> res;
353 res.emplace_back(std::make_shared<location_callable>(
movements[
n].first));
357 }
else if(key ==
"target_value") {
359 }
else if(key ==
"avg_losses") {
361 }
else if(key ==
"chance_to_kill") {
363 }
else if(key ==
"avg_damage_inflicted") {
365 }
else if(key ==
"target_starting_damage") {
367 }
else if(key ==
"avg_damage_taken") {
369 }
else if(key ==
"resources_used") {
371 }
else if(key ==
"terrain_quality") {
373 }
else if(key ==
"alternative_terrain_quality") {
375 }
else if(key ==
"vulnerability") {
377 }
else if(key ==
"support") {
379 }
else if(key ==
"leader_threat") {
381 }
else if(key ==
"uses_leader") {
383 }
else if(key ==
"is_surrounded") {
437 if(move_from != att_src) {
445 if(!result->is_ok()) {
447 LOG_AI <<
"ERROR #" << result->get_status() <<
" while executing 'attack' formula function";
448 return wfl::variant(std::make_shared<wfl::safe_call_result>(
fake_ptr(), result->get_status(), result->get_unit_location()));
452 if(units.
count(att_src)) {
454 if(!result->is_ok()) {
456 LOG_AI <<
"ERROR #" << result->get_status() <<
" while executing 'attack' formula function";
Various functions that implement attacks and attack calculations.
Managing the AI-Game interaction - AI actions and their results.
static lg::log_domain log_ai("ai/attack")
Managing the AIs lifecycle - headers TODO: Refactor history handling and internal commands.
std::vector< std::pair< map_location, map_location > > movements
void analyze(const gamemap &map, unit_map &units, const readonly_context &ai_obj, const move_map &dstsrc, const move_map &srcdst, const move_map &enemy_dstsrc, double aggression)
bool uses_leader
Is true if this attack sequence makes use of the leader.
wfl::variant get_value(const std::string &key) const override
void get_inputs(wfl::formula_input_vector &inputs) const override
double target_value
The value of the unit being targeted.
double avg_damage_inflicted
The average hitpoints damage inflicted.
double chance_to_kill
Estimated % chance to kill the unit.
bool attack_close(const map_location &loc) const
wfl::variant execute_self(wfl::variant ctxt) override
double terrain_quality
The weighted average of the % chance to hit each attacking unit.
double avg_damage_taken
The average hitpoints damage taken.
double alternative_terrain_quality
The weighted average of the % defense of the best possible terrain that the attacking units could rea...
bool leader_threat
Is true if the unit is a threat to our leader.
double avg_losses
The value on average, of units lost in the combat.
double vulnerability
The vulnerability is the power projection of enemy units onto the hex we're standing on.
double resources_used
The sum of the values of units used in the attack.
double rating(double aggression, const readonly_context &ai_obj) const
int target_starting_damage
bool is_surrounded
Is true if the units involved in this attack sequence are surrounded.
std::set< map_location > recent_attacks
static manager & get_singleton()
game_info & get_ai_info()
Gets global AI-game info.
virtual const defensive_position & best_defensive_position(const map_location &unit, const move_map &dstsrc, const move_map &srcdst, const move_map &enemy_dstsrc) const =0
virtual unit_stats_cache_t & unit_stats_cache() const =0
virtual const team & current_team() const =0
virtual double get_caution() const =0
virtual double get_leader_aggression() const =0
virtual attack_result_ptr execute_attack_action(const map_location &attacker_loc, const map_location &defender_loc, int attacker_weapon)=0
virtual move_result_ptr execute_move_action(const map_location &from, const map_location &to, bool remove_movement=true, bool unreach_is_ok=false)=0
Computes the statistics of a battle between an attacker and a defender unit.
virtual const unit_map & units() const override
Encapsulates the map of the game.
bool is_village(const map_location &loc) const
int gives_healing(const map_location &loc) const
bool is_enemy(int n) const
Container associating units to locations.
unit_ptr extract(const map_location &loc)
Extracts a unit from the map.
std::size_t count(const map_location &loc) const
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.
umap_retval_pair_t move(const map_location &src, const map_location &dst)
Moves a unit from location src to location dst.
This class represents a single unit of a specific type.
const_formula_callable_ptr as_callable() const
@ STATE_POISONED
The unit is slowed - it moves slower and does less damage.
int attacks_left() const
Gets the remaining number of attacks this unit can perform this turn.
void get_adjacent_tiles(const map_location &a, map_location *res)
Function which, given a location, will place all adjacent locations in res.
std::size_t distance_between(const map_location &a, const map_location &b)
Function which gives the number of hexes between two tiles (i.e.
Standard logging facilities (interface).
A small explanation about what's going on here: Each action has access to two game_info objects First...
ai_context & get_ai_context(wfl::const_formula_callable_ptr for_fai)
std::shared_ptr< attack_result > attack_result_ptr
std::multimap< map_location, map_location > move_map
The standard way in which a map of possible moves is recorded.
std::shared_ptr< move_result > move_result_ptr
std::pair< std::string, unsigned > item
std::string::const_iterator iterator
std::vector< formula_input > formula_input_vector
std::shared_ptr< const formula_callable > const_formula_callable_ptr
std::shared_ptr< unit > unit_ptr
std::vector< double > hp_dist
Resulting probability distribution (might be not as large as max_hp)
double average_hp(unsigned int healing=0) const
What's the average hp (weighted average of hp_dist).
Encapsulates the map of the game.
static map_location::DIRECTION n