39 namespace ai_default_rca
42 #define DBG_AI LOG_STREAM(debug, log_ai_testing_aspect_attacks)
43 #define LOG_AI LOG_STREAM(info, log_ai_testing_aspect_attacks)
44 #define ERR_AI LOG_STREAM(err, log_ai_testing_aspect_attacks)
82 auto res = std::make_shared<attacks_vector>();
85 std::vector<map_location> unit_locs;
86 for(
const unit& u : units_) {
92 unit_locs.push_back(u.get_location());
96 std::array<bool, 6> used_locations;
97 used_locations.fill(
false);
100 move_map fullmove_srcdst, fullmove_dstsrc;
105 for(
const unit& u : units_) {
108 if(
current_team().is_enemy(u.side()) && !u.incapacitated() && !u.invisible(u.get_location())) {
115 analysis.
target = u.get_location();
119 do_attack_analysis(u.get_location(), srcdst, dstsrc, fullmove_srcdst, fullmove_dstsrc, enemy_srcdst,
120 enemy_dstsrc, adjacent, used_locations, unit_locs, *res, analysis,
current_team());
133 const std::array<map_location, 6>& tiles,
134 std::array<bool, 6>& used_locations,
135 std::vector<map_location>& units,
136 std::vector<attack_analysis>& result,
138 const team& current_team)
const
143 const int max_attack_depth = 5;
144 if(cur_analysis.
movements.size() >= std::size_t(max_attack_depth)) {
152 const std::size_t max_positions = 1000;
153 if(result.size() > max_positions && !cur_analysis.
movements.empty()) {
154 LOG_AI <<
"cut analysis short with number of positions";
158 for(std::size_t
i = 0;
i != units.size(); ++
i) {
162 assert(unit_itor != units_.
end());
169 bool backstab =
false, slow =
false;
172 if(
a.has_special(
"backstab",
true)) {
176 if(
a.has_special(
"slow",
true)) {
181 if(slow && cur_analysis.
movements.empty() ==
false) {
190 bool is_surrounded =
false;
191 bool is_flanked =
false;
192 int enemy_units_around = 0;
193 int accessible_tiles = 0;
196 for(std::size_t tile = 0; tile != 3; ++tile) {
198 bool possible_flanked =
false;
203 ++enemy_units_around;
204 possible_flanked =
true;
212 ++enemy_units_around;
213 if(possible_flanked) {
220 if((is_flanked && enemy_units_around > 2) || enemy_units_around >= accessible_tiles - 1) {
221 is_surrounded =
true;
224 double best_vulnerability = 0.0, best_support = 0.0;
226 int cur_position = -1;
229 for(
unsigned j = 0; j < tiles.size(); ++j) {
231 if(used_locations[j]) {
236 if(tiles[j] != current_unit) {
237 auto its = dstsrc.equal_range(tiles[j]);
238 while(its.first != its.second) {
239 if(its.first->second == current_unit) {
247 if(its.first == its.second || units_.
find(tiles[j]) != units_.
end()) {
253 double leadership_bonus =
static_cast<double>(best_leadership_bonus + 100) / 100.0;
254 if(leadership_bonus > 1.1) {
255 LOG_AI << unit_itor->name() <<
" is getting leadership " << leadership_bonus;
259 int backstab_bonus = 1;
260 double surround_bonus = 1.0;
262 if(tiles[(j + 3) % 6] != current_unit) {
278 if(!itor->get_ability_bool(
"skirmisher")) {
279 surround_bonus = 1.2;
285 int rating =
static_cast<int>(
rate_terrain(*unit_itor, tiles[j]) * backstab_bonus * leadership_bonus);
286 if(cur_position >= 0 && rating < best_rating) {
299 if(cur_position >= 0 && rating == best_rating
300 && vulnerability / surround_bonus - support * surround_bonus >= best_vulnerability - best_support) {
305 best_rating = rating;
306 best_vulnerability = vulnerability / surround_bonus;
307 best_support = support * surround_bonus;
310 if(cur_position != -1) {
311 units.erase(units.begin() +
i);
313 cur_analysis.
movements.emplace_back(current_unit, tiles[cur_position]);
315 cur_analysis.
support += best_support;
318 result.push_back(cur_analysis);
320 used_locations[cur_position] =
true;
322 do_attack_analysis(loc, srcdst, dstsrc, fullmove_srcdst, fullmove_dstsrc, enemy_srcdst, enemy_dstsrc, tiles,
323 used_locations, units, result, cur_analysis,
current_team);
325 used_locations[cur_position] =
false;
328 cur_analysis.
support -= best_support;
331 units.insert(units.begin() +
i, current_unit);
341 int rating = 100 - defense;
343 const int healing_value = 10;
344 const int friendly_village_value = 5;
345 const int neutral_village_value = 10;
346 const int enemy_village_value = 15;
349 rating += healing_value;
355 if(owner == u.
side()) {
356 rating += friendly_village_value;
357 }
else if(owner == 0) {
358 rating += neutral_village_value;
360 rating += enemy_village_value;
411 readonly_context& context,
const config& cfg,
const std::string&
id, std::shared_ptr<lua_ai_context>& l_ctx)
412 : aspect_attacks_base(context, cfg,
id)
415 , params_(cfg.child_or_empty(
"args"))
417 this->
name_ =
"lua_aspect";
419 code_ = cfg[
"code"].str();
437 aspect_attacks_base::recalculate();
441 luaL_unref(filt.
lua, LUA_REGISTRYINDEX, filt.
ref_own_);
464 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)
Euivalent 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...