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)
55 if (
const config &filter_own = cfg.
child(
"filter_own")) {
60 if (
const config &filter_enemy = cfg.
child(
"filter_enemy")) {
83 std::vector<map_location> unit_locs;
89 unit_locs.push_back(
i->get_location());
93 bool used_locations[6];
94 std::fill(used_locations,used_locations+6,
false);
97 move_map fullmove_srcdst, fullmove_dstsrc;
107 !j->invisible(j->get_location()))
115 analysis.
target = j->get_location();
116 analysis.vulnerability = 0.0;
117 analysis.support = 0.0;
119 fullmove_srcdst, fullmove_dstsrc, enemy_srcdst, enemy_dstsrc,
134 std::vector<map_location>&
units,
135 std::vector<attack_analysis>&
result,
137 const team ¤t_team
143 const int default_attack_depth = 5;
144 if(cur_analysis.
movements.size() >= size_t(default_attack_depth)) {
153 const size_t max_positions = 1000;
154 if(result.size() > max_positions && !cur_analysis.
movements.empty()) {
155 LOG_AI <<
"cut analysis short with number of positions\n";
159 for(
size_t i = 0;
i != units.size(); ++
i) {
163 assert(unit_itor != units_.
end());
170 bool backstab =
false, slow =
false;
171 std::vector<attack_type>& attacks = unit_itor->attacks();
175 if (
a->get_special_bool(
"backstab",
true) ) {
179 if (
a->get_special_bool(
"slow",
true) ) {
184 if(slow && cur_analysis.
movements.empty() ==
false) {
193 bool is_surrounded =
false;
194 bool is_flanked =
false;
195 int enemy_units_around = 0;
196 int accessible_tiles = 0;
201 for(tile = 0; tile != 3; ++tile) {
204 bool possible_flanked =
false;
209 if (tmp_unit != units_.
end() && current_team.
is_enemy(tmp_unit->side()))
211 enemy_units_around++;
212 possible_flanked =
true;
220 if (tmp_opposite_unit != units_.
end() && current_team.
is_enemy(tmp_opposite_unit->side()))
222 enemy_units_around++;
231 if((is_flanked && enemy_units_around > 2) || enemy_units_around >= accessible_tiles - 1)
232 is_surrounded =
true;
236 double best_vulnerability = 0.0, best_support = 0.0;
238 int cur_position = -1;
241 for(
int j = 0; j != 6; ++j) {
244 if(used_locations[j]) {
249 if (tiles[j] != current_unit) {
250 typedef std::multimap<map_location,map_location>::const_iterator Itor;
251 std::pair<Itor,Itor> its = dstsrc.equal_range(tiles[j]);
252 while(its.first != its.second) {
253 if(its.first->second == current_unit)
259 if(its.first == its.second || units_.
find(tiles[j]) != units_.
end()) {
265 int best_leadership_bonus = abil.
highest(
"value").first;
266 double leadership_bonus =
static_cast<double>(best_leadership_bonus+100)/100.0;
267 if (leadership_bonus > 1.1) {
268 LOG_AI << unit_itor->name() <<
" is getting leadership " << leadership_bonus <<
"\n";
272 int backstab_bonus = 1;
273 double surround_bonus = 1.0;
275 if(tiles[(j+3)%6] != current_unit) {
285 if(itor != units_.
end() &&
292 if (!itor->get_ability_bool(
"skirmisher"))
293 surround_bonus = 1.2;
300 int rating =
static_cast<int>(
rate_terrain(*unit_itor, tiles[j]) * backstab_bonus * leadership_bonus);
301 if(cur_position >= 0 && rating < best_rating) {
317 if(cur_position >= 0 && rating < best_rating
318 && (vulnerability/surround_bonus*30.0)/unit_itor->second.hitpoints() -
319 (support*surround_bonus*30.0)/unit_itor->second.max_hitpoints()
320 > best_vulnerability - best_support) {
324 if(cur_position >= 0 && rating == best_rating && vulnerability/surround_bonus - support*surround_bonus >= best_vulnerability - best_support) {
329 best_rating = rating;
332 best_vulnerability = (vulnerability/surround_bonus*30.0)/unit_itor->second.hitpoints();
333 best_support = (support*surround_bonus*30.0)/unit_itor->second.max_hitpoints();
335 best_vulnerability = vulnerability/surround_bonus;
336 best_support = support*surround_bonus;
340 if(cur_position != -1) {
341 units.erase(units.begin() +
i);
343 cur_analysis.
movements.push_back(std::pair<map_location,map_location>(current_unit,tiles[cur_position]));
347 cur_analysis.
support += best_support;
351 result.push_back(cur_analysis);
352 used_locations[cur_position] =
true;
353 do_attack_analysis(loc,srcdst,dstsrc,fullmove_srcdst,fullmove_dstsrc,enemy_srcdst,enemy_dstsrc,
354 tiles,used_locations,
355 units,result,cur_analysis, current_team);
356 used_locations[cur_position] =
false;
360 cur_analysis.
support -= best_support;
364 units.insert(units.begin() +
i, current_unit);
374 int rating = 100 - defense;
376 const int healing_value = 10;
377 const int friendly_village_value = 5;
378 const int neutral_village_value = 10;
379 const int enemy_village_value = 15;
382 rating += healing_value;
388 if(owner == u.
side()) {
389 rating += friendly_village_value;
390 }
else if(owner == 0) {
391 rating += neutral_village_value;
393 rating += enemy_village_value;
432 : aspect_attacks_base(context, cfg, id)
433 , handler_(), code_(), params_(cfg.child_or_empty(
"args"))
435 this->
name_ =
"lua_aspect";
438 code_ = cfg[
"code"].str();
457 aspect_attacks_base::recalculate();
virtual side_number get_side() const
Get the side number.
boost::shared_ptr< unit_filter > filter_own_
LUA_API void lua_rawgeti(lua_State *L, int idx, int n)
LUA_API void lua_pushlightuserdata(lua_State *L, void *p)
virtual config to_config() const
boost::shared_ptr< attacks_vector > analyze_targets() const
aspect_attacks_lua(readonly_context &context, const config &cfg, const std::string &id, boost::shared_ptr< lua_ai_context > &l_ctx)
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.
size_t underlying_id() const
The unique internal ID of the unit.
boost::shared_ptr< attacks_vector > value_
Various functions that implement attacks and attack calculations.
void get_adjacent_tiles(const map_location &a, map_location *res)
Function which, given a location, will place all adjacent locations in res.
bool is_village(const map_location &loc) const
std::map< map_location, pathfind::paths > moves_map
The standard way in which a map of possible movement routes to location is recorded.
bool is_enemy(int n) const
boost::shared_ptr< lua_object< aspect_attacks_lua_filter > > obj_
double vulnerability
The vulnerability is the power projection of enemy units onto the hex we're standing on...
boost::shared_ptr< lua_ai_action_handler > handler_
virtual unit_stats_cache_t & unit_stats_cache() const
int village_owner(const map_location &loc) const
Given the location of a village, will return the 0-based index of the team that currently owns it...
std::pair< int, map_location > highest(const std::string &key, int def=0) const
aspect_attacks_base(readonly_context &context, const config &cfg, const std::string &id)
luatypekey const getunitKey
virtual config to_config() const
bool get_ability_bool(const std::string &tag_name, const map_location &loc) const
Returns true if the unit is currently under effect by an ability with this given TAG NAME...
boost::shared_ptr< unit_filter > filter_enemy_
LUA_API void * lua_newuserdata(lua_State *L, size_t size)
int defense_modifier(const t_translation::t_terrain &terrain) const
virtual config to_config() const
virtual double power_projection(const map_location &loc, const move_map &dstsrc) const
Function which finds how much 'power' a side can attack a certain location with.
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.
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...
virtual double get_aggression() const
boost::shared_ptr< unit_filter > filter_own_
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::vector< team > * teams
bool luaW_toboolean(lua_State *L, int n)
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 map_location *tiles, bool *used_locations, std::vector< map_location > &units, std::vector< attack_analysis > &result, attack_analysis &cur_analysis, const team ¤t_team) const
filter_context * filter_con
virtual bool is_allowed_enemy(const unit &u) const
GLboolean GLboolean GLboolean GLboolean a
boost::shared_ptr< unit_filter > filter_enemy_
Encapsulates the map of the game.
aspect_attacks(readonly_context &context, const config &cfg, const std::string &id)
config & add_child(const std::string &key)
virtual void recalculate() const
LUA_API int lua_setmetatable(lua_State *L, int objindex)
Managing the AIs lifecycle - headers.
virtual const move_map & get_srcdst() const
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
static const ::config * terrain
The terrain used to create the cache.
virtual const move_map & get_enemy_dstsrc() const
A terrain string which is converted to a terrain is a string with 1 or 2 layers the layers are separa...
virtual const move_map & get_enemy_srcdst() const
Encapsulates the map of the game.
Storage for a unit, either owned by the Lua code (ptr != 0), a local variable unit (c_ptr != 0)...
static 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.
std::map< std::string, tfilter >::iterator itor
virtual bool is_allowed_attacker(const unit &u) const =0
virtual bool is_allowed_attacker(const unit &u) const
virtual bool get_passive_leader() const
std::vector< std::pair< map_location, map_location > > movements
ai::lua_ai_action_handler * create_lua_ai_action_handler(char const *code, ai::lua_ai_context &context)
boost::shared_ptr< std::vector< unit_const_ptr > > units_
virtual const team & current_team() const
virtual const gamemap & map() const
t_translation::t_terrain 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.
#define LUA_REGISTRYINDEX
bool has_attribute(const std::string &key) const
virtual bool is_allowed_enemy(const unit &u) const =0
config & child(const std::string &key, int n=0)
Returns the nth child with the given key, or a reference to an invalid config if there is none...
A variable-expanding proxy for the config class.
Standard logging facilities (interface).
game_lua_kernel * lua_kernel
Container associating units to locations.
LUALIB_API void luaL_unref(lua_State *L, int t, int ref)
bool is_surrounded
Is true if the units involved in this attack sequence are surrounded.
virtual bool is_allowed_attacker(const unit &u) const
virtual void recalculate() const
unit_iterator find(size_t id)
A config object defines a single node in a WML file, with access to child nodes.
virtual bool is_allowed_enemy(const unit &u) const
void make_safe() const
instruct the vconfig to make a private copy of its underlying data.
static int rate_terrain(const unit &u, const map_location &loc)
This module contains various pathfinding functions and utilities.
LUA_API void lua_rawget(lua_State *L, int idx)
GLsizei const GLcharARB ** string
virtual const move_map & get_dstsrc() const
int gives_healing(const map_location &loc) const