45 #define LOG_AI LOG_STREAM(info, log_formula_ai)
46 #define WRN_AI LOG_STREAM(warn, log_formula_ai)
47 #define ERR_AI LOG_STREAM(err, log_formula_ai)
60 auto unit = arg.try_convert<unit_callable>();
77 std::pair<std::string, std::string> types = attack.
damage_type();
79 if(!(types.second).empty()){
110 #define DEFINE_FAI_FUNCTION(name, min_args, max_args) \
111 class name##_function : public function_expression \
114 explicit name##_function(const args_list& args, const formula_ai& ai) \
115 : function_expression(#name, args, min_args, max_args), ai_(ai) \
120 const formula_ai& ai_; \
121 variant execute(const formula_callable& variables, formula_debugger* fdb) const; \
124 variant name##_function::execute(const formula_callable& variables, formula_debugger* fdb) const
128 const map_location loc = args()[0]->evaluate(variables,
add_debug_info(fdb, 0,
"distance_to_nearest_unowned_village:location")).convert_to<location_callable>()->
loc();
132 for(std::vector<map_location>::const_iterator
i = villages.begin();
i != villages.end(); ++
i) {
134 if(distance < best) {
135 if(my_villages.count(*
i) == 0) {
141 return variant(best);
144 static unsigned search_counter;
149 indexer(
int a,
int b) :
w(a),
h(
b) { }
187 comp(
const std::vector<node>&
n) :
nodes(
n) { }
188 bool operator()(
int l,
int r)
const {
194 std::vector<int>& scores,
bool allow_teleport,
const formula_ai&
ai_)
196 const std::set<map_location>& teleports = allow_teleport ?
ai_.
current_team().
villages() : std::set<map_location>();
200 std::vector<map_location> locs(6 + teleports.size());
201 std::copy(teleports.begin(), teleports.end(), locs.begin() + 6);
204 if (search_counter == 0) search_counter = 2;
206 static std::vector<node>
nodes;
207 nodes.resize(
static_cast<size_t>(map.
w()) * map.
h());
209 indexer
index(map.
w(), map.
h());
210 comp node_comp(
nodes);
215 while (!pq.empty()) {
216 node&
n =
nodes[pq.front()];
217 std::pop_heap(pq.begin(), pq.end(), node_comp);
219 n.in = search_counter;
222 for (
int i = teleports.count(
n.loc_) ? locs.size() : 6;
i-- > 0;) {
223 if (!locs[
i].valid(map.
w(), map.
h()))
continue;
226 bool next_visited = next.in - search_counter <= 1u;
230 if (next_visited && !(
n < next))
continue;
231 const int move_cost = u.movement_cost(map[locs[
i]]);
233 node
t = node(
n.movement_cost_ + move_cost, locs[
i]);
235 if (next_visited && !(
t < next))
continue;
237 bool in_list = next.in == search_counter + 1;
238 t.in = search_counter + 1;
243 std::push_heap(pq.begin(),
std::find(pq.begin(), pq.end(),
index(locs[
i])) + 1, node_comp);
246 pq.push_back(
index(locs[
i]));
247 std::push_heap(pq.begin(), pq.end(), node_comp);
252 for (
int x = 0; x < map.
w(); ++x) {
253 for (
int y = 0; y < map.
h(); ++y)
255 int i = y * map.
w() + x;
257 scores[
i] = scores[
i] +
n.movement_cost_;
269 const variant units_input = args()[0]->evaluate(variables,fdb);
270 const variant leaders_input = args()[1]->evaluate(variables,fdb);
272 int enemy_tolerance = 3;
273 if( args().
size() > 2 )
274 enemy_tolerance = args()[2]->evaluate(variables,fdb).as_int();
276 int enemy_border_tolerance = 5;
277 if( args().
size() > 3 )
278 enemy_border_tolerance = args()[3]->evaluate(variables,fdb).as_int();
280 int ally_tolerance = 3;
281 if( args().
size() > 4 )
282 ally_tolerance = args()[4]->evaluate(variables,fdb).as_int();
284 if( !units_input.is_list() )
287 std::size_t number_of_teams = units_input.num_elements();
289 std::vector< std::vector<int>> scores( number_of_teams );
291 for( std::size_t
i = 0;
i< number_of_teams; ++
i)
292 scores[
i].resize(
static_cast<size_t>(
w)*
h);
302 for(std::size_t side = 0 ; side < units_input.num_elements() ; ++side) {
303 if( leaders_input[side].is_empty() )
306 const map_location loc = leaders_input[side][0].convert_to<location_callable>()->
loc();
307 const variant units_of_side = units_input[side];
309 for(std::size_t unit_it = 0 ; unit_it < units_of_side.num_elements() ; ++unit_it) {
310 unit_adapter
unit(units_of_side[unit_it]);
311 find_movemap(
unit,
loc, scores[side],
true,
ai_ );
315 std::size_t
index = 0;
316 for( std::vector< std::vector<int>>::
iterator i = scores.begin() ;
i != scores.end() ; ++
i) {
318 if(units_input[
index].num_elements() != 0) {
319 *j /= units_input[
index].num_elements();
328 std::map<variant, variant> res;
332 std::vector<int> enemies;
333 std::vector<int> allies;
335 for(std::size_t side = 0 ; side < units_input.num_elements() ; ++side) {
336 if( side == current_side)
340 if( !leaders_input[side].is_empty() )
341 enemies.push_back(side);
343 if( !leaders_input[side].is_empty() )
344 allies.push_back(side);
350 for (
int x = 0; x <
w; ++x) {
351 for (
int y = 0; y <
h; ++y)
355 bool enemy_border =
false;
357 if( scores[current_side][
i] > 98 )
360 for (
int side : enemies) {
361 int diff = scores[current_side][
i] - scores[side][
i];
362 if ( diff > enemy_tolerance) {
365 }
else if( std::abs(diff) < enemy_border_tolerance )
370 for (
int side : allies) {
371 if ( scores[current_side][
i] - scores[side][
i] > ally_tolerance ) {
380 res.emplace(variant(std::make_shared<location_callable>(
map_location(x, y))), variant(scores[0][
i] + 10000));
382 res.emplace(variant(std::make_shared<location_callable>(
map_location(x, y))), variant(scores[0][
i]));
392 variant items = args()[1]->evaluate(variables,
add_debug_info(fdb,1,
"nearest_loc:locations"));
396 for(std::size_t
i = 0;
i < items.num_elements(); ++
i) {
398 const map_location move_loc = items[
i].convert_to<location_callable>()->
loc();
401 if(distance < best) {
408 return variant(std::make_shared<location_callable>(items[best_i].convert_to<location_callable>()->
loc()));
418 const args_list& arguments = args();
419 const variant var0 = arguments[0]->evaluate(variables,
add_debug_info(fdb,0,
"run_file:file"));
420 const std::string
filename = var0.string_cast();
433 ERR_AI <<
"run_file : unable to create formula";
436 return parsed_formula->evaluate(variables,
add_debug_info(fdb,-1,
"run_file:formula_from_file"));
441 const map_location starting_loc = args()[0]->evaluate(variables,
add_debug_info(fdb, 0,
"castle_locs:location")).convert_to<location_callable>()->
loc();
444 std::set< map_location > visited_locs;
445 std::queue< map_location > queued_locs;
447 queued_locs.push(starting_loc);
449 while( !queued_locs.empty() ) {
453 if ( visited_locs.find(
loc ) != visited_locs.end() )
456 visited_locs.insert(
loc);
459 if (
resources::gameboard->map().on_board(adj) && visited_locs.find( adj ) == visited_locs.end() ) {
462 queued_locs.push(adj);
470 visited_locs.erase(starting_loc);
472 std::vector<variant> res;
474 res.emplace_back(std::make_shared<location_callable>( ml ));
489 variant u = args()[0]->evaluate(variables,
add_debug_info(fdb,0,
"timeofday_modifier:unit"));
495 auto u_call = u.try_convert<unit_callable>();
501 const unit& un = u_call->get_unit();
505 if(args().
size()==2) {
506 loc = args()[1]->evaluate(variables,
add_debug_info(fdb, 1,
"timeofday_modifier:location")).convert_to<location_callable>()->
loc();
510 loc = u_call->get_location();
525 for(
int i = 0 ;
i <
size; ++
i) {
549 if (u == units.
end()){
558 std::vector<variant> vars;
561 if(args().
size()==1) {
562 const gamemap& m = args()[0]->evaluate(variables,
add_debug_info(fdb, 0,
"find_shroud:gamemap")).convert_to<gamemap_callable>()->get_gamemap();
570 for(
int i = 0;
i <
w; ++
i)
571 for(
int j = 0; j <
h; ++j) {
573 vars.emplace_back(std::make_shared<location_callable>(
map_location(
i, j)));
576 return variant(vars);
581 std::vector<variant> vars;
583 int range_s = args()[1]->evaluate(variables,
add_debug_info(fdb,1,
"close_enemies:distance")).as_int();
585 WRN_AI <<
"close_enemies_function: range is negative (" << range_s <<
")";
588 std::size_t range =
static_cast<std::size_t
>(range_s);
594 vars.emplace_back(std::make_shared<unit_callable>(*un));
599 return variant(vars);
604 std::vector<variant> vars;
606 if (args().
size() > 3) weapon = args()[3]->evaluate(variables,
add_debug_info(fdb,3,
"calculate_outcome:weapon")).as_int();
611 args()[0]->evaluate(variables,
add_debug_info(fdb, 0,
"calculate_outcome:attacker_current_location")).convert_to<location_callable>()->
loc();
612 if(units.
count(attacker_location) == 0) {
613 ERR_AI <<
"Performing calculate_outcome() with non-existent attacker at (" <<
614 attacker_location.
wml_x() <<
"," << attacker_location.
wml_y() <<
")";
619 args()[2]->evaluate(variables,
add_debug_info(fdb, 2,
"calculate_outcome:defender_location")).convert_to<location_callable>()->
loc();
620 if(units.
count(defender_location) == 0) {
621 ERR_AI <<
"Performing calculate_outcome() with non-existent defender at (" <<
622 defender_location.
wml_x() <<
"," << defender_location.
wml_y() <<
")";
626 battle_context bc(units, args()[1]->evaluate(variables,
add_debug_info(fdb, 1,
"calculate_outcome:attacker_attack_location")).convert_to<location_callable>()->
loc(),
627 defender_location, weapon, -1, 1.0,
nullptr, units.
find(attacker_location).
get_shared_ptr());
628 std::vector<double> hp_dist = bc.get_attacker_combatant().hp_dist;
631 std::vector<variant> hitLeft;
632 std::vector<variant> prob;
633 while (it != hp_dist.end()) {
635 hitLeft.emplace_back(
i);
636 prob.emplace_back(
static_cast<int>(*it*10000));
641 std::vector<variant> status;
642 if (bc.get_attacker_combatant().poisoned != 0)
643 status.emplace_back(
"Poisoned");
644 if (bc.get_attacker_combatant().slowed != 0)
645 status.emplace_back(
"Slowed");
646 if (bc.get_defender_stats().petrifies &&
static_cast<unsigned int>(hitLeft[0].as_int()) != bc.get_attacker_stats().hp)
647 status.emplace_back(
"Stoned");
648 if (bc.get_defender_stats().plagues && hitLeft[0].as_int() == 0)
649 status.emplace_back(
"Zombiefied");
650 vars.emplace_back(std::make_shared<outcome_callable>(hitLeft, prob, status));
654 hp_dist = bc.get_defender_combatant().hp_dist;
655 it = hp_dist.begin();
657 while (it != hp_dist.end()) {
659 hitLeft.emplace_back(
i);
660 prob.emplace_back(
static_cast<int>(*it*10000));
665 if (bc.get_defender_combatant().poisoned != 0)
666 status.emplace_back(
"Poisoned");
667 if (bc.get_defender_combatant().slowed != 0)
668 status.emplace_back(
"Slowed");
669 if (bc.get_attacker_stats().petrifies &&
static_cast<unsigned int>(hitLeft[0].as_int()) != bc.get_defender_stats().hp)
670 status.emplace_back(
"Stoned");
671 if (bc.get_attacker_stats().plagues && hitLeft[0].as_int() == 0)
672 status.emplace_back(
"Zombiefied");
673 vars.emplace_back(std::make_shared<outcome_callable>(hitLeft, prob, status));
674 return variant(vars);
679 variant attack = args()[0]->evaluate(variables,
add_debug_info(fdb,0,
"outcomes:attack"));
687 std::vector<variant> vars;
688 if(analysis->chance_to_kill > 0.0) {
691 vars.emplace_back(std::make_shared<position_callable>(
static_cast<int>(analysis->chance_to_kill*100)));
695 if(analysis->chance_to_kill < 1.0) {
697 vars.emplace_back(std::make_shared<position_callable>(
static_cast<int>(100 - analysis->chance_to_kill*100)));
700 return variant(vars);
705 variant act = args()[0]->evaluate(variables,
add_debug_info(fdb,0,
"rate_action:action"));
713 const std::string
id = args()[0]->evaluate(variables,
add_debug_info(fdb,0,
"recall:id")).as_string();
715 if(args().
size() >= 2) {
716 loc = args()[1]->evaluate(variables,
add_debug_info(fdb, 1,
"recall:location")).convert_to<location_callable>()->
loc();
719 return variant(std::make_shared<recall_callable>(
loc,
id));
724 const std::string
type = args()[0]->evaluate(variables,
add_debug_info(fdb,0,
"recruit:type")).as_string();
726 if(args().
size() >= 2) {
727 loc = args()[1]->evaluate(variables,
add_debug_info(fdb, 1,
"recruit:location")).convert_to<location_callable>()->
loc();
730 return variant(std::make_shared<recruit_callable>(
loc,
type));
736 std::vector<variant> locations;
743 return variant(locations);
745 if(args().
size() > 2)
746 unit_loc = args()[2]->evaluate(variables,
add_debug_info(fdb,2,
"shortest_path:unit_location")).convert_to<location_callable>()->
loc();
753 std::ostringstream str;
754 str <<
"shortest_path function: expected unit at location (" << (unit_loc.
wml_x()) <<
"," << (unit_loc.
wml_y()) <<
")";
755 throw formula_error( str.str(),
"",
"", 0);
762 if( route.
steps.size() < 2 ) {
763 return variant(locations);
766 for (std::vector<map_location>::const_iterator loc_iter = route.
steps.begin() + 1 ; loc_iter !=route.
steps.end(); ++loc_iter) {
767 locations.emplace_back(std::make_shared<location_callable>(*loc_iter));
770 return variant(locations);
775 std::vector<variant> locations;
782 return variant(locations);
784 if(args().
size() > 2)
785 unit_loc = args()[2]->evaluate(variables,
add_debug_info(fdb, 2,
"simplest_path:unit_location")).convert_to<location_callable>()->
loc();
792 std::ostringstream str;
793 str <<
"simplest_path function: expected unit at location (" << (unit_loc.
wml_x()) <<
"," << (unit_loc.
wml_y()) <<
")";
794 throw formula_error( str.str(),
"",
"", 0);
803 if( route.
steps.size() < 2 ) {
804 return variant(locations);
807 for (std::vector<map_location>::const_iterator loc_iter = route.
steps.begin() + 1 ; loc_iter !=route.
steps.end(); ++loc_iter) {
809 locations.emplace_back(std::make_shared<location_callable>(*loc_iter));
815 return variant(locations);
828 if(args().
size() > 2)
829 unit_loc = args()[2]->evaluate(variables,
add_debug_info(fdb, 2,
"next_hop:unit_location")).convert_to<location_callable>()->
loc();
836 std::ostringstream str;
837 str <<
"next_hop function: expected unit at location (" << (unit_loc.
wml_x()) <<
"," << (unit_loc.
wml_y()) <<
")";
838 throw formula_error( str.str(),
"",
"", 0);
845 if( route.
steps.size() < 2 ) {
851 const ai::moves_map::const_iterator& p_it = possible_moves.find(unit_loc);
852 if (p_it==possible_moves.end() ) {
856 for (std::vector<map_location>::const_iterator loc_iter = route.
steps.begin() + 1 ; loc_iter !=route.
steps.end(); ++loc_iter) {
858 if (p_it->second.destinations.find(*loc_iter) != p_it->second.destinations.end() ) {
867 return variant(std::make_shared<location_callable>(
loc));
875 return variant(std::make_shared<move_callable>(
src,
dst));
882 LOG_AI <<
"move_partial(): " <<
src <<
", " <<
dst <<
")";
883 return variant(std::make_shared<move_partial_callable>(
src,
dst));
888 return variant(std::make_shared<set_unit_var_callable>(args()[0]->evaluate(variables,
add_debug_info(fdb,0,
"set_unit_var:key")).as_string(), args()[1]->evaluate(variables,
add_debug_info(fdb,1,
"set_unit_var:value")), args()[2]->evaluate(variables,
add_debug_info(fdb,2,
"set_unit_var:unit_location")).convert_to<location_callable>()->
loc()));
894 if(args().
size() == 1 && args()[0]->evaluate(variables).as_string() !=
"human")
896 return variant(std::make_shared<fallback_callable>());
901 const map_location move_from = args()[0]->evaluate(variables,
add_debug_info(fdb, 0,
"attack:move_from")).convert_to<location_callable>()->
loc();
904 const int weapon = args().size() == 4 ? args()[3]->evaluate(variables,
add_debug_info(fdb,3,
"attack:weapon")).as_int() : -1;
906 ERR_AI <<
"AI ERROR: Formula produced illegal attack: " << move_from <<
" -> " <<
src <<
" -> " <<
dst;
909 return variant(std::make_shared<attack_callable>(move_from,
src,
dst, weapon));
914 const args_list& arguments = args();
915 const variant var0 = arguments[0]->evaluate(variables,fdb);
916 const variant var1 = arguments[1]->evaluate(variables,fdb);
918 const map_location location = var0.convert_to<location_callable>()->
loc();
920 if( var1.is_string() )
921 text = var1.as_string();
923 text = var1.to_debug_string();
926 std::string team_name;
931 res =
gui->labels().set_label(location, text,
ai_.
get_side() - 1, team_name, color);
935 std::vector<variant> result;
936 result.push_back(var0);
937 result.push_back(var1);
938 return variant(result);
943 const gamemap& m = args()[0]->evaluate(variables,
add_debug_info(fdb, 0,
"is_village:map")).convert_to<gamemap_callable>()->get_gamemap();
946 if(args().
size() == 2) {
947 loc = args()[1]->evaluate(variables,
add_debug_info(fdb, 1,
"is_village:location")).convert_to<location_callable>()->
loc();
958 const gamemap& m = args()[0]->evaluate(variables,
add_debug_info(fdb, 0,
"is_unowned_village:map")).convert_to<gamemap_callable>()->get_gamemap();
962 if(args().
size() == 2) {
963 loc = args()[1]->evaluate(variables,
add_debug_info(fdb, 1,
"is_unowned_village:location")).convert_to<location_callable>()->
loc();
970 return variant(
true);
972 return variant(
false);
978 variant res = args()[0]->evaluate(variables,
add_debug_info(fdb,0,
"unit_moves:unit_location"));
979 std::vector<variant> vars;
981 return variant(vars);
986 typedef ai::move_map::const_iterator Itor;
987 std::pair<Itor,Itor> range = srcdst.equal_range(
loc);
989 for(Itor
i = range.first;
i != range.second; ++
i) {
990 vars.emplace_back(std::make_shared<location_callable>(
i->second));
993 return variant(vars);
998 std::vector<variant> vars;
999 variant dstsrc_var = args()[0]->evaluate(variables,
add_debug_info(fdb,0,
"units_can_reach:possible_move_list"));
1000 const ai::move_map& dstsrc = dstsrc_var.convert_to<move_map_callable>()->dstsrc();
1001 std::pair<ai::move_map::const_iterator,ai::move_map::const_iterator> range =
1002 dstsrc.equal_range(args()[1]->evaluate(variables,
add_debug_info(fdb, 1,
"units_can_reach:possible_move_list")).convert_to<location_callable>()->
loc());
1003 while(range.first != range.second) {
1006 vars.emplace_back(std::make_shared<unit_callable>(*un));
1010 return variant(vars);
1015 variant res = args()[0]->evaluate(variables,
add_debug_info(fdb,0,
"is_avoided_location:location"));
1025 variant u1 = args()[0]->evaluate(variables,
add_debug_info(fdb,0,
"max_possible_damage:unit1"));
1026 variant u2 = args()[1]->evaluate(variables,
add_debug_info(fdb,1,
"max_possible_damage:unit2"));
1027 if(u1.is_null() || u2.is_null()) {
1031 unit_adapter u_attacker(u1), u_defender(u2);
1033 for(
const attack_type& atk : u_attacker.attacks()) {
1034 const int dmg =
round_damage(atk.damage(), u_defender.damage_from(atk), 100) * atk.num_attacks();
1038 return variant(best);
1042 std::pair<int, int> best_melee_and_ranged_attacks(unit_adapter attacker, unit_adapter defender) {
1043 int highest_melee_damage = 0;
1044 int highest_ranged_damage = 0;
1046 for (
const attack_type &attack : attacker.attacks()) {
1047 const int dmg =
round_damage(attack.damage(), defender.damage_from(attack), 100) * attack.num_attacks();
1048 if (attack.range() ==
"melee") {
1049 highest_melee_damage = std::max(highest_melee_damage, dmg);
1051 highest_ranged_damage = std::max(highest_ranged_damage, dmg);
1055 return std::pair(highest_melee_damage, highest_ranged_damage);
1061 variant u1 = args()[0]->evaluate(variables,
add_debug_info(fdb,0,
"max_possible_damage_with_retaliation:unit1"));
1062 variant u2 = args()[1]->evaluate(variables,
add_debug_info(fdb,1,
"max_possible_damage_with_retaliation:unit2"));
1064 if(u1.is_null() || u2.is_null()) {
1068 unit_adapter attacker(u1);
1069 unit_adapter defender(u2);
1072 std::pair<int, int> best_attacker_attacks = best_melee_and_ranged_attacks(attacker, defender);
1073 std::pair<int, int> best_defender_attacks = best_melee_and_ranged_attacks(defender, attacker);
1075 std::vector<variant> vars;
1076 vars.emplace_back(best_attacker_attacks.first);
1077 vars.emplace_back(best_attacker_attacks.second);
1078 vars.emplace_back(best_defender_attacks.first);
1079 vars.emplace_back(best_defender_attacks.second);
1081 return variant(vars);
1084 template<
typename T>
1085 class ai_formula_function :
public formula_function {
1089 ai_formula_function(
const std::string& name,
ai::formula_ai&
ai) : formula_function(name),
ai_(
ai) {}
1091 return std::make_shared<T>(args,
ai_);
1099 #define DECLARE_FAI_FUNCTION(name) \
1100 add_function(#name, std::make_shared<ai_formula_function<name##_function>>(#name, ai))
1139 #undef DECLARE_WFL_FUNCTION
int combat_modifier(const unit_map &units, const gamemap &map, const map_location &loc, unit_alignments::type alignment, bool is_fearless)
Returns the amount that a unit's damage should be multiplied by due to the current time of day.
boost::iterator_range< boost::indirect_iterator< attack_list::const_iterator > > const_attack_itors
virtual const map_location & suitable_keep(const map_location &leader_location, const pathfind::paths &leader_paths) const override
get most suitable keep for leader - nearest free that can be reached in 1 turn, if none - return near...
virtual const team & current_team() const override
virtual const terrain_filter & get_avoid() const override
virtual const move_map & get_srcdst() const override
virtual double get_aggression() const override
virtual const moves_map & get_possible_moves() const override
virtual side_number get_side() const override
Get the side number.
std::pair< std::string, std::string > damage_type() const
return a modified damage type and/or add a secondary_type for hybrid use if special is active.
Computes the statistics of a battle between an attacker and a defender unit.
Sort-of-Singleton that many classes, both GUI and non-GUI, use to access the game data.
static display * get_singleton()
Returns the display object if a display object exists.
virtual const unit_map & units() const override
virtual const gamemap & map() const override
int w() const
Effective map width.
int h() const
Effective map height.
Encapsulates the map of the game.
bool is_village(const map_location &loc) const
const std::vector< map_location > & villages() const
Return a list of the locations of villages on the map.
static const int UNREACHABLE
Magic value that signifies a hex is unreachable.
int resistance_against(const std::string &damage_type) const
Returns the vulnerability to the indicated damage type (higher means takes more damage).
int movement_cost(const t_translation::terrain_code &terrain, bool slowed=false) const
Returns the cost to move through the indicated terrain.
void add_label(const terrain_label *)
bool is_enemy(int n) const
const std::set< map_location > & villages() const
bool shrouded(const map_location &loc) const
static color_t get_side_color(int side)
To store label data Class implements logic for rendering.
Container associating units to locations.
std::size_t count(const map_location &loc) const
unit_iterator find(std::size_t id)
A single unit type that the player may recruit.
const movetype & movement_type() const
const_attack_itors attacks() const
This class represents a single unit of a specific type.
ai_function_symbol_table(ai::formula_ai &ai)
std::size_t num_elements() const
std::shared_ptr< T > convert_to() const
map_display and display: classes which take care of displaying the map and game-data on the screen.
Declarations for File-IO.
#define DEFINE_WFL_FUNCTION(name, min_args, max_args)
Helper macro to declare an associated class for a WFL function.
#define DECLARE_WFL_FUNCTION(name)
Declares a function name in the local function table functions_table.
static lg::log_domain log_formula_ai("ai/engine/fai")
#define DEFINE_FAI_FUNCTION(name, min_args, max_args)
const unit_type * unit_type_
const std::vector< node > & nodes
#define DECLARE_FAI_FUNCTION(name)
unsigned in
If equal to search_counter, the node is off the list.
static bool operator<(const placing_info &a, const placing_info &b)
unit_alignments::type alignment() const
The alignment of this unit.
int damage_from(const attack_type &attack, bool attacker, const map_location &loc, const_attack_ptr weapon=nullptr) const
Calculates the damage this unit would take from a certain attack.
attack_itors attacks()
Gets an iterator over this unit's attacks.
int movement_cost(const t_translation::terrain_code &terrain) const
Get the unit's movement cost on a particular terrain.
bool is_fearless() const
Gets whether this unit is fearless - ie, unaffected by time of day.
T end(const std::pair< T, T > &p)
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).
constexpr int round_damage(int base_damage, int bonus, int divisor)
round (base_damage * bonus / divisor) to the closest integer, but up or down towards base_damage
A small explanation about what's going on here: Each action has access to two game_info objects First...
std::multimap< map_location, map_location > move_map
The standard way in which a map of possible moves is recorded.
std::map< map_location, pathfind::paths > moves_map
The standard way in which a map of possible movement routes to location is recorded.
utils::optional< std::string > get_wml_location(const std::string &path, const utils::optional< std::string > ¤t_dir)
Returns a translated path to the actual file or directory, if it exists.
std::string read_file(const std::string &fname)
Basic disk I/O - read file.
plain_route a_star_search(const map_location &src, const map_location &dst, double stop_at, const cost_calculator &calc, const std::size_t width, const std::size_t height, const teleport_map *teleports, bool border)
std::size_t size(std::string_view str)
Length in characters of a UTF-8 string.
std::size_t index(std::string_view str, const std::size_t index)
Codepoint index corresponding to the nth character in a UTF-8 string.
auto * find(Container &container, const Value &value)
Convenience wrapper for using find on a container without needing to comare to end()
std::string::const_iterator iterator
formula_debugger * add_debug_info(formula_debugger *fdb, int arg_number, const std::string &f_name)
std::shared_ptr< formula > formula_ptr
std::shared_ptr< function_expression > function_expression_ptr
This module contains various pathfinding functions and utilities.
static config unit_moves(const reports::context &rc, const unit *u, bool is_visible_unit)
rect dst
Location on the final composed sheet.
rect src
Non-transparent portion of the surface to compose.
std::string filename
Filename.
The basic class for representing 8-bit RGB or RGBA colour values.
Encapsulates the map of the game.
static const map_location & null_location()
Function which only uses terrain, ignoring shroud, enemies, etc.
Object which contains all the possible locations a unit can move to, with associated best routes to t...
Structure which holds a single route between one location and another.
std::vector< map_location > steps
A terrain string which is converted to a terrain is a string with 1 or 2 layers the layers are separa...
pointer get_shared_ptr() const
This is exactly the same as operator-> but it's slightly more readable, and can replace &*iter syntax...
static map_location::direction n
static const unit_type & get_unit_type(const std::string &type_id)
Converts a string ID to a unit_type.