46 #define LOG_AI LOG_STREAM(info, log_formula_ai)
47 #define WRN_AI LOG_STREAM(warn, log_formula_ai)
48 #define ERR_AI LOG_STREAM(err, log_formula_ai)
61 auto unit = arg.try_convert<unit_callable>();
99 #define DEFINE_FAI_FUNCTION(name, min_args, max_args) \
100 class name##_function : public function_expression \
103 explicit name##_function(const args_list& args, const formula_ai& ai) \
104 : function_expression(#name, args, min_args, max_args), ai_(ai) \
109 const formula_ai& ai_; \
110 variant execute(const formula_callable& variables, formula_debugger* fdb) const; \
113 variant name##_function::execute(const formula_callable& variables, formula_debugger* fdb) const
117 const map_location loc = args()[0]->evaluate(variables,
add_debug_info(fdb, 0,
"distance_to_nearest_unowned_village:location")).convert_to<location_callable>()->loc();
121 for(std::vector<map_location>::const_iterator
i = villages.begin();
i != villages.end(); ++
i) {
123 if(distance < best) {
124 if(my_villages.count(*
i) == 0) {
130 return variant(best);
133 static unsigned search_counter;
138 indexer(
int a,
int b) :
w(
a),
h(
b) { }
140 return loc.
y *
w + loc.
x;
176 comp(
const std::vector<node>&
n) :
nodes(
n) { }
177 bool operator()(
int l,
int r)
const {
182 void find_movemap(
const unit_adapter& u,
const map_location& loc,
183 std::vector<int>& scores,
bool allow_teleport,
const formula_ai&
ai_)
185 const std::set<map_location>& teleports = allow_teleport ?
ai_.
current_team().
villages() : std::set<map_location>();
189 std::vector<map_location> locs(6 + teleports.size());
190 std::copy(teleports.begin(), teleports.end(), locs.begin() + 6);
193 if (search_counter == 0) search_counter = 2;
195 static std::vector<node>
nodes;
196 nodes.resize(map.
w() * map.
h());
198 indexer
index(map.
w(), map.
h());
199 comp node_comp(
nodes);
203 pq.push_back(
index(loc));
204 while (!pq.empty()) {
205 node&
n =
nodes[pq.front()];
206 std::pop_heap(pq.begin(), pq.end(), node_comp);
208 n.in = search_counter;
211 for (
int i = teleports.count(
n.loc_) ? locs.size() : 6;
i-- > 0;) {
212 if (!locs[
i].valid(map.
w(), map.
h()))
continue;
215 bool next_visited = next.in - search_counter <= 1u;
219 if (next_visited && !(
n < next))
continue;
220 const int move_cost = u.movement_cost(map[locs[
i]]);
222 node
t = node(
n.movement_cost_ + move_cost, locs[
i]);
224 if (next_visited && !(
t < next))
continue;
226 bool in_list = next.in == search_counter + 1;
227 t.in = search_counter + 1;
232 std::push_heap(pq.begin(), std::find(pq.begin(), pq.end(),
index(locs[
i])) + 1, node_comp);
235 pq.push_back(
index(locs[
i]));
236 std::push_heap(pq.begin(), pq.end(), node_comp);
241 for (
int x = 0; x < map.
w(); ++x) {
242 for (
int y = 0; y < map.
h(); ++y)
244 int i = y * map.
w() + x;
246 scores[
i] = scores[
i] +
n.movement_cost_;
258 const variant units_input = args()[0]->evaluate(variables,fdb);
259 const variant leaders_input = args()[1]->evaluate(variables,fdb);
261 int enemy_tolerance = 3;
262 if( args().
size() > 2 )
263 enemy_tolerance = args()[2]->evaluate(variables,fdb).as_int();
265 int enemy_border_tolerance = 5;
266 if( args().
size() > 3 )
267 enemy_border_tolerance = args()[3]->evaluate(variables,fdb).as_int();
269 int ally_tolerance = 3;
270 if( args().
size() > 4 )
271 ally_tolerance = args()[4]->evaluate(variables,fdb).as_int();
273 if( !units_input.is_list() )
276 std::size_t number_of_teams = units_input.num_elements();
278 std::vector< std::vector<int>> scores( number_of_teams );
280 for( std::size_t
i = 0;
i< number_of_teams; ++
i)
281 scores[
i].resize(
w*
h);
291 for(std::size_t side = 0 ; side < units_input.num_elements() ; ++side) {
292 if( leaders_input[side].is_empty() )
295 const map_location loc = leaders_input[side][0].convert_to<location_callable>()->loc();
296 const variant units_of_side = units_input[side];
298 for(std::size_t unit_it = 0 ; unit_it < units_of_side.num_elements() ; ++unit_it) {
299 unit_adapter
unit(units_of_side[unit_it]);
300 find_movemap(
unit, loc, scores[side],
true,
ai_ );
304 std::size_t
index = 0;
305 for( std::vector< std::vector<int>>::
iterator i = scores.begin() ;
i != scores.end() ; ++
i) {
307 if(units_input[
index].num_elements() != 0) {
308 *j /= units_input[
index].num_elements();
317 std::map<variant, variant> res;
321 std::vector<int> enemies;
322 std::vector<int> allies;
324 for(std::size_t side = 0 ; side < units_input.num_elements() ; ++side) {
325 if( side == current_side)
329 if( !leaders_input[side].is_empty() )
330 enemies.push_back(side);
332 if( !leaders_input[side].is_empty() )
333 allies.push_back(side);
339 for (
int x = 0; x <
w; ++x) {
340 for (
int y = 0; y <
h; ++y)
344 bool enemy_border =
false;
346 if( scores[current_side][
i] > 98 )
349 for (
int side : enemies) {
350 int diff = scores[current_side][
i] - scores[side][
i];
351 if ( diff > enemy_tolerance) {
354 }
else if( std::abs(diff) < enemy_border_tolerance )
359 for (
int side : allies) {
360 if ( scores[current_side][
i] - scores[side][
i] > ally_tolerance ) {
369 res.emplace(variant(std::make_shared<location_callable>(
map_location(x, y))), variant(scores[0][
i] + 10000));
371 res.emplace(variant(std::make_shared<location_callable>(
map_location(x, y))), variant(scores[0][
i]));
380 const map_location loc = args()[0]->evaluate(variables,
add_debug_info(fdb, 0,
"nearest_loc:location")).convert_to<location_callable>()->loc();
381 variant
items = args()[1]->evaluate(variables,
add_debug_info(fdb,1,
"nearest_loc:locations"));
385 for(std::size_t
i = 0;
i <
items.num_elements(); ++
i) {
390 if(distance < best) {
397 return variant(std::make_shared<location_callable>(
items[best_i].convert_to<location_callable>()->loc()));
407 const args_list& arguments = args();
408 const variant var0 = arguments[0]->evaluate(variables,
add_debug_info(fdb,0,
"run_file:file"));
409 const std::string filename = var0.string_cast();
414 ERR_AI <<
"run_file : not found [" << filename <<
"]";
422 ERR_AI <<
"run_file : unable to create formula";
425 return parsed_formula->evaluate(variables,
add_debug_info(fdb,-1,
"run_file:formula_from_file"));
430 const map_location starting_loc = args()[0]->evaluate(variables,
add_debug_info(fdb, 0,
"castle_locs:location")).convert_to<location_callable>()->loc();
433 std::set< map_location > visited_locs;
434 std::queue< map_location > queued_locs;
436 queued_locs.push(starting_loc);
438 while( !queued_locs.empty() ) {
442 if ( visited_locs.find( loc ) != visited_locs.end() )
445 visited_locs.insert(loc);
448 if (
resources::gameboard->map().on_board(adj) && visited_locs.find( adj ) == visited_locs.end() ) {
451 queued_locs.push(adj);
459 visited_locs.erase(starting_loc);
461 std::vector<variant> res;
463 res.emplace_back(std::make_shared<location_callable>( ml ));
478 variant u = args()[0]->evaluate(variables,
add_debug_info(fdb,0,
"timeofday_modifier:unit"));
484 auto u_call = u.try_convert<unit_callable>();
490 const unit& un = u_call->get_unit();
494 if(args().
size()==2) {
495 loc = args()[1]->evaluate(variables,
add_debug_info(fdb, 1,
"timeofday_modifier:location")).convert_to<location_callable>()->loc();
499 loc = u_call->get_location();
507 const map_location loc = args()[0]->evaluate(variables,
add_debug_info(fdb, 0,
"nearest_keep:location")).convert_to<location_callable>()->loc();
514 for(
int i = 0 ;
i <
size; ++
i) {
535 const map_location loc = args()[0]->evaluate(variables,
add_debug_info(fdb, 0,
"suitable_keep:location")).convert_to<location_callable>()->loc();
538 if (u == units.
end()){
542 return variant(std::make_shared<location_callable>(
ai_.
suitable_keep(loc,unit_paths)));
547 std::vector<variant> vars;
550 if(args().
size()==1) {
551 const gamemap& m = args()[0]->evaluate(variables,
add_debug_info(fdb, 0,
"find_shroud:gamemap")).convert_to<gamemap_callable>()->get_gamemap();
559 for(
int i = 0;
i <
w; ++
i)
560 for(
int j = 0; j <
h; ++j) {
562 vars.emplace_back(std::make_shared<location_callable>(
map_location(
i, j)));
565 return variant(vars);
570 std::vector<variant> vars;
571 const map_location loc = args()[0]->evaluate(variables,
add_debug_info(fdb, 0,
"close_enemies:location")).convert_to<location_callable>()->loc();
572 int range_s = args()[1]->evaluate(variables,
add_debug_info(fdb,1,
"close_enemies:distance")).as_int();
574 WRN_AI <<
"close_enemies_function: range is negative (" << range_s <<
")";
577 std::size_t range =
static_cast<std::size_t
>(range_s);
583 vars.emplace_back(std::make_shared<unit_callable>(*un));
588 return variant(vars);
593 std::vector<variant> vars;
595 if (args().
size() > 3) weapon = args()[3]->evaluate(variables,
add_debug_info(fdb,3,
"calculate_outcome:weapon")).as_int();
600 args()[0]->evaluate(variables,
add_debug_info(fdb, 0,
"calculate_outcome:attacker_current_location")).convert_to<location_callable>()->loc();
601 if(units.
count(attacker_location) == 0) {
602 ERR_AI <<
"Performing calculate_outcome() with non-existent attacker at (" <<
603 attacker_location.
wml_x() <<
"," << attacker_location.
wml_y() <<
")";
608 args()[2]->evaluate(variables,
add_debug_info(fdb, 2,
"calculate_outcome:defender_location")).convert_to<location_callable>()->loc();
609 if(units.
count(defender_location) == 0) {
610 ERR_AI <<
"Performing calculate_outcome() with non-existent defender at (" <<
611 defender_location.
wml_x() <<
"," << defender_location.
wml_y() <<
")";
615 battle_context bc(units, args()[1]->evaluate(variables,
add_debug_info(fdb, 1,
"calculate_outcome:attacker_attack_location")).convert_to<location_callable>()->loc(),
616 defender_location, weapon, -1, 1.0,
nullptr, units.
find(attacker_location).
get_shared_ptr());
617 std::vector<double> hp_dist = bc.get_attacker_combatant().hp_dist;
620 std::vector<variant> hitLeft;
621 std::vector<variant> prob;
622 while (it != hp_dist.end()) {
624 hitLeft.emplace_back(
i);
625 prob.emplace_back(
static_cast<int>(*it*10000));
630 std::vector<variant> status;
631 if (bc.get_attacker_combatant().poisoned != 0)
632 status.emplace_back(
"Poisoned");
633 if (bc.get_attacker_combatant().slowed != 0)
634 status.emplace_back(
"Slowed");
635 if (bc.get_defender_stats().petrifies &&
static_cast<unsigned int>(hitLeft[0].as_int()) != bc.get_attacker_stats().hp)
636 status.emplace_back(
"Stoned");
637 if (bc.get_defender_stats().plagues && hitLeft[0].as_int() == 0)
638 status.emplace_back(
"Zombiefied");
639 vars.emplace_back(std::make_shared<outcome_callable>(hitLeft, prob, status));
643 hp_dist = bc.get_defender_combatant().hp_dist;
644 it = hp_dist.begin();
646 while (it != hp_dist.end()) {
648 hitLeft.emplace_back(
i);
649 prob.emplace_back(
static_cast<int>(*it*10000));
654 if (bc.get_defender_combatant().poisoned != 0)
655 status.emplace_back(
"Poisoned");
656 if (bc.get_defender_combatant().slowed != 0)
657 status.emplace_back(
"Slowed");
658 if (bc.get_attacker_stats().petrifies &&
static_cast<unsigned int>(hitLeft[0].as_int()) != bc.get_defender_stats().hp)
659 status.emplace_back(
"Stoned");
660 if (bc.get_attacker_stats().plagues && hitLeft[0].as_int() == 0)
661 status.emplace_back(
"Zombiefied");
662 vars.emplace_back(std::make_shared<outcome_callable>(hitLeft, prob, status));
663 return variant(vars);
668 variant attack = args()[0]->evaluate(variables,
add_debug_info(fdb,0,
"outcomes:attack"));
676 std::vector<variant> vars;
677 if(analysis->chance_to_kill > 0.0) {
680 vars.emplace_back(std::make_shared<position_callable>(
static_cast<int>(analysis->chance_to_kill*100)));
684 if(analysis->chance_to_kill < 1.0) {
686 vars.emplace_back(std::make_shared<position_callable>(
static_cast<int>(100 - analysis->chance_to_kill*100)));
689 return variant(vars);
694 variant act = args()[0]->evaluate(variables,
add_debug_info(fdb,0,
"rate_action:action"));
702 const std::string
id = args()[0]->evaluate(variables,
add_debug_info(fdb,0,
"recall:id")).as_string();
704 if(args().
size() >= 2) {
705 loc = args()[1]->evaluate(variables,
add_debug_info(fdb, 1,
"recall:location")).convert_to<location_callable>()->loc();
708 return variant(std::make_shared<recall_callable>(loc,
id));
713 const std::string
type = args()[0]->evaluate(variables,
add_debug_info(fdb,0,
"recruit:type")).as_string();
715 if(args().
size() >= 2) {
716 loc = args()[1]->evaluate(variables,
add_debug_info(fdb, 1,
"recruit:location")).convert_to<location_callable>()->loc();
719 return variant(std::make_shared<recruit_callable>(loc,
type));
725 std::vector<variant> locations;
727 const map_location src = args()[0]->evaluate(variables,
add_debug_info(fdb, 0,
"shortest_path:src")).convert_to<location_callable>()->loc();
728 const map_location dst = args()[1]->evaluate(variables,
add_debug_info(fdb, 1,
"shortest_path:dst")).convert_to<location_callable>()->loc();
732 return variant(locations);
734 if(args().
size() > 2)
735 unit_loc = args()[2]->evaluate(variables,
add_debug_info(fdb,2,
"shortest_path:unit_location")).convert_to<location_callable>()->loc();
742 std::ostringstream str;
743 str <<
"shortest_path function: expected unit at location (" << (unit_loc.
wml_x()) <<
"," << (unit_loc.
wml_y()) <<
")";
744 throw formula_error( str.str(),
"",
"", 0);
751 if( route.
steps.size() < 2 ) {
752 return variant(locations);
755 for (std::vector<map_location>::const_iterator loc_iter = route.
steps.begin() + 1 ; loc_iter !=route.
steps.end(); ++loc_iter) {
756 locations.emplace_back(std::make_shared<location_callable>(*loc_iter));
759 return variant(locations);
764 std::vector<variant> locations;
766 const map_location src = args()[0]->evaluate(variables,
add_debug_info(fdb, 0,
"simplest_path:src")).convert_to<location_callable>()->loc();
767 const map_location dst = args()[1]->evaluate(variables,
add_debug_info(fdb, 1,
"simplest_path:dst")).convert_to<location_callable>()->loc();
771 return variant(locations);
773 if(args().
size() > 2)
774 unit_loc = args()[2]->evaluate(variables,
add_debug_info(fdb, 2,
"simplest_path:unit_location")).convert_to<location_callable>()->loc();
781 std::ostringstream str;
782 str <<
"simplest_path function: expected unit at location (" << (unit_loc.
wml_x()) <<
"," << (unit_loc.
wml_y()) <<
")";
783 throw formula_error( str.str(),
"",
"", 0);
792 if( route.
steps.size() < 2 ) {
793 return variant(locations);
796 for (std::vector<map_location>::const_iterator loc_iter = route.
steps.begin() + 1 ; loc_iter !=route.
steps.end(); ++loc_iter) {
798 locations.emplace_back(std::make_shared<location_callable>(*loc_iter));
804 return variant(locations);
810 const map_location src = args()[0]->evaluate(variables,
add_debug_info(fdb, 0,
"next_hop:src")).convert_to<location_callable>()->loc();
811 const map_location dst = args()[1]->evaluate(variables,
add_debug_info(fdb, 1,
"next_hop:dst")).convert_to<location_callable>()->loc();
817 if(args().
size() > 2)
818 unit_loc = args()[2]->evaluate(variables,
add_debug_info(fdb, 2,
"next_hop:unit_location")).convert_to<location_callable>()->loc();
825 std::ostringstream str;
826 str <<
"next_hop function: expected unit at location (" << (unit_loc.
wml_x()) <<
"," << (unit_loc.
wml_y()) <<
")";
827 throw formula_error( str.str(),
"",
"", 0);
834 if( route.
steps.size() < 2 ) {
840 const ai::moves_map::const_iterator& p_it = possible_moves.find(unit_loc);
841 if (p_it==possible_moves.end() ) {
845 for (std::vector<map_location>::const_iterator loc_iter = route.
steps.begin() + 1 ; loc_iter !=route.
steps.end(); ++loc_iter) {
847 if (p_it->second.destinations.find(*loc_iter) != p_it->second.destinations.end() ) {
856 return variant(std::make_shared<location_callable>(loc));
861 const map_location src = args()[0]->evaluate(variables,
add_debug_info(fdb, 0,
"move:src")).convert_to<location_callable>()->loc();
862 const map_location dst = args()[1]->evaluate(variables,
add_debug_info(fdb, 1,
"move:dst")).convert_to<location_callable>()->loc();
863 LOG_AI <<
"move(): " << src <<
", " << dst <<
")";
864 return variant(std::make_shared<move_callable>(src, dst));
869 const map_location src = args()[0]->evaluate(variables,
add_debug_info(fdb, 0,
"move_partial:src")).convert_to<location_callable>()->loc();
870 const map_location dst = args()[1]->evaluate(variables,
add_debug_info(fdb, 1,
"move_partial:dst")).convert_to<location_callable>()->loc();
871 LOG_AI <<
"move_partial(): " << src <<
", " << dst <<
")";
872 return variant(std::make_shared<move_partial_callable>(src, dst));
877 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()));
884 if(args().
size() == 1 && args()[0]->evaluate(variables).as_string() !=
"human")
886 return variant(std::make_shared<fallback_callable>());
891 const map_location move_from = args()[0]->evaluate(variables,
add_debug_info(fdb, 0,
"attack:move_from")).convert_to<location_callable>()->loc();
892 const map_location src = args()[1]->evaluate(variables,
add_debug_info(fdb, 1,
"attack:src")).convert_to<location_callable>()->loc();
893 const map_location dst = args()[2]->evaluate(variables,
add_debug_info(fdb, 2,
"attack:dst")).convert_to<location_callable>()->loc();
894 const int weapon = args().size() == 4 ? args()[3]->evaluate(variables,
add_debug_info(fdb,3,
"attack:weapon")).as_int() : -1;
896 ERR_AI <<
"AI ERROR: Formula produced illegal attack: " << move_from <<
" -> " << src <<
" -> " << dst;
899 return variant(std::make_shared<attack_callable>(move_from, src, dst, weapon));
904 const args_list& arguments = args();
905 const variant var0 = arguments[0]->evaluate(variables,fdb);
906 const variant var1 = arguments[1]->evaluate(variables,fdb);
908 const map_location location = var0.convert_to<location_callable>()->loc();
910 if( var1.is_string() )
911 text = var1.as_string();
913 text = var1.to_debug_string();
916 std::string team_name;
921 res =
gui->labels().set_label(location, text,
ai_.
get_side() - 1, team_name, color);
925 std::vector<variant> result;
926 result.push_back(var0);
927 result.push_back(var1);
928 return variant(result);
933 const gamemap& m = args()[0]->evaluate(variables,
add_debug_info(fdb, 0,
"is_village:map")).convert_to<gamemap_callable>()->get_gamemap();
936 if(args().
size() == 2) {
937 loc = args()[1]->evaluate(variables,
add_debug_info(fdb, 1,
"is_village:location")).convert_to<location_callable>()->loc();
948 const gamemap& m = args()[0]->evaluate(variables,
add_debug_info(fdb, 0,
"is_unowned_village:map")).convert_to<gamemap_callable>()->get_gamemap();
952 if(args().
size() == 2) {
953 loc = args()[1]->evaluate(variables,
add_debug_info(fdb, 1,
"is_unowned_village:location")).convert_to<location_callable>()->loc();
959 if(m.
is_village(loc) && (my_villages.count(loc)==0) ) {
960 return variant(
true);
962 return variant(
false);
968 variant res = args()[0]->evaluate(variables,
add_debug_info(fdb,0,
"unit_moves:unit_location"));
969 std::vector<variant> vars;
971 return variant(vars);
974 const map_location& loc = res.convert_to<location_callable>()->loc();
976 typedef ai::move_map::const_iterator Itor;
977 std::pair<Itor,Itor> range = srcdst.equal_range(loc);
979 for(Itor
i = range.first;
i != range.second; ++
i) {
980 vars.emplace_back(std::make_shared<location_callable>(
i->second));
983 return variant(vars);
988 std::vector<variant> vars;
989 variant dstsrc_var = args()[0]->evaluate(variables,
add_debug_info(fdb,0,
"units_can_reach:possible_move_list"));
990 const ai::move_map& dstsrc = dstsrc_var.convert_to<move_map_callable>()->dstsrc();
991 std::pair<ai::move_map::const_iterator,ai::move_map::const_iterator> range =
992 dstsrc.equal_range(args()[1]->evaluate(variables,
add_debug_info(fdb, 1,
"units_can_reach:possible_move_list")).convert_to<location_callable>()->loc());
993 while(range.first != range.second) {
996 vars.emplace_back(std::make_shared<unit_callable>(*un));
1000 return variant(vars);
1005 variant res = args()[0]->evaluate(variables,
add_debug_info(fdb,0,
"is_avoided_location:location"));
1009 const map_location& loc = res.convert_to<location_callable>()->loc();
1015 variant u1 = args()[0]->evaluate(variables,
add_debug_info(fdb,0,
"max_possible_damage:unit1"));
1016 variant u2 = args()[1]->evaluate(variables,
add_debug_info(fdb,1,
"max_possible_damage:unit2"));
1017 if(u1.is_null() || u2.is_null()) {
1021 unit_adapter u_attacker(u1), u_defender(u2);
1023 for(
const attack_type& atk : u_attacker.attacks()) {
1024 const int dmg =
round_damage(atk.damage(), u_defender.damage_from(atk), 100) * atk.num_attacks();
1028 return variant(best);
1032 std::pair<int, int> best_melee_and_ranged_attacks(unit_adapter attacker, unit_adapter defender) {
1033 int highest_melee_damage = 0;
1034 int highest_ranged_damage = 0;
1036 for (
const attack_type &attack : attacker.attacks()) {
1037 const int dmg =
round_damage(attack.damage(), defender.damage_from(attack), 100) * attack.num_attacks();
1038 if (attack.range() ==
"melee") {
1039 highest_melee_damage = std::max(highest_melee_damage, dmg);
1041 highest_ranged_damage = std::max(highest_ranged_damage, dmg);
1045 return std::pair(highest_melee_damage, highest_ranged_damage);
1051 variant u1 = args()[0]->evaluate(variables,
add_debug_info(fdb,0,
"max_possible_damage_with_retaliation:unit1"));
1052 variant u2 = args()[1]->evaluate(variables,
add_debug_info(fdb,1,
"max_possible_damage_with_retaliation:unit2"));
1054 if(u1.is_null() || u2.is_null()) {
1058 unit_adapter attacker(u1);
1059 unit_adapter defender(u2);
1062 std::pair<int, int> best_attacker_attacks = best_melee_and_ranged_attacks(attacker, defender);
1063 std::pair<int, int> best_defender_attacks = best_melee_and_ranged_attacks(defender, attacker);
1065 std::vector<variant> vars;
1066 vars.emplace_back(best_attacker_attacks.first);
1067 vars.emplace_back(best_attacker_attacks.second);
1068 vars.emplace_back(best_defender_attacks.first);
1069 vars.emplace_back(best_defender_attacks.second);
1071 return variant(vars);
1074 template<
typename T>
1075 class ai_formula_function :
public formula_function {
1079 ai_formula_function(
const std::string& name,
ai::formula_ai&
ai) : formula_function(name),
ai_(
ai) {}
1081 return std::make_shared<T>(args,
ai_);
1089 #define DECLARE_FAI_FUNCTION(name) \
1090 add_function(#name, std::make_shared<ai_formula_function<name##_function>>(#name, ai))
1129 #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.
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 attack_type &attack) const
Returns the resistance against the indicated attack.
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
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.
std::string get_wml_location(const std::string &filename, const std::string ¤t_dir)
Returns a complete path to the actual WML file or directory or an empty string if the file isn't pres...
std::string read_file(const std::string &fname)
Basic disk I/O - read file.
const std::vector< std::string > items
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 index(const std::string &str, const std::size_t index)
Codepoint index corresponding to the nth character in a UTF-8 string.
std::size_t size(const std::string &str)
Length in characters of a UTF-8 string.
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)
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.