The Battle for Wesnoth  1.15.5+dev
function_table.cpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2009 - 2018 by Bartosz Waresiak <dragonking@o2.pl>
3  Part of the Battle for Wesnoth Project https://www.wesnoth.org/
4 
5  This program is free software; you can redistribute it and/or modify
6  it under the terms of the GNU General Public License as published by
7  the Free Software Foundation; either version 2 of the License, or
8  (at your option) any later version.
9  This program is distributed in the hope that it will be useful,
10  but WITHOUT ANY WARRANTY.
11 
12  See the COPYING file for more details.
13 */
14 
15 
16 #include <queue>
17 #include <set>
18 #include <utility>
19 #include <vector>
20 
21 #include "ai/formula/ai.hpp"
24 
25 #include "ai/default/contexts.hpp"
26 
28 #include "attack_prediction.hpp"
29 #include "filesystem.hpp"
30 #include "game_board.hpp"
31 #include "display.hpp"
32 #include "log.hpp"
33 #include "map/label.hpp"
34 #include "map/map.hpp"
35 #include "pathfind/teleport.hpp"
36 #include "replay.hpp"
37 #include "resources.hpp"
38 #include "color.hpp"
39 #include "terrain/filter.hpp"
40 #include "units/unit.hpp"
41 #include "units/types.hpp"
42 #include "pathfind/pathfind.hpp"
43 
44 static lg::log_domain log_formula_ai("ai/engine/fai");
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)
48 
49 namespace wfl {
50 using ai::formula_ai;
51 
52 namespace {
53 
54 /*
55  * unit adapters let us treat unit and unit_type the same if we want to get access to attacks or movement cost
56  */
57 class unit_adapter {
58  public:
59  unit_adapter(const variant& arg) : unit_type_(), unit_() {
60  auto unit = arg.try_convert<unit_callable>();
61 
62  if (unit) {
63  unit_ = &unit->get_unit();
64  } else {
65  unit_type_ = &(arg.convert_to<unit_type_callable>()->get_unit_type());
66  }
67  }
68 
69  int damage_from(const attack_type& attack) const {
70  if(unit_type_ != nullptr) {
72  } else {
73  return unit_->damage_from(attack, false, map_location());
74  }
75  }
76 
77  const_attack_itors attacks() const {
78  if(unit_type_ != nullptr) {
79  return unit_type_->attacks();
80  } else {
81  return unit_->attacks();
82  }
83  }
84 
85  int movement_cost(const t_translation::terrain_code & terrain) const {
86  if(unit_type_ != nullptr) {
87  return unit_type_->movement_type().movement_cost(terrain);
88  } else {
89  return unit_->movement_cost(terrain);
90  }
91  }
92 
93 
94  private:
96  const unit* unit_;
97 };
98 
99 #define DEFINE_FAI_FUNCTION(name, min_args, max_args) \
100  class name##_function : public function_expression \
101  { \
102  public: \
103  explicit name##_function(const args_list& args, const formula_ai& ai) \
104  : function_expression(#name, args, min_args, max_args), ai_(ai) \
105  { \
106  } \
107  \
108  private: \
109  const formula_ai& ai_; \
110  variant execute(const formula_callable& variables, formula_debugger* fdb) const; \
111  }; \
112  \
113  variant name##_function::execute(const formula_callable& variables, formula_debugger* fdb) const
114 
115 
116 DEFINE_FAI_FUNCTION(distance_to_nearest_unowned_village, 1, 1)
117 {
118  const map_location loc = args()[0]->evaluate(variables, add_debug_info(fdb, 0, "distance_to_nearest_unowned_village:location")).convert_to<location_callable>()->loc();
119  int best = 1000000;
120  const std::vector<map_location>& villages = resources::gameboard->map().villages();
121  const std::set<map_location>& my_villages = ai_.current_team().villages();
122  for(std::vector<map_location>::const_iterator i = villages.begin(); i != villages.end(); ++i) {
123  int distance = distance_between(loc, *i);
124  if(distance < best) {
125  if(my_villages.count(*i) == 0) {
126  best = distance;
127  }
128  }
129  }
130 
131  return variant(best);
132 }
133 
134 static unsigned search_counter;
135 
136 namespace {
137  struct indexer {
138  int w, h;
139  indexer(int a, int b) : w(a), h(b) { }
140  int operator()(const map_location& loc) const {
141  return loc.y * w + loc.x;
142  }
143  };
144 
145  struct node {
148 
149  /**
150  * If equal to search_counter, the node is off the list.
151  * If equal to search_counter + 1, the node is on the list.
152  * Otherwise it is outdated.
153  */
154  unsigned in;
155 
156  node(int moves, const map_location &loc)
157  : movement_cost_(moves)
158  , loc_(loc)
159  , in(0)
160  {
161  }
162 
163  node()
164  : movement_cost_(0)
165  , loc_()
166  , in(0)
167  {
168  }
169 
170  bool operator<(const node& o) const {
171  return movement_cost_ < o.movement_cost_;
172  }
173  };
174 
175  struct comp {
176  const std::vector<node>& nodes;
177  comp(const std::vector<node>& n) : nodes(n) { }
178  bool operator()(int l, int r) const {
179  return nodes[r] < nodes[l];
180  }
181  };
182 
183  void find_movemap(const unit_adapter& u, const map_location& loc,
184  std::vector<int>& scores, bool allow_teleport, const formula_ai& ai_)
185  {
186  const std::set<map_location>& teleports = allow_teleport ? ai_.current_team().villages() : std::set<map_location>();
187 
188  const gamemap& map = resources::gameboard->map();
189 
190  std::vector<map_location> locs(6 + teleports.size());
191  std::copy(teleports.begin(), teleports.end(), locs.begin() + 6);
192 
193  search_counter += 2;
194  if (search_counter == 0) search_counter = 2;
195 
196  static std::vector<node> nodes;
197  nodes.resize(map.w() * map.h());
198 
199  indexer index(map.w(), map.h());
200  comp node_comp(nodes);
201 
202  nodes[index(loc)] = node(0, loc);
203  std::vector<int> pq;
204  pq.push_back(index(loc));
205  while (!pq.empty()) {
206  node& n = nodes[pq.front()];
207  std::pop_heap(pq.begin(), pq.end(), node_comp);
208  pq.pop_back();
209  n.in = search_counter;
210 
211  get_adjacent_tiles(n.loc_, locs.data());
212  for (int i = teleports.count(n.loc_) ? locs.size() : 6; i-- > 0;) {
213  if (!locs[i].valid(map.w(), map.h())) continue;
214 
215  node& next = nodes[index(locs[i])];
216  bool next_visited = next.in - search_counter <= 1u;
217 
218  // test if the current path to locs[i] is better than this one could possibly be.
219  // we do this a couple more times below
220  if (next_visited && !(n < next)) continue;
221  const int move_cost = u.movement_cost(map[locs[i]]);
222 
223  node t = node(n.movement_cost_ + move_cost, locs[i]);
224 
225  if (next_visited && !(t < next)) continue;
226 
227  bool in_list = next.in == search_counter + 1;
228  t.in = search_counter + 1;
229  next = t;
230 
231  // if already in the priority queue then we just update it, else push it.
232  if (in_list) {
233  std::push_heap(pq.begin(), std::find(pq.begin(), pq.end(), index(locs[i])) + 1, node_comp);
234  }
235  else {
236  pq.push_back(index(locs[i]));
237  std::push_heap(pq.begin(), pq.end(), node_comp);
238  }
239  }
240  }
241 
242  for (int x = 0; x < map.w(); ++x) {
243  for (int y = 0; y < map.h(); ++y)
244  {
245  int i = y * map.w() + x;
246  const node &n = nodes[i];
247  scores[i] = scores[i] + n.movement_cost_;
248  //std::cout << x << "," << y << ":" << n.movement_cost << std::endl;
249  }
250  }
251  }
252 }
253 
254 DEFINE_FAI_FUNCTION(calculate_map_ownership, 2, 5)
255 {
256  int w = resources::gameboard->map().w();
257  int h = resources::gameboard->map().h();
258 
259  const variant units_input = args()[0]->evaluate(variables,fdb);
260  const variant leaders_input = args()[1]->evaluate(variables,fdb);
261 
262  int enemy_tolerance = 3;
263  if( args().size() > 2 )
264  enemy_tolerance = args()[2]->evaluate(variables,fdb).as_int();
265 
266  int enemy_border_tolerance = 5;
267  if( args().size() > 3 )
268  enemy_border_tolerance = args()[3]->evaluate(variables,fdb).as_int();
269 
270  int ally_tolerance = 3;
271  if( args().size() > 4 )
272  ally_tolerance = args()[4]->evaluate(variables,fdb).as_int();
273 
274  if( !units_input.is_list() )
275  return variant();
276 
277  std::size_t number_of_teams = units_input.num_elements();
278 
279  std::vector< std::vector<int>> scores( number_of_teams );
280 
281  for( std::size_t i = 0; i< number_of_teams; ++i)
282  scores[i].resize(w*h);
283 
284  /* // TODO: Do we need this?
285  for(unit_map::const_iterator i = resources::gameboard->units().begin(); i != resources::gameboard->units().end(); ++i) {
286  unit_counter[i->second.side()-1]++;
287  unit_adapter unit(i->second);
288  find_movemap( resources::gameboard->map(), resources::gameboard->units(), unit, i->first, scores[i->second.side()-1], ai_.resources::gameboard->teams() , true );
289  }
290  */
291 
292  for(std::size_t side = 0 ; side < units_input.num_elements() ; ++side) {
293  if( leaders_input[side].is_empty() )
294  continue;
295 
296  const map_location loc = leaders_input[side][0].convert_to<location_callable>()->loc();
297  const variant units_of_side = units_input[side];
298 
299  for(std::size_t unit_it = 0 ; unit_it < units_of_side.num_elements() ; ++unit_it) {
300  unit_adapter unit(units_of_side[unit_it]);
301  find_movemap( unit, loc, scores[side], true, ai_ );
302  }
303  }
304 
305  std::size_t index = 0;
306  for( std::vector< std::vector<int>>::iterator i = scores.begin() ; i != scores.end() ; ++i) {
307  for( std::vector<int>::iterator j = i->begin() ; j != i->end() ; ++j ) {
308  if(units_input[index].num_elements() != 0) {
309  *j /= units_input[index].num_elements();
310  } else {
311  *j = 0;
312  }
313  }
314 
315  ++index;
316  }
317  //std::vector<variant> res;
318  std::map<variant, variant> res;
319 
320  std::size_t current_side = ai_.get_side() - 1 ;
321 
322  std::vector<int> enemies;
323  std::vector<int> allies;
324 
325  for(std::size_t side = 0 ; side < units_input.num_elements() ; ++side) {
326  if( side == current_side)
327  continue;
328 
329  if( ai_.current_team().is_enemy(side+1) ) {
330  if( !leaders_input[side].is_empty() )
331  enemies.push_back(side);
332  } else {
333  if( !leaders_input[side].is_empty() )
334  allies.push_back(side);
335  }
336  }
337 
338  //calculate_map_ownership( recruits_of_side, map(units_of_side, 'units', map( filter(units, leader), loc) ) )
339  //map(, debug_label(key,value))
340  for (int x = 0; x < w; ++x) {
341  for (int y = 0; y < h; ++y)
342  {
343  int i = y * w + x;
344  bool valid = true;
345  bool enemy_border = false;
346 
347  if( scores[current_side][i] > 98 )
348  continue;
349 
350  for (int side : enemies) {
351  int diff = scores[current_side][i] - scores[side][i];
352  if ( diff > enemy_tolerance) {
353  valid = false;
354  break;
355  } else if( std::abs(diff) < enemy_border_tolerance )
356  enemy_border = true;
357  }
358 
359  if( valid ) {
360  for (int side : allies) {
361  if ( scores[current_side][i] - scores[side][i] > ally_tolerance ) {
362  valid = false;
363  break;
364  }
365  }
366  }
367 
368  if( valid ) {
369  if( enemy_border )
370  res.emplace(variant(std::make_shared<location_callable>(map_location(x, y))), variant(scores[0][i] + 10000));
371  else
372  res.emplace(variant(std::make_shared<location_callable>(map_location(x, y))), variant(scores[0][i]));
373  }
374  }
375  }
376  return variant(res);
377 }
378 
379 DEFINE_WFL_FUNCTION(nearest_loc, 2, 2)
380 {
381  const map_location loc = args()[0]->evaluate(variables, add_debug_info(fdb, 0, "nearest_loc:location")).convert_to<location_callable>()->loc();
382  variant items = args()[1]->evaluate(variables,add_debug_info(fdb,1,"nearest_loc:locations"));
383  int best = 1000000;
384  int best_i = -1;
385 
386  for(std::size_t i = 0; i < items.num_elements(); ++i) {
387 
388  const map_location move_loc = items[i].convert_to<location_callable>()->loc();
389  int distance = distance_between(loc, move_loc);
390 
391  if(distance < best) {
392  best = distance;
393  best_i = i;
394  }
395  }
396 
397  if( best_i != -1)
398  return variant(std::make_shared<location_callable>(items[best_i].convert_to<location_callable>()->loc()));
399  else
400  return variant();
401 }
402 
403 /** FormulaAI function to run fai script from file. Usable from in-game console.
404 * arguments[0] - required file name, follows the usual wml convention
405 */
406 DEFINE_FAI_FUNCTION(run_file, 1, 1)
407 {
408  const args_list& arguments = args();
409  const variant var0 = arguments[0]->evaluate(variables,add_debug_info(fdb,0,"run_file:file"));
410  const std::string filename = var0.string_cast();
411 
412  //NOTE: get_wml_location also filters file path to ensure it doesn't contain things like "../../top/secret"
414  if(path.empty()) {
415  ERR_AI << "run_file : not found [" << filename <<"]"<< std::endl;
416  return variant(); //no suitable file
417  }
418 
419  std::string formula_string = filesystem::read_file(path);
420  //need to get function_table from somewhere or delegate to someone who has access to it
421  formula_ptr parsed_formula = ai_.create_optional_formula(formula_string);
422  if(parsed_formula == formula_ptr()) {
423  ERR_AI << "run_file : unable to create formula"<< std::endl;
424  return variant(); //was unable to create a formula from file
425  }
426  return parsed_formula->evaluate(variables,add_debug_info(fdb,-1,"run_file:formula_from_file"));
427 }
428 
429 DEFINE_WFL_FUNCTION(castle_locs, 1, 1)
430 {
431  const map_location starting_loc = args()[0]->evaluate(variables, add_debug_info(fdb, 0, "castle_locs:location")).convert_to<location_callable>()->loc();
432 
433  //looks like reimplementing a generic graph search algorithm to me
434  std::set< map_location > visited_locs;
435  std::queue< map_location > queued_locs;
436 
437  queued_locs.push(starting_loc);
438 
439  while( !queued_locs.empty() ) {
440  const map_location loc = queued_locs.front();
441  queued_locs.pop();
442 
443  if ( visited_locs.find( loc ) != visited_locs.end() )
444  continue;
445 
446  visited_locs.insert(loc);
447 
449  get_adjacent_tiles(loc, adj.data());
450 
451  for(unsigned n = 0; n < adj.size(); ++n) {
452  if (resources::gameboard->map().on_board(adj[n]) && visited_locs.find( adj[n] ) == visited_locs.end() ) {
453  if (resources::gameboard->map().get_terrain_info(adj[n]).is_keep() ||
455  queued_locs.push(adj[n]);
456  }
457  }
458  }
459  }
460 
461  if ( !resources::gameboard->map().get_terrain_info(starting_loc).is_keep() &&
462  !resources::gameboard->map().get_terrain_info(starting_loc).is_castle() )
463  visited_locs.erase(starting_loc);
464 
465  std::vector<variant> res;
466  for (const map_location& ml : visited_locs) {
467  res.emplace_back(std::make_shared<location_callable>( ml ));
468  }
469 
470  return variant(res);
471 }
472 
473 /**
474  * timeofday_modifer formula function. Returns combat modifier, taking
475  * alignment, illuminate, time of day and fearless trait into account.
476  * 'leadership' and 'slowed' are not taken into account.
477  * arguments[0] - unit
478  * arguments[1] - location (optional, defaults to unit's current location.
479  */
480 DEFINE_WFL_FUNCTION(timeofday_modifier, 1, 2)
481 {
482  variant u = args()[0]->evaluate(variables,add_debug_info(fdb,0,"timeofday_modifier:unit"));
483 
484  if( u.is_null() ) {
485  return variant();
486  }
487 
488  auto u_call = u.try_convert<unit_callable>();
489 
490  if(!u_call) {
491  return variant();
492  }
493 
494  const unit& un = u_call->get_unit();
495 
496  map_location loc;
497 
498  if(args().size()==2) {
499  loc = args()[1]->evaluate(variables, add_debug_info(fdb, 1, "timeofday_modifier:location")).convert_to<location_callable>()->loc();
500  }
501 
502  if(!loc.valid()) {
503  loc = u_call->get_location();
504  }
505 
506  return variant(combat_modifier(resources::gameboard->units(), resources::gameboard->map(), loc, un.alignment(), un.is_fearless()));
507 }
508 
509 DEFINE_FAI_FUNCTION(nearest_keep, 1, 1)
510 {
511  const map_location loc = args()[0]->evaluate(variables, add_debug_info(fdb, 0, "nearest_keep:location")).convert_to<location_callable>()->loc();
512  int best = 1000000;
513  int best_i = -1;
514 
515  ai_.get_keeps();
516  int size = ai_.get_keeps_cache().num_elements();
517 
518  for( int i = 0 ; i < size; ++i) {
519  int distance = distance_between(loc, ai_.get_keeps_cache()[i].convert_to<location_callable>()->loc() );
520  if(distance < best)
521  {
522  best = distance;
523  best_i = i;
524  }
525  }
526 
527  if( best_i != -1)
528  return variant(std::make_shared<location_callable>(ai_.get_keeps_cache()[best_i].convert_to<location_callable>()->loc()));
529  else
530  return variant();
531 }
532 
533 /**
534 * Find suitable keep for unit at location
535 * arguments[0] - location for unit on which the suitable keep is to be found
536 */
537 DEFINE_FAI_FUNCTION(suitable_keep, 1, 1)
538 {
539  const map_location loc = args()[0]->evaluate(variables, add_debug_info(fdb, 0, "suitable_keep:location")).convert_to<location_callable>()->loc();
540  const unit_map& units = resources::gameboard->units();
541  const unit_map::const_iterator u = units.find(loc);
542  if (u == units.end()){
543  return variant();
544  }
545  const pathfind::paths unit_paths(*u, false, true, ai_.current_team());
546  return variant(std::make_shared<location_callable>(ai_.suitable_keep(loc,unit_paths)));
547 }
548 
549 DEFINE_FAI_FUNCTION(find_shroud, 0, 1)
550 {
551  std::vector<variant> vars;
552  int w,h;
553 
554  if(args().size()==1) {
555  const gamemap& m = args()[0]->evaluate(variables, add_debug_info(fdb, 0, "find_shroud:gamemap")).convert_to<gamemap_callable>()->get_gamemap();
556  w = m.w();
557  h = m.h();
558  } else {
559  w = resources::gameboard->map().w();
560  h = resources::gameboard->map().h();
561  }
562 
563  for(int i = 0; i < w; ++i)
564  for(int j = 0; j < h; ++j) {
565  if(ai_.current_team().shrouded(map_location(i,j)))
566  vars.emplace_back(std::make_shared<location_callable>(map_location(i, j)));
567  }
568 
569  return variant(vars);
570 }
571 
572 DEFINE_FAI_FUNCTION(close_enemies, 2, 2)
573 {
574  std::vector<variant> vars;
575  const map_location loc = args()[0]->evaluate(variables, add_debug_info(fdb, 0, "close_enemies:location")).convert_to<location_callable>()->loc();
576  int range_s = args()[1]->evaluate(variables,add_debug_info(fdb,1,"close_enemies:distance")).as_int();
577  if (range_s < 0) {
578  WRN_AI << "close_enemies_function: range is negative (" << range_s << ")" << std::endl;
579  range_s = 0;
580  }
581  std::size_t range = static_cast<std::size_t>(range_s);
584  while (un != end) {
585  if (distance_between(loc, un->get_location()) <= range) {
586  if (un->side() != ai_.get_side()) {//fixme: ignores allied units
587  vars.emplace_back(std::make_shared<unit_callable>(*un));
588  }
589  }
590  ++un;
591  }
592  return variant(vars);
593 }
594 
595 DEFINE_WFL_FUNCTION(calculate_outcome, 3, 4)
596 {
597  std::vector<variant> vars;
598  int weapon;
599  if (args().size() > 3) weapon = args()[3]->evaluate(variables,add_debug_info(fdb,3,"calculate_outcome:weapon")).as_int();
600  else weapon = -1;
601 
602  const unit_map& units = resources::gameboard->units();
603  map_location attacker_location =
604  args()[0]->evaluate(variables, add_debug_info(fdb, 0, "calculate_outcome:attacker_current_location")).convert_to<location_callable>()->loc();
605  if(units.count(attacker_location) == 0) {
606  ERR_AI << "Performing calculate_outcome() with non-existent attacker at (" <<
607  attacker_location.wml_x() << "," << attacker_location.wml_y() << ")\n";
608  return variant();
609  }
610 
611  map_location defender_location =
612  args()[2]->evaluate(variables,add_debug_info(fdb, 2, "calculate_outcome:defender_location")).convert_to<location_callable>()->loc();
613  if(units.count(defender_location) == 0) {
614  ERR_AI << "Performing calculate_outcome() with non-existent defender at (" <<
615  defender_location.wml_x() << "," << defender_location.wml_y() << ")\n";
616  return variant();
617  }
618 
619  battle_context bc(units, args()[1]->evaluate(variables, add_debug_info(fdb, 1, "calculate_outcome:attacker_attack_location")).convert_to<location_callable>()->loc(),
620  defender_location, weapon, -1, 1.0, nullptr, units.find(attacker_location).get_shared_ptr());
621  std::vector<double> hp_dist = bc.get_attacker_combatant().hp_dist;
622  std::vector<double>::iterator it = hp_dist.begin();
623  int i = 0;
624  std::vector<variant> hitLeft;
625  std::vector<variant> prob;
626  while (it != hp_dist.end()) {
627  if (*it != 0) {
628  hitLeft.emplace_back(i);
629  prob.emplace_back(static_cast<int>(*it*10000));
630  }
631  ++it;
632  ++i;
633  }
634  std::vector<variant> status;
635  if (bc.get_attacker_combatant().poisoned != 0)
636  status.emplace_back("Poisoned");
637  if (bc.get_attacker_combatant().slowed != 0)
638  status.emplace_back("Slowed");
639  if (bc.get_defender_stats().petrifies && static_cast<unsigned int>(hitLeft[0].as_int()) != bc.get_attacker_stats().hp)
640  status.emplace_back("Stoned");
641  if (bc.get_defender_stats().plagues && hitLeft[0].as_int() == 0)
642  status.emplace_back("Zombiefied");
643  vars.emplace_back(std::make_shared<outcome_callable>(hitLeft, prob, status));
644  hitLeft.clear();
645  prob.clear();
646  status.clear();
647  hp_dist = bc.get_defender_combatant().hp_dist;
648  it = hp_dist.begin();
649  i = 0;
650  while (it != hp_dist.end()) {
651  if (*it != 0) {
652  hitLeft.emplace_back(i);
653  prob.emplace_back(static_cast<int>(*it*10000));
654  }
655  ++it;
656  ++i;
657  }
658  if (bc.get_defender_combatant().poisoned != 0)
659  status.emplace_back("Poisoned");
660  if (bc.get_defender_combatant().slowed != 0)
661  status.emplace_back("Slowed");
662  if (bc.get_attacker_stats().petrifies && static_cast<unsigned int>(hitLeft[0].as_int()) != bc.get_defender_stats().hp)
663  status.emplace_back("Stoned");
664  if (bc.get_attacker_stats().plagues && hitLeft[0].as_int() == 0)
665  status.emplace_back("Zombiefied");
666  vars.emplace_back(std::make_shared<outcome_callable>(hitLeft, prob, status));
667  return variant(vars);
668 }
669 
670 DEFINE_WFL_FUNCTION(outcomes, 1, 1)
671 {
672  variant attack = args()[0]->evaluate(variables,add_debug_info(fdb,0,"outcomes:attack"));
673  auto analysis = attack.convert_to<ai::attack_analysis>();
674  //unit_map units_with_moves(resources::gameboard->units());
675  //typedef std::pair<map_location, map_location> mv;
676  //for(const mv &m : analysis->movements) {
677  // units_with_moves.move(m.first, m.second);
678  //}
679 
680  std::vector<variant> vars;
681  if(analysis->chance_to_kill > 0.0) {
682  //unit_map units(units_with_moves);
683  //units.erase(analysis->target);
684  vars.emplace_back(std::make_shared<position_callable>(/*&units,*/ static_cast<int>(analysis->chance_to_kill*100)));
685 
686  }
687 
688  if(analysis->chance_to_kill < 1.0) {
689  //unit_map units(units_with_moves);
690  vars.emplace_back(std::make_shared<position_callable>(/*&units,*/ static_cast<int>(100 - analysis->chance_to_kill*100)));
691  }
692 
693  return variant(vars);
694 }
695 
696 DEFINE_FAI_FUNCTION(rate_action, 1, 1)
697 {
698  variant act = args()[0]->evaluate(variables,add_debug_info(fdb,0,"rate_action:action"));
699  auto analysis = act.convert_to<ai::attack_analysis>();
700 
701  return variant(analysis->rating(ai_.get_aggression(),ai_)*1000,variant::DECIMAL_VARIANT);
702 }
703 
704 DEFINE_WFL_FUNCTION(recall, 1, 2)
705 {
706  const std::string id = args()[0]->evaluate(variables,add_debug_info(fdb,0,"recall:id")).as_string();
707  map_location loc;
708  if(args().size() >= 2) {
709  loc = args()[1]->evaluate(variables, add_debug_info(fdb, 1, "recall:location")).convert_to<location_callable>()->loc();
710  }
711 
712  return variant(std::make_shared<recall_callable>(loc, id));
713 }
714 
715 DEFINE_WFL_FUNCTION(recruit, 1, 2)
716 {
717  const std::string type = args()[0]->evaluate(variables,add_debug_info(fdb,0,"recruit:type")).as_string();
718  map_location loc;
719  if(args().size() >= 2) {
720  loc = args()[1]->evaluate(variables, add_debug_info(fdb, 1, "recruit:location")).convert_to<location_callable>()->loc();
721  }
722 
723  return variant(std::make_shared<recruit_callable>(loc, type));
724 }
725 
726 DEFINE_FAI_FUNCTION(shortest_path, 2, 3)
727 {
728 
729  std::vector<variant> locations;
730 
731  const map_location src = args()[0]->evaluate(variables, add_debug_info(fdb, 0, "shortest_path:src")).convert_to<location_callable>()->loc();
732  const map_location dst = args()[1]->evaluate(variables, add_debug_info(fdb, 1, "shortest_path:dst")).convert_to<location_callable>()->loc();
733  map_location unit_loc;
734 
735  if( src == dst )
736  return variant(locations);
737 
738  if(args().size() > 2)
739  unit_loc = args()[2]->evaluate(variables,add_debug_info(fdb,2,"shortest_path:unit_location")).convert_to<location_callable>()->loc();
740  else
741  unit_loc = src;
742 
743  unit_map::iterator unit_it = resources::gameboard->units().find(unit_loc);
744 
745  if( unit_it == resources::gameboard->units().end() ) {
746  std::ostringstream str;
747  str << "shortest_path function: expected unit at location (" << (unit_loc.wml_x()) << "," << (unit_loc.wml_y()) << ")";
748  throw formula_error( str.str(), "", "", 0);
749  }
750 
751  pathfind::teleport_map allowed_teleports = ai_.get_allowed_teleports(unit_it);
752 
753  pathfind::plain_route route = ai_.shortest_path_calculator( src, dst, unit_it, allowed_teleports );
754 
755  if( route.steps.size() < 2 ) {
756  return variant(locations);
757  }
758 
759  for (std::vector<map_location>::const_iterator loc_iter = route.steps.begin() + 1 ; loc_iter !=route.steps.end(); ++loc_iter) {
760  locations.emplace_back(std::make_shared<location_callable>(*loc_iter));
761  }
762 
763  return variant(locations);
764 }
765 
766 DEFINE_FAI_FUNCTION(simplest_path, 2, 3)
767 {
768  std::vector<variant> locations;
769 
770  const map_location src = args()[0]->evaluate(variables, add_debug_info(fdb, 0, "simplest_path:src")).convert_to<location_callable>()->loc();
771  const map_location dst = args()[1]->evaluate(variables, add_debug_info(fdb, 1, "simplest_path:dst")).convert_to<location_callable>()->loc();
772  map_location unit_loc;
773 
774  if( src == dst )
775  return variant(locations);
776 
777  if(args().size() > 2)
778  unit_loc = args()[2]->evaluate(variables, add_debug_info(fdb, 2, "simplest_path:unit_location")).convert_to<location_callable>()->loc();
779  else
780  unit_loc = src;
781 
782  unit_map::iterator unit_it = resources::gameboard->units().find(unit_loc);
783 
784  if( unit_it == resources::gameboard->units().end() ) {
785  std::ostringstream str;
786  str << "simplest_path function: expected unit at location (" << (unit_loc.wml_x()) << "," << (unit_loc.wml_y()) << ")";
787  throw formula_error( str.str(), "", "", 0);
788  }
789 
790  pathfind::teleport_map allowed_teleports = ai_.get_allowed_teleports(unit_it);
791 
793 
794  pathfind::plain_route route = pathfind::a_star_search(src, dst, 1000.0, em_calc, resources::gameboard->map().w(), resources::gameboard->map().h(), &allowed_teleports);
795 
796  if( route.steps.size() < 2 ) {
797  return variant(locations);
798  }
799 
800  for (std::vector<map_location>::const_iterator loc_iter = route.steps.begin() + 1 ; loc_iter !=route.steps.end(); ++loc_iter) {
801  if (unit_it->movement_cost((resources::gameboard->map())[*loc_iter]) < movetype::UNREACHABLE )
802  locations.emplace_back(std::make_shared<location_callable>(*loc_iter));
803  else
804  break;
805  }
806 
807  return variant(locations);
808 }
809 
810 DEFINE_FAI_FUNCTION(next_hop, 2, 3)
811 {
812 
813  const map_location src = args()[0]->evaluate(variables, add_debug_info(fdb, 0, "next_hop:src")).convert_to<location_callable>()->loc();
814  const map_location dst = args()[1]->evaluate(variables, add_debug_info(fdb, 1, "next_hop:dst")).convert_to<location_callable>()->loc();
815  map_location unit_loc;
816 
817  if( src == dst )
818  return variant();
819 
820  if(args().size() > 2)
821  unit_loc = args()[2]->evaluate(variables, add_debug_info(fdb, 2, "next_hop:unit_location")).convert_to<location_callable>()->loc();
822  else
823  unit_loc = src;
824 
825  unit_map::iterator unit_it = resources::gameboard->units().find(unit_loc);
826 
827  if( unit_it == resources::gameboard->units().end() ) {
828  std::ostringstream str;
829  str << "next_hop function: expected unit at location (" << (unit_loc.wml_x()) << "," << (unit_loc.wml_y()) << ")";
830  throw formula_error( str.str(), "", "", 0);
831  }
832 
833  pathfind::teleport_map allowed_teleports = ai_.get_allowed_teleports(unit_it);
834 
835  pathfind::plain_route route = ai_.shortest_path_calculator( src, dst, unit_it, allowed_teleports );
836 
837  if( route.steps.size() < 2 ) {
838  return variant();
839  }
840 
842  const ai::moves_map &possible_moves = ai_.get_possible_moves();
843  const ai::moves_map::const_iterator& p_it = possible_moves.find(unit_loc);
844  if (p_it==possible_moves.end() ) {
845  return variant();
846  }
847 
848  for (std::vector<map_location>::const_iterator loc_iter = route.steps.begin() + 1 ; loc_iter !=route.steps.end(); ++loc_iter) {
849 
850  if (p_it->second.destinations.find(*loc_iter) != p_it->second.destinations.end() ) {
851  loc = *loc_iter;
852  } else {
853  break;
854  }
855  }
856  if (loc==map_location::null_location()) {
857  return variant();
858  }
859  return variant(std::make_shared<location_callable>(loc));
860 }
861 
862 DEFINE_WFL_FUNCTION(move, 2, 2)
863 {
864  const map_location src = args()[0]->evaluate(variables, add_debug_info(fdb, 0, "move:src")).convert_to<location_callable>()->loc();
865  const map_location dst = args()[1]->evaluate(variables, add_debug_info(fdb, 1, "move:dst")).convert_to<location_callable>()->loc();
866  LOG_AI << "move(): " << src << ", " << dst << ")\n";
867  return variant(std::make_shared<move_callable>(src, dst));
868 }
869 
870 DEFINE_WFL_FUNCTION(move_partial, 2, 2)
871 {
872  const map_location src = args()[0]->evaluate(variables, add_debug_info(fdb, 0, "move_partial:src")).convert_to<location_callable>()->loc();
873  const map_location dst = args()[1]->evaluate(variables, add_debug_info(fdb, 1, "move_partial:dst")).convert_to<location_callable>()->loc();
874  LOG_AI << "move_partial(): " << src << ", " << dst << ")\n";
875  return variant(std::make_shared<move_partial_callable>(src, dst));
876 }
877 
878 DEFINE_WFL_FUNCTION(set_unit_var, 3, 3)
879 {
880  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()));
881 }
882 
883 DEFINE_WFL_FUNCTION(fallback, 0, 1)
884 {
885  UNUSED(fdb);
886  // The parameter is not used, but is accepted for legacy compatibility
887  if(args().size() == 1 && args()[0]->evaluate(variables).as_string() != "human")
888  return variant();
889  return variant(std::make_shared<fallback_callable>());
890 }
891 
892 DEFINE_WFL_FUNCTION(attack, 3, 4)
893 {
894  const map_location move_from = args()[0]->evaluate(variables, add_debug_info(fdb, 0, "attack:move_from")).convert_to<location_callable>()->loc();
895  const map_location src = args()[1]->evaluate(variables, add_debug_info(fdb, 1, "attack:src")).convert_to<location_callable>()->loc();
896  const map_location dst = args()[2]->evaluate(variables, add_debug_info(fdb, 2, "attack:dst")).convert_to<location_callable>()->loc();
897  const int weapon = args().size() == 4 ? args()[3]->evaluate(variables,add_debug_info(fdb,3,"attack:weapon")).as_int() : -1;
898  if(resources::gameboard->units().count(move_from) == 0 || resources::gameboard->units().count(dst) == 0) {
899  ERR_AI << "AI ERROR: Formula produced illegal attack: " << move_from << " -> " << src << " -> " << dst << std::endl;
900  return variant();
901  }
902  return variant(std::make_shared<attack_callable>(move_from, src, dst, weapon));
903 }
904 
905 DEFINE_FAI_FUNCTION(debug_label, 2, 2)
906 {
907  const args_list& arguments = args();
908  const variant var0 = arguments[0]->evaluate(variables,fdb);
909  const variant var1 = arguments[1]->evaluate(variables,fdb);
910 
911  const map_location location = var0.convert_to<location_callable>()->loc();
912  std::string text;
913  if( var1.is_string() )
914  text = var1.as_string();
915  else
916  text = var1.to_debug_string();
917 
919  std::string team_name;
920 
921  color_t color = team::get_side_color(ai_.get_side());
922 
923  const terrain_label *res;
924  res = gui->labels().set_label(location, text, ai_.get_side() - 1, team_name, color);
925  if (res && resources::recorder)
927 
928  std::vector<variant> result;
929  result.push_back(var0);
930  result.push_back(var1);
931  return variant(result);
932 }
933 
934 
935 DEFINE_WFL_FUNCTION(is_village, 2, 3)
936 {
937  const gamemap& m = args()[0]->evaluate(variables, add_debug_info(fdb, 0, "is_village:map")).convert_to<gamemap_callable>()->get_gamemap();
938 
939  map_location loc;
940  if(args().size() == 2) {
941  loc = args()[1]->evaluate(variables, add_debug_info(fdb, 1, "is_village:location")).convert_to<location_callable>()->loc();
942  } else {
943  loc = map_location( args()[1]->evaluate(variables,add_debug_info(fdb,1,"is_village:x")).as_int(),
944  args()[2]->evaluate(variables,add_debug_info(fdb,2,"is_village:y")).as_int(), wml_loc());
945  }
946  return variant(m.is_village(loc));
947 }
948 
949 DEFINE_FAI_FUNCTION(is_unowned_village, 2, 3)
950 {
951 
952  const gamemap& m = args()[0]->evaluate(variables, add_debug_info(fdb, 0, "is_unowned_village:map")).convert_to<gamemap_callable>()->get_gamemap();
953  const std::set<map_location>& my_villages = ai_.current_team().villages();
954 
955  map_location loc;
956  if(args().size() == 2) {
957  loc = args()[1]->evaluate(variables, add_debug_info(fdb, 1, "is_unowned_village:location")).convert_to<location_callable>()->loc();
958  } else {
959  loc = map_location( args()[1]->evaluate(variables,add_debug_info(fdb,1,"is_unowned_village:x")).as_int(),
960  args()[2]->evaluate(variables,add_debug_info(fdb,2,"is_unowned_village:y")).as_int(), wml_loc());
961  }
962 
963  if(m.is_village(loc) && (my_villages.count(loc)==0) ) {
964  return variant(true);
965  } else {
966  return variant(false);
967  }
968 }
969 
971 {
972  variant res = args()[0]->evaluate(variables,add_debug_info(fdb,0,"unit_moves:unit_location"));
973  std::vector<variant> vars;
974  if(res.is_null()) {
975  return variant(vars);
976  }
977 
978  const map_location& loc = res.convert_to<location_callable>()->loc();
979  const ai::move_map& srcdst = ai_.get_srcdst();
980  typedef ai::move_map::const_iterator Itor;
981  std::pair<Itor,Itor> range = srcdst.equal_range(loc);
982 
983  for(Itor i = range.first; i != range.second; ++i) {
984  vars.emplace_back(std::make_shared<location_callable>(i->second));
985  }
986 
987  return variant(vars);
988 }
989 
990 DEFINE_WFL_FUNCTION(units_can_reach, 2, 2)
991 {
992  std::vector<variant> vars;
993  variant dstsrc_var = args()[0]->evaluate(variables,add_debug_info(fdb,0,"units_can_reach:possible_move_list"));
994  const ai::move_map& dstsrc = dstsrc_var.convert_to<move_map_callable>()->dstsrc();
995  std::pair<ai::move_map::const_iterator,ai::move_map::const_iterator> range =
996  dstsrc.equal_range(args()[1]->evaluate(variables, add_debug_info(fdb, 1, "units_can_reach:possible_move_list")).convert_to<location_callable>()->loc());
997  while(range.first != range.second) {
998  unit_map::const_iterator un = resources::gameboard->units().find(range.first->second);
999  assert(un != resources::gameboard->units().end());
1000  vars.emplace_back(std::make_shared<unit_callable>(*un));
1001  ++range.first;
1002  }
1003 
1004  return variant(vars);
1005 }
1006 
1007 DEFINE_FAI_FUNCTION(is_avoided_location, 1, 1)
1008 {
1009  variant res = args()[0]->evaluate(variables,add_debug_info(fdb,0,"is_avoided_location:location"));
1010  if(res.is_null()) {
1011  return variant();
1012  }
1013  const map_location& loc = res.convert_to<location_callable>()->loc();
1014  return variant(ai_.get_avoid().match(loc));
1015 }
1016 
1017 DEFINE_WFL_FUNCTION(max_possible_damage, 2, 2)
1018 {
1019  variant u1 = args()[0]->evaluate(variables,add_debug_info(fdb,0,"max_possible_damage:unit1"));
1020  variant u2 = args()[1]->evaluate(variables,add_debug_info(fdb,1,"max_possible_damage:unit2"));
1021  if(u1.is_null() || u2.is_null()) {
1022  return variant();
1023  }
1024 
1025  unit_adapter u_attacker(u1), u_defender(u2);
1026  int best = 0;
1027  for(const attack_type& atk : u_attacker.attacks()) {
1028  const int dmg = round_damage(atk.damage(), u_defender.damage_from(atk), 100) * atk.num_attacks();
1029  if(dmg > best)
1030  best = dmg;
1031  }
1032  return variant(best);
1033 }
1034 
1035 namespace {
1036  std::pair<int, int> best_melee_and_ranged_attacks(unit_adapter attacker, unit_adapter defender) {
1037  int highest_melee_damage = 0;
1038  int highest_ranged_damage = 0;
1039 
1040  for (const attack_type &attack : attacker.attacks()) {
1041  const int dmg = round_damage(attack.damage(), defender.damage_from(attack), 100) * attack.num_attacks();
1042  if (attack.range() == "melee") {
1043  highest_melee_damage = std::max(highest_melee_damage, dmg);
1044  } else {
1045  highest_ranged_damage = std::max(highest_ranged_damage, dmg);
1046  }
1047  }
1048 
1049  return std::make_pair(highest_melee_damage, highest_ranged_damage);
1050  }
1051 }
1052 
1053 DEFINE_WFL_FUNCTION(max_possible_damage_with_retaliation, 2, 2)
1054 {
1055  variant u1 = args()[0]->evaluate(variables,add_debug_info(fdb,0,"max_possible_damage_with_retaliation:unit1"));
1056  variant u2 = args()[1]->evaluate(variables,add_debug_info(fdb,1,"max_possible_damage_with_retaliation:unit2"));
1057 
1058  if(u1.is_null() || u2.is_null()) {
1059  return variant();
1060  }
1061 
1062  unit_adapter attacker(u1);
1063  unit_adapter defender(u2);
1064 
1065  // find max damage inflicted by attacker and by defender to the attacker
1066  std::pair<int, int> best_attacker_attacks = best_melee_and_ranged_attacks(attacker, defender);
1067  std::pair<int, int> best_defender_attacks = best_melee_and_ranged_attacks(defender, attacker);
1068 
1069  std::vector<variant> vars;
1070  vars.emplace_back(best_attacker_attacks.first);
1071  vars.emplace_back(best_attacker_attacks.second);
1072  vars.emplace_back(best_defender_attacks.first);
1073  vars.emplace_back(best_defender_attacks.second);
1074 
1075  return variant(vars);
1076 }
1077 
1078 template<typename T>
1079 class ai_formula_function : public formula_function {
1080 protected:
1081  formula_ai& ai_;
1082 public:
1083  ai_formula_function(const std::string& name, ai::formula_ai& ai) : formula_function(name), ai_(ai) {}
1084  function_expression_ptr generate_function_expression(const std::vector<expression_ptr>& args) const {
1085  return std::make_shared<T>(args, ai_);
1086  }
1087 };
1088 
1089 }
1090 
1091 // This macro is for functions taking an additional formula_ai argument.
1092 // Functions using the other macro could potentially be made core.
1093 #define DECLARE_FAI_FUNCTION(name) \
1094  add_function(#name, std::make_shared<ai_formula_function<name##_function>>(#name, ai))
1095 
1098 {
1099  function_symbol_table& functions_table = *this;
1100  DECLARE_WFL_FUNCTION(outcomes);
1101  //DECLARE_FAI_FUNCTION(evaluate_for_position);
1102  DECLARE_WFL_FUNCTION(move);
1103  DECLARE_WFL_FUNCTION(move_partial);
1104  DECLARE_WFL_FUNCTION(attack);
1105  DECLARE_FAI_FUNCTION(rate_action);
1106  DECLARE_WFL_FUNCTION(recall);
1107  DECLARE_WFL_FUNCTION(recruit);
1108  DECLARE_FAI_FUNCTION(is_avoided_location);
1109  DECLARE_WFL_FUNCTION(is_village);
1110  DECLARE_FAI_FUNCTION(is_unowned_village);
1112  DECLARE_WFL_FUNCTION(set_unit_var);
1113  DECLARE_WFL_FUNCTION(fallback);
1114  DECLARE_WFL_FUNCTION(units_can_reach);
1115  DECLARE_FAI_FUNCTION(debug_label);
1116  DECLARE_WFL_FUNCTION(max_possible_damage);
1117  DECLARE_WFL_FUNCTION(max_possible_damage_with_retaliation);
1118  DECLARE_FAI_FUNCTION(next_hop);
1119  DECLARE_WFL_FUNCTION(castle_locs);
1120  DECLARE_WFL_FUNCTION(timeofday_modifier);
1121  DECLARE_FAI_FUNCTION(distance_to_nearest_unowned_village);
1122  DECLARE_FAI_FUNCTION(shortest_path);
1123  DECLARE_FAI_FUNCTION(simplest_path);
1124  DECLARE_FAI_FUNCTION(nearest_keep);
1125  DECLARE_FAI_FUNCTION(suitable_keep);
1126  DECLARE_WFL_FUNCTION(nearest_loc);
1127  DECLARE_FAI_FUNCTION(find_shroud);
1128  DECLARE_FAI_FUNCTION(close_enemies);
1129  DECLARE_WFL_FUNCTION(calculate_outcome);
1130  DECLARE_FAI_FUNCTION(run_file);
1131  DECLARE_FAI_FUNCTION(calculate_map_ownership);
1132 }
1133 #undef DECLARE_WFL_FUNCTION
1134 
1135 }
Defines formula ai.
#define ERR_AI
int h() const
Effective map height, in hexes.
Definition: map.hpp:128
bool is_castle() const
Definition: terrain.hpp:142
std::vector< double > hp_dist
Resulting probability distribution (might be not as large as max_hp)
unit_iterator end()
Definition: map.hpp:429
static display * get_singleton()
Returns the display object if a display object exists.
Definition: display.hpp:88
const std::vector< node > & nodes
int movement_cost_
void get_adjacent_tiles(const map_location &a, map_location *res)
Function which, given a location, will place all adjacent locations in res.
Definition: location.cpp:474
virtual const unit_map & units() const override
Definition: game_board.hpp:114
This class represents a single unit of a specific type.
Definition: unit.hpp:129
#define LOG_AI
int movement_cost(const t_translation::terrain_code &terrain) const
Get the unit&#39;s movement cost on a particular terrain.
Definition: unit.hpp:1426
const combatant & get_attacker_combatant(const combatant *prev_def=nullptr)
Get the simulation results.
Definition: attack.cpp:460
#define a
static const int UNREACHABLE
Magic value that signifies a hex is unreachable.
Definition: movetype.hpp:155
formula_debugger * add_debug_info(formula_debugger *fdb, int arg_number, const std::string &f_name)
General purpose widgets.
virtual const gamemap & map() const override
Definition: game_board.hpp:109
unit_iterator begin()
Definition: map.hpp:419
int wml_x() const
Definition: location.hpp:157
A terrain string which is converted to a terrain is a string with 1 or 2 layers the layers are separa...
Definition: translation.hpp:50
const terrain_type & get_terrain_info(const t_translation::terrain_code &terrain) const
Definition: map.cpp:97
STL namespace.
int resistance_against(const attack_type &attack) const
Returns the resistance against the indicated attack.
Definition: movetype.hpp:271
Replay control code.
const std::vector< std::string > items
std::string str
Definition: statement.cpp:110
const unit * unit_
ai_function_symbol_table(ai::formula_ai &ai)
#define WRN_AI
A single unit type that the player may recruit.
Definition: types.hpp:44
formula_ai & ai_
map_location loc_
std::multimap< map_location, map_location > move_map
The standard way in which a map of possible moves is recorded.
Definition: game_info.hpp:42
#define b
std::map< map_location, pathfind::paths > moves_map
The standard way in which a map of possible movement routes to location is recorded.
Definition: game_info.hpp:45
unsigned in
If equal to search_counter, the node is off the list.
A small explanation about what&#39;s going on here: Each action has access to two game_info objects First...
Definition: actions.cpp:59
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.
Definition: unit.hpp:970
std::vector< map_location > steps
Definition: pathfind.hpp:134
const movetype & movement_type() const
Definition: types.hpp:178
Structure which holds a single route between one location and another.
Definition: pathfind.hpp:131
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="")
Definition: label.cpp:146
static const ::game_config_view * terrain
The terrain used to create the cache.
Definition: minimap.cpp:130
int wml_y() const
Definition: location.hpp:158
bool valid() const
Definition: location.hpp:93
game_board * gameboard
Definition: resources.cpp:20
std::shared_ptr< function_expression > function_expression_ptr
Definition: function.hpp:167
Encapsulates the map of the game.
Definition: map.hpp:36
Computes the statistics of a battle between an attacker and a defender unit.
Definition: attack.hpp:173
int h
std::string path
Definition: game_config.cpp:39
map_display and display: classes which take care of displaying the map and game-data on the screen...
replay * recorder
Definition: resources.cpp:28
Function which only uses terrain, ignoring shroud, enemies, etc.
Definition: pathfind.hpp:240
std::size_t count(const map_location &loc) const
Definition: map.hpp:414
std::array< map_location, 6 > adjacent_loc_array_t
Definition: location.hpp:170
#define DEFINE_FAI_FUNCTION(name, min_args, max_args)
std::string read_file(const std::string &fname)
Basic disk I/O - read file.
Definition: filesystem.cpp:985
Encapsulates the map of the game.
Definition: location.hpp:42
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 ...
Definition: math.hpp:79
unit_iterator find(std::size_t id)
Definition: map.cpp:311
#define UNUSED(x)
Definition: global.hpp:34
int w() const
Effective map width, in hexes.
Definition: map.hpp:125
pointer get_shared_ptr() const
This is exactly the same as operator-> but it&#39;s slightly more readable, and can replace &*iter syntax...
Definition: map.hpp:220
std::size_t i
Definition: function.cpp:933
std::string get_wml_location(const std::string &filename, const std::string &current_dir)
Returns a complete path to the actual WML file or directory or an empty string if the file isn&#39;t pres...
u64 size
Definition: statement.cpp:80
static bool operator<(const placing_info &a, const placing_info &b)
Definition: game_state.cpp:140
#define DECLARE_FAI_FUNCTION(name)
Default AI contexts.
attack_itors attacks()
Gets an iterator over this unit&#39;s attacks.
Definition: unit.hpp:926
Declarations for File-IO.
int w
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.
Definition: unicode.cpp:71
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.
Definition: movetype.hpp:257
#define DECLARE_WFL_FUNCTION(name)
Declares a function name in the local function table functions_table.
Definition: function.hpp:47
#define next(ls)
Definition: llex.cpp:32
static const unit_type & get_unit_type(const std::string &type_id)
Converts a string ID to a unit_type.
Definition: unit.cpp:215
bool is_village(const map_location &loc) const
Definition: map.cpp:65
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.
Definition: location.cpp:557
To store label data Class implements logic for rendering.
Definition: label.hpp:107
bool is_fearless() const
Gets whether this unit is fearless - ie, unaffected by time of day.
Definition: unit.hpp:1233
double t
Definition: astarsearch.cpp:64
UNIT_ALIGNMENT alignment() const
The alignment of this unit.
Definition: unit.hpp:476
Definition: contexts.hpp:42
bool find(E event, F functor)
Tests whether an event handler is available.
const std::vector< map_location > & villages() const
Return a list of the locations of villages on the map.
Definition: map.hpp:192
static color_t get_side_color(int side)
Definition: team.cpp:949
#define DEFINE_WFL_FUNCTION(name, min_args, max_args)
Helper macro to declare an associated class for a WFL function.
Definition: function.hpp:27
const unit_type * unit_type_
Standard logging facilities (interface).
static config unit_moves(reports::context &rc, const unit *u, bool is_visible_unit)
Definition: reports.cpp:646
Object which contains all the possible locations a unit can move to, with associated best routes to t...
Definition: pathfind.hpp:70
static const map_location & null_location()
Definition: location.hpp:85
Container associating units to locations.
Definition: map.hpp:99
map_labels & labels()
Definition: display.cpp:2540
const_attack_itors attacks() const
Definition: types.cpp:512
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
This module contains various pathfinding functions and utilities.
std::string::const_iterator iterator
Definition: tokenizer.hpp:24
void add_label(const terrain_label *)
Definition: replay.cpp:269
int combat_modifier(const unit_map &units, const gamemap &map, const map_location &loc, unit_type::ALIGNMENT alignment, bool is_fearless)
Returns the amount that a unit&#39;s damage should be multiplied by due to the current time of day...
Definition: attack.cpp:1591
std::shared_ptr< formula > formula_ptr
Definition: formula_fwd.hpp:21