38 namespace ai_default_rca
41 #define DBG_AI LOG_STREAM(debug, log_ai_testing_aspect_attacks)
42 #define LOG_AI LOG_STREAM(info, log_ai_testing_aspect_attacks)
43 #define ERR_AI LOG_STREAM(err, log_ai_testing_aspect_attacks)
81 auto res = std::make_shared<attacks_vector>();
84 std::vector<map_location> unit_locs;
85 for(
const unit& u : units_) {
91 unit_locs.push_back(u.get_location());
95 std::array<bool, 6> used_locations;
96 used_locations.fill(
false);
99 move_map fullmove_srcdst, fullmove_dstsrc;
104 for(
const unit& u : units_) {
107 if(
current_team().is_enemy(u.side()) && !u.incapacitated() && !u.invisible(u.get_location())) {
114 analysis.
target = u.get_location();
118 do_attack_analysis(u.get_location(), srcdst, dstsrc, fullmove_srcdst, fullmove_dstsrc, enemy_srcdst,
119 enemy_dstsrc, adjacent, used_locations, unit_locs, *res, analysis,
current_team());
132 const std::array<map_location, 6>& tiles,
133 std::array<bool, 6>& used_locations,
134 std::vector<map_location>& units,
135 std::vector<attack_analysis>& result,
137 const team& current_team)
const
142 const int max_attack_depth = 5;
143 if(cur_analysis.
movements.size() >= std::size_t(max_attack_depth)) {
151 const std::size_t max_positions = 1000;
152 if(result.size() > max_positions && !cur_analysis.
movements.empty()) {
153 LOG_AI <<
"cut analysis short with number of positions";
157 for(std::size_t
i = 0;
i != units.size(); ++
i) {
161 assert(unit_itor != units_.
end());
168 bool backstab =
false, slow =
false;
171 if(a.has_special(
"backstab",
true)) {
175 if(a.has_special(
"slow",
true)) {
180 if(slow && cur_analysis.
movements.empty() ==
false) {
189 bool is_surrounded =
false;
190 bool is_flanked =
false;
191 int enemy_units_around = 0;
192 int accessible_tiles = 0;
195 for(std::size_t tile = 0; tile != 3; ++tile) {
197 bool possible_flanked =
false;
202 ++enemy_units_around;
203 possible_flanked =
true;
211 ++enemy_units_around;
212 if(possible_flanked) {
219 if((is_flanked && enemy_units_around > 2) || enemy_units_around >= accessible_tiles - 1) {
220 is_surrounded =
true;
223 double best_vulnerability = 0.0, best_support = 0.0;
225 int cur_position = -1;
228 for(
unsigned j = 0; j < tiles.size(); ++j) {
230 if(used_locations[j]) {
235 if(tiles[j] != current_unit) {
236 auto its = dstsrc.equal_range(tiles[j]);
237 while(its.first != its.second) {
238 if(its.first->second == current_unit) {
246 if(its.first == its.second || units_.
find(tiles[j]) != units_.
end()) {
252 double leadership_bonus =
static_cast<double>(best_leadership_bonus + 100) / 100.0;
253 if(leadership_bonus > 1.1) {
254 LOG_AI << unit_itor->name() <<
" is getting leadership " << leadership_bonus;
258 int backstab_bonus = 1;
259 double surround_bonus = 1.0;
261 if(tiles[(j + 3) % 6] != current_unit) {
277 if(!itor->get_ability_bool(
"skirmisher")) {
278 surround_bonus = 1.2;
284 int rating =
static_cast<int>(
rate_terrain(*unit_itor, tiles[j]) * backstab_bonus * leadership_bonus);
285 if(cur_position >= 0 && rating < best_rating) {
298 if(cur_position >= 0 && rating == best_rating
299 && vulnerability / surround_bonus - support * surround_bonus >= best_vulnerability - best_support) {
304 best_rating = rating;
305 best_vulnerability = vulnerability / surround_bonus;
306 best_support = support * surround_bonus;
309 if(cur_position != -1) {
310 units.erase(units.begin() +
i);
312 cur_analysis.
movements.emplace_back(current_unit, tiles[cur_position]);
314 cur_analysis.
support += best_support;
317 result.push_back(cur_analysis);
319 used_locations[cur_position] =
true;
321 do_attack_analysis(loc, srcdst, dstsrc, fullmove_srcdst, fullmove_dstsrc, enemy_srcdst, enemy_dstsrc, tiles,
322 used_locations, units, result, cur_analysis,
current_team);
324 used_locations[cur_position] =
false;
327 cur_analysis.
support -= best_support;
330 units.insert(units.begin() +
i, current_unit);
340 int rating = 100 - defense;
342 const int healing_value = 10;
343 const int friendly_village_value = 5;
344 const int neutral_village_value = 10;
345 const int enemy_village_value = 15;
348 rating += healing_value;
354 if(owner == u.
side()) {
355 rating += friendly_village_value;
356 }
else if(owner == 0) {
357 rating += neutral_village_value;
359 rating += enemy_village_value;
410 readonly_context& context,
const config& cfg,
const std::string&
id, std::shared_ptr<lua_ai_context>& l_ctx)
411 : aspect_attacks_base(context, cfg,
id)
414 , params_(cfg.child_or_empty(
"args"))
416 this->
name_ =
"lua_aspect";
418 code_ = cfg[
"code"].str();
436 aspect_attacks_base::recalculate();
440 luaL_unref(filt.
lua, LUA_REGISTRYINDEX, filt.
ref_own_);
463 lua_rawgeti(L, LUA_REGISTRYINDEX, idx);
int under_leadership(const unit &u, const map_location &loc, const_attack_ptr weapon, const_attack_ptr opp_weapon)
Tests if the unit at loc is currently affected by leadership.
bool backstab_check(const map_location &attacker_loc, const map_location &defender_loc, const unit_map &units, const std::vector< team > &teams)
Function to check if an attack will satisfy the requirements for backstab.
Various functions that implement attacks and attack calculations.
Managing the AIs lifecycle - headers TODO: Refactor history handling and internal commands.
std::shared_ptr< attacks_vector > analyze_targets() const
virtual void recalculate() const
virtual bool is_allowed_enemy(const unit &u) const =0
void do_attack_analysis(const map_location &loc, const move_map &srcdst, const move_map &dstsrc, const move_map &fullmove_srcdst, const move_map &fullmove_dstsrc, const move_map &enemy_srcdst, const move_map &enemy_dstsrc, const std::array< map_location, 6 > &tiles, std::array< bool, 6 > &used_locations, std::vector< map_location > &units, std::vector< attack_analysis > &result, attack_analysis &cur_analysis, const team ¤t_team) const
aspect_attacks_base(readonly_context &context, const config &cfg, const std::string &id)
static int rate_terrain(const unit &u, const map_location &loc)
virtual bool is_allowed_attacker(const unit &u) const =0
std::shared_ptr< unit_filter > filter_own_
virtual bool is_allowed_attacker(const unit &u) const
virtual bool is_allowed_enemy(const unit &u) const
std::shared_ptr< unit_filter > filter_enemy_
aspect_attacks(readonly_context &context, const config &cfg, const std::string &id)
virtual config to_config() const
virtual config to_config() const
virtual bool is_allowed_enemy(const unit &u) const
std::shared_ptr< lua_object< aspect_attacks_lua_filter > > obj_
virtual bool is_allowed_attacker(const unit &u) const
virtual void recalculate() const
aspect_attacks_lua(readonly_context &context, const config &cfg, const std::string &id, std::shared_ptr< lua_ai_context > &l_ctx)
std::shared_ptr< lua_ai_action_handler > handler_
virtual config to_config() const
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)
double vulnerability
The vulnerability is the power projection of enemy units onto the hex we're standing on.
bool is_surrounded
Is true if the units involved in this attack sequence are surrounded.
void raise_user_interact()
Notifies all observers of 'ai_user_interact' event.
static manager & get_singleton()
virtual const team & current_team() const override
virtual const move_map & get_enemy_srcdst() const override
virtual const move_map & get_dstsrc() const override
virtual const move_map & get_srcdst() const override
virtual void calculate_possible_moves(std::map< map_location, pathfind::paths > &possible_moves, move_map &srcdst, move_map &dstsrc, bool enemy, bool assume_full_movement=false, const terrain_filter *remove_destinations=nullptr) const override
virtual bool is_passive_leader(const std::string &id) const 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 unit_stats_cache_t & unit_stats_cache() const override
virtual double get_aggression() 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< attacks_vector > value_
A config object defines a single node in a WML file, with access to child nodes.
bool has_attribute(config_key_type key) const
optional_config_impl< config > optional_child(config_key_type key, int n=0)
Equivalent to mandatory_child, but returns an empty optional if the nth child was not found.
config & add_child(config_key_type key)
int village_owner(const map_location &loc) const
Given the location of a village, will return the 1-based number of the team that currently owns it,...
virtual const std::vector< team > & teams() const override
virtual const unit_map & units() const override
virtual const gamemap & map() const override
terrain_code get_terrain(const map_location &loc) const
Looks up terrain at a particular location.
bool on_board(const map_location &loc) const
Tell if a location is on the map.
Encapsulates the map of the game.
bool is_village(const map_location &loc) const
int gives_healing(const map_location &loc) const
This class stores all the data for a single 'side' (in game nomenclature).
bool is_enemy(int n) const
Container associating units to locations.
unit_iterator find(std::size_t id)
This class represents a single unit of a specific type.
A variable-expanding proxy for the config class.
const vconfig & make_safe() const
instruct the vconfig to make a private copy of its underlying data.
bool get_ability_bool(const std::string &tag_name, const map_location &loc) const
Checks whether this unit currently possesses or is affected by a given ability.
int side() const
The side this unit belongs to.
std::size_t underlying_id() const
This unit's unique internal ID.
int defense_modifier(const t_translation::terrain_code &terrain) const
The unit's defense on a given terrain.
std::string id
Text to match against addon_info.tags()
void get_adjacent_tiles(const map_location &a, map_location *res)
Function which, given a location, will place all adjacent locations in res.
Standard logging facilities (interface).
bool luaW_toboolean(lua_State *L, int n)
bool luaW_pcall(lua_State *L, int nArgs, int nRets, bool allow_wml_error)
Calls a Lua function stored below its nArgs arguments at the top of the stack.
lua_unit * luaW_pushunit(lua_State *L, Args... args)
static lg::log_domain log_ai_testing_aspect_attacks("ai/aspect/attacks")
A small explanation about what's going on here: Each action has access to two game_info objects First...
std::vector< attack_analysis > attacks_vector
std::multimap< map_location, map_location > move_map
The standard way in which a map of possible moves is recorded.
static bool call_lua_filter_fcn(lua_State *L, const unit &u, int idx)
std::map< map_location, pathfind::paths > moves_map
The standard way in which a map of possible movement routes to location is recorded.
static std::unique_ptr< class sdl_event_handler > handler_
game_lua_kernel * lua_kernel
This module contains various pathfinding functions and utilities.
std::shared_ptr< unit_filter > filter_own_
std::shared_ptr< unit_filter > filter_enemy_
Encapsulates the map of the game.
A terrain string which is converted to a terrain is a string with 1 or 2 layers the layers are separa...