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();
120 const std::set<map_location>& my_villages =
ai_.current_team().villages();
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;
156 : movement_cost_(moves)
170 return movement_cost_ < o.movement_cost_;
176 comp(
const std::vector<node>&
n) : nodes(n) { }
177 bool operator()(
int l,
int r)
const {
178 return nodes[r] < nodes[l];
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);
201 nodes[
index(loc)] = node(0, loc);
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;
214 node& next = nodes[
index(locs[
i])];
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;
245 const node &
n = nodes[
i];
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;
319 std::size_t current_side =
ai_.get_side() - 1 ;
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)
328 if(
ai_.current_team().is_enemy(side+1) ) {
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) {
387 const map_location move_loc = items[
i].convert_to<location_callable>()->loc();
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 <<
"]";
420 formula_ptr parsed_formula =
ai_.create_optional_formula(formula_string);
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();
512 int size =
ai_.get_keeps_cache().num_elements();
514 for(
int i = 0 ;
i <
size; ++
i) {
515 int distance =
distance_between(loc,
ai_.get_keeps_cache()[
i].convert_to<location_callable>()->loc() );
524 return variant(std::make_shared<location_callable>(
ai_.get_keeps_cache()[best_i].convert_to<location_callable>()->loc()));
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);
582 if (un->side() !=
ai_.get_side()) {
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());
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;
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();
949 const std::set<map_location>& my_villages =
ai_.current_team().villages();
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();
1010 return variant(
ai_.get_avoid().match(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
std::vector< double > hp_dist
Resulting probability distribution (might be not as large as max_hp)
static display * get_singleton()
Returns the display object if a display object exists.
const std::vector< node > & nodes
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
This class represents a single unit of a specific type.
int movement_cost(const t_translation::terrain_code &terrain) const
Get the unit's movement cost on a particular terrain.
const combatant & get_attacker_combatant(const combatant *prev_def=nullptr)
Get the simulation results.
static const int UNREACHABLE
Magic value that signifies a hex is unreachable.
formula_debugger * add_debug_info(formula_debugger *fdb, int arg_number, const std::string &f_name)
virtual const gamemap & map() const override
const std::vector< std::string > items
A terrain string which is converted to a terrain is a string with 1 or 2 layers the layers are separa...
const terrain_type & get_terrain_info(const t_translation::terrain_code &terrain) const
int resistance_against(const attack_type &attack) const
Returns the resistance against the indicated attack.
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 ...
ai_function_symbol_table(ai::formula_ai &ai)
A single unit type that the player may recruit.
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.
unsigned in
If equal to search_counter, the node is off the list.
A small explanation about what's going on here: Each action has access to two game_info objects First...
std::size_t size(const std::string &str)
Length in characters of a UTF-8 string.
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.
std::vector< map_location > steps
int w() const
Effective map width.
const movetype & movement_type() const
Structure which holds a single route between one location and another.
const terrain_label * set_label(const map_location &loc, const t_string &text, const int creator=-1, const std::string &team="", const color_t color=font::NORMAL_COLOR, const bool visible_in_fog=true, const bool visible_in_shroud=false, const bool immutable=false, const std::string &category="", const t_string &tooltip="")
std::shared_ptr< function_expression > function_expression_ptr
Encapsulates the map of the game.
The basic class for representing 8-bit RGB or RGBA colour values.
Computes the statistics of a battle between an attacker and a defender unit.
map_display and display: classes which take care of displaying the map and game-data on the screen...
Function which only uses terrain, ignoring shroud, enemies, etc.
std::size_t count(const map_location &loc) const
#define DEFINE_FAI_FUNCTION(name, min_args, max_args)
std::string read_file(const std::string &fname)
Basic disk I/O - read file.
unit_alignments::type alignment() const
The alignment of this unit.
Encapsulates the map of the game.
unit_iterator find(std::size_t id)
pointer get_shared_ptr() const
This is exactly the same as operator-> but it's slightly more readable, and can replace &*iter syntax...
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...
static bool operator<(const placing_info &a, const placing_info &b)
#define DECLARE_FAI_FUNCTION(name)
attack_itors attacks()
Gets an iterator over this unit's attacks.
Declarations for File-IO.
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.
static lg::log_domain log_formula_ai("ai/engine/fai")
int movement_cost(const t_translation::terrain_code &terrain, bool slowed=false) const
Returns the cost to move through the indicated terrain.
#define DECLARE_WFL_FUNCTION(name)
Declares a function name in the local function table functions_table.
static const unit_type & get_unit_type(const std::string &type_id)
Converts a string ID to a unit_type.
bool is_village(const map_location &loc) const
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.
To store label data Class implements logic for rendering.
bool is_fearless() const
Gets whether this unit is fearless - ie, unaffected by time of day.
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...
const std::vector< map_location > & villages() const
Return a list of the locations of villages on the map.
static color_t get_side_color(int side)
#define DEFINE_WFL_FUNCTION(name, min_args, max_args)
Helper macro to declare an associated class for a WFL function.
const unit_type * unit_type_
Standard logging facilities (interface).
static config unit_moves(reports::context &rc, const unit *u, bool is_visible_unit)
Object which contains all the possible locations a unit can move to, with associated best routes to t...
static const map_location & null_location()
Container associating units to locations.
const_attack_itors attacks() const
boost::iterator_range< boost::indirect_iterator< attack_list::const_iterator > > const_attack_itors
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)
static map_location::DIRECTION n
int h() const
Effective map height.
This module contains various pathfinding functions and utilities.
std::string::const_iterator iterator
void add_label(const terrain_label *)
std::shared_ptr< formula > formula_ptr