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) 56 if(
const config& filter_own = cfg.
child(
"filter_own")) {
62 if(
const config& filter_enemy = cfg.
child(
"filter_enemy")) {
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();
116 analysis.vulnerability = 0.0;
117 analysis.support = 0.0;
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,
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;
202 if(tmp_unit != units_.
end() && current_team.
is_enemy(tmp_unit->side())) {
203 ++enemy_units_around;
204 possible_flanked =
true;
211 if(tmp_opposite_unit != units_.
end() && current_team.
is_enemy(tmp_opposite_unit->side())) {
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)
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 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...
static std::unique_ptr< class sdl_event_handler > handler_
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...
virtual const move_map & get_enemy_srcdst() const override
lua_unit * luaW_pushunit(lua_State *L, Args... args)
aspect_attacks_lua(readonly_context &context, const config &cfg, const std::string &id, std::shared_ptr< lua_ai_context > &l_ctx)
virtual const std::vector< team > & teams() const override
void get_adjacent_tiles(const map_location &a, map_location *res)
Function which, given a location, will place all adjacent locations in res.
virtual const unit_map & units() const override
static bool call_lua_filter_fcn(lua_State *L, const unit &u, int idx)
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.
This class represents a single unit of a specific type.
static manager & get_singleton()
Various functions that implement attacks and attack calculations.
bool has_attribute(config_key_type key) const
virtual bool is_allowed_attacker(const unit &u) const
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.
virtual const move_map & get_srcdst() const override
virtual config to_config() const
virtual const gamemap & map() const override
double vulnerability
The vulnerability is the power projection of enemy units onto the hex we're standing on...
A terrain string which is converted to a terrain is a string with 1 or 2 layers the layers are separa...
aspect_attacks_base(readonly_context &context, const config &cfg, const std::string &id)
std::shared_ptr< attacks_vector > value_
virtual unit_stats_cache_t & unit_stats_cache() const override
std::multimap< map_location, map_location > move_map
The standard way in which a map of possible moves is recorded.
std::vector< attack_analysis > attacks_vector
std::map< map_location, pathfind::paths > moves_map
The standard way in which a map of possible movement routes to location is recorded.
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
std::shared_ptr< unit_filter > filter_enemy_
int defense_modifier(const t_translation::terrain_code &terrain) const
The unit's defense on a given terrain.
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...
const vconfig & make_safe() const
instruct the vconfig to make a private copy of its underlying data.
int gives_healing(const map_location &loc) const
static lg::log_domain log_ai_testing_aspect_attacks("ai/aspect/attacks")
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)
std::shared_ptr< unit_filter > filter_own_
std::shared_ptr< unit_filter > filter_enemy_
bool luaW_toboolean(lua_State *L, int n)
terrain_code get_terrain(const map_location &loc) const
Looks up terrain at a particular location.
Encapsulates the map of the game.
aspect_attacks(readonly_context &context, const config &cfg, const std::string &id)
bool is_enemy(int n) const
virtual bool is_passive_leader(const std::string &id) const override
virtual const move_map & get_enemy_dstsrc() const override
Managing the AIs lifecycle - headers TODO: Refactor history handling and internal commands...
virtual config to_config() const
Encapsulates the map of the game.
unit_iterator find(std::size_t id)
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.
void raise_user_interact()
Notifies all observers of 'ai_user_interact' event.
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.
virtual bool is_allowed_attacker(const unit &u) const
virtual const team & current_team() const override
std::shared_ptr< lua_ai_action_handler > handler_
virtual void recalculate() const
std::vector< std::pair< map_location, map_location > > movements
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 bool is_allowed_enemy(const unit &u) const
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::shared_ptr< unit_filter > filter_own_
config & add_child(config_key_type key)
virtual void recalculate() const
bool is_village(const map_location &loc) const
virtual const move_map & get_dstsrc() const override
virtual double get_aggression() 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
A variable-expanding proxy for the config class.
Standard logging facilities (interface).
game_lua_kernel * lua_kernel
Container associating units to locations.
bool is_surrounded
Is true if the units involved in this attack sequence are surrounded.
int side() const
The side this unit belongs to.
virtual bool is_allowed_enemy(const unit &u) const
A config object defines a single node in a WML file, with access to child nodes.
std::shared_ptr< lua_object< aspect_attacks_lua_filter > > obj_
static int rate_terrain(const unit &u, const map_location &loc)
virtual config to_config() const
This module contains various pathfinding functions and utilities.
std::size_t underlying_id() const
This unit's unique internal ID.
std::shared_ptr< attacks_vector > analyze_targets() const