33 #include "formula/callable_objects.hpp"
38 #define LOG_AI LOG_STREAM(info, log_ai)
39 #define ERR_AI LOG_STREAM(err, log_ai)
48 const move_map& enemy_dstsrc,
double aggression)
51 assert(defend_it != units.
end());
56 for(tile = 0; tile < adj.size(); ++tile) {
67 target_value += (
static_cast<double>(defend_it->experience())/
68 static_cast<double>(defend_it->max_experience()))*
target_value;
70 defend_it->hitpoints();
77 double cost_sum = 0.0;
80 const double cost = att->cost();
93 double def_avg_experience = 0.0;
94 double first_chance_kill = 0.0;
96 double prob_dead_already = 0.0;
98 std::vector<std::pair<map_location,map_location>>::const_iterator m;
100 std::unique_ptr<battle_context> bc(
nullptr);
101 std::unique_ptr<battle_context> old_bc(
nullptr);
108 up->set_location(m->second);
110 double m_aggression = aggression;
112 if (up->can_recruit()) {
119 bool from_cache =
false;
128 const readonly_context::unit_stats_cache_t::key_type cache_key = std::pair(
target, &up->
type());
132 usc->second.first.attack_num <
133 static_cast<int>(up->attacks().size())) {
136 bc.reset(
new battle_context(usc->second.first, usc->second.second));
140 const combatant &att = bc->get_attacker_combatant(prev_def);
141 const combatant &def = bc->get_defender_combatant(prev_def);
143 prev_def = &bc->get_defender_combatant(prev_def);
146 old_bc.reset(
nullptr);
150 bc->get_attacker_stats(),
151 bc->get_defender_stats()
156 double prob_fought = (1.0 - prob_dead_already);
158 double prob_killed = def.
hp_dist[0] - prob_dead_already;
159 prob_dead_already = def.
hp_dist[0];
161 double prob_died = att.
hp_dist[0];
162 double prob_survived = (1.0 - prob_died) * prob_fought;
164 double cost = up->cost();
165 const bool on_village = map.
is_village(m->second);
167 cost += (
static_cast<double>(up->experience()) / up->max_experience())*cost;
174 if (!bc->get_defender_stats().is_poisoned) {
183 terrain_quality += (
static_cast<double>(bc->get_defender_stats().chance_to_hit)/100.0)*cost * (on_village ? 0.5 : 1.0);
185 double advance_prob = 0.0;
187 if (!up->advances_to().empty()) {
188 int xp_for_advance = up->experience_to_advance();
192 if (xp_for_advance == 0)
198 if (fight_xp >= xp_for_advance) {
199 advance_prob = prob_fought;
201 }
else if (
kill_xp >= xp_for_advance) {
202 advance_prob = prob_killed;
211 fight_xp * (prob_fought - prob_killed)
215 (
kill_xp * prob_killed + fight_xp * (prob_fought - prob_killed))
221 if (bc->get_attacker_stats().plagues) {
233 first_chance_kill = def.
hp_dist[0];
237 if (!defend_it->advances_to().empty() &&
238 def_avg_experience >= defend_it->experience_to_advance()) {
252 units.
move(m->second, m->first);
259 for(std::set<map_location>::const_iterator
i = attacks.begin();
i != attacks.end(); ++
i) {
289 LOG_AI <<
"attack option has base value " << value <<
" with exposure " << exposure <<
": "
291 value -= exposure*(1.0-aggression);
337 if(key ==
"target") {
339 }
else if(key ==
"movements") {
340 std::vector<variant> res;
342 auto item = std::make_shared<map_formula_callable>(
nullptr);
343 item->add(
"src",
variant(std::make_shared<location_callable>(
movements[
n].first)));
344 item->add(
"dst",
variant(std::make_shared<location_callable>(
movements[
n].second)));
345 res.emplace_back(item);
349 }
else if(key ==
"units") {
350 std::vector<variant> res;
352 res.emplace_back(std::make_shared<location_callable>(
movements[
n].first));
356 }
else if(key ==
"target_value") {
358 }
else if(key ==
"avg_losses") {
360 }
else if(key ==
"chance_to_kill") {
362 }
else if(key ==
"avg_damage_inflicted") {
364 }
else if(key ==
"target_starting_damage") {
366 }
else if(key ==
"avg_damage_taken") {
368 }
else if(key ==
"resources_used") {
370 }
else if(key ==
"terrain_quality") {
372 }
else if(key ==
"alternative_terrain_quality") {
374 }
else if(key ==
"vulnerability") {
376 }
else if(key ==
"support") {
378 }
else if(key ==
"leader_threat") {
380 }
else if(key ==
"uses_leader") {
382 }
else if(key ==
"is_surrounded") {
436 if(move_from != att_src) {
444 if(!result->is_ok()) {
446 LOG_AI <<
"ERROR #" << result->get_status() <<
" while executing 'attack' formula function";
447 return wfl::variant(std::make_shared<wfl::safe_call_result>(
fake_ptr(), result->get_status(), result->get_unit_location()));
451 if(units.
count(att_src)) {
453 if(!result->is_ok()) {
455 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::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