The Battle for Wesnoth  1.19.5+dev
ai.cpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2008 - 2024
3  by David White <dave@whitevine.net>
4  Part of the Battle for Wesnoth Project https://www.wesnoth.org/
5 
6  This program is free software; you can redistribute it and/or modify
7  it under the terms of the GNU General Public License as published by
8  the Free Software Foundation; either version 2 of the License, or
9  (at your option) any later version.
10  This program is distributed in the hope that it will be useful,
11  but WITHOUT ANY WARRANTY.
12 
13  See the COPYING file for more details.
14 */
15 
16 /**
17  * @file
18  * Defines formula ai candidate actions - headers
19  */
20 
21 #include "ai/formula/ai.hpp"
22 
23 #include "ai/formula/callable_objects.hpp" // for unit_callable, etc
24 #include "chat_events.hpp" // for chat_handler, etc
25 #include "display_chat_manager.hpp"
26 #include "formula/function.hpp" // for formula_expression
27 #include "game_board.hpp" // for game_board
28 #include "game_display.hpp" // for game_display
29 #include "log.hpp" // for LOG_STREAM, logger, etc
30 #include "map/map.hpp" // for gamemap
31 #include "pathfind/pathfind.hpp" // for plain_route, etc
32 #include "pathfind/teleport.hpp" // for get_teleport_locations, etc
33 #include "recall_list_manager.hpp" // for recall_list_manager
34 #include "resources.hpp" // for gameboard, teams, units, etc
35 #include "serialization/string_utils.hpp" // for split
36 #include "team.hpp" // for team
37 #include "terrain/filter.hpp" // for terrain_filter
38 #include "time_of_day.hpp" // for time_of_day
39 #include "tod_manager.hpp" // for tod_manager
40 #include "tstring.hpp" // for t_string, operator+
41 #include "units/unit.hpp" // for unit
42 #include "units/ptr.hpp" // for unit_ptr
43 #include "units/types.hpp"
44 #include "formula/formula.hpp" // for formula_error, formula, etc
45 #include "map/location.hpp" // for map_location, etc
46 #include "ai/formula/function_table.hpp" // for ai_function_symbol_table
47 #include "ai/game_info.hpp" // for move_result_ptr, move_map, etc
48 #include "ai/formula/candidates.hpp" // for base_candidate_action, etc
49 #include "utils/variant.hpp"
50 
51 #include <ctime> // for time
52 #include <vector> // for vector, allocator, etc
53 
54 static lg::log_domain log_formula_ai("ai/engine/fai");
55 #define DBG_AI LOG_STREAM(debug, log_formula_ai)
56 #define LOG_AI LOG_STREAM(info, log_formula_ai)
57 #define WRN_AI LOG_STREAM(warn, log_formula_ai)
58 #define ERR_AI LOG_STREAM(err, log_formula_ai)
59 
60 using namespace wfl;
61 
62 namespace ai {
63 
65 
67 {
68  ca_ptr new_ca;
69  const std::string name = rc_action["name"];
70  try {
71  const std::string& type = rc_action["type"];
72 
73  if( type == "movement") {
74  new_ca = std::make_shared<move_candidate_action>(name, type, rc_action, &function_table_);
75  } else if( type == "attack") {
76  new_ca = std::make_shared<attack_candidate_action>(name, type, rc_action, &function_table_);
77  } else {
78  ERR_AI << "Unknown candidate action type: " << type;
79  }
80  } catch(const formula_error& e) {
81  handle_exception(e, "Error while registering candidate action '" + name + "'");
82  }
83  return new_ca;
84 }
85 
88 }
89 
91  :
94  ai_ptr_(nullptr),
95  cfg_(cfg),
96  recursion_counter_(context.get_recursion_count()),
97  keeps_cache_(),
98  attacks_callable(*this, resources::gameboard->units()),
99 // infinite_loop_guardian_(),
100  vars_(),
101  function_table_(*this)
102 {
104  LOG_AI << "creating new formula ai";
105 }
106 
108 {
109  handle_exception(e, "Error while parsing formula");
110 }
111 
112 void formula_ai::handle_exception(const formula_error& e, const std::string& failed_operation) const
113 {
114  LOG_AI << failed_operation << ": " << e.formula;
115  display_message(failed_operation + ": " + e.formula);
116  //if line number = 0, don't display info about filename and line number
117  if (e.line != 0) {
118  LOG_AI << e.type << " in " << e.filename << ":" << e.line;
119  display_message(e.type + " in " + e.filename + ":" + std::to_string(e.line));
120  } else {
121  LOG_AI << e.type;
122  display_message(e.type);
123  }
124 }
125 
126 void formula_ai::display_message(const std::string& msg) const
127 {
128  game_display::get_singleton()->get_chat_manager().add_chat_message(std::time(nullptr), "wfl", get_side(), msg,
130 
131 }
132 
133 formula_ptr formula_ai::create_optional_formula(const std::string& formula_string) const {
134  try{
135  return formula::create_optional_formula(formula_string, &function_table_);
136  }
137  catch(const formula_error& e) {
139  return wfl::formula_ptr();
140  }
141 }
142 
144 {
145  ai_ptr_ = context;
146 }
147 
148 std::string formula_ai::evaluate(const std::string& formula_str)
149 {
150  try{
151 
152  formula f(formula_str, &function_table_);
153 
154  map_formula_callable callable(fake_ptr());
155 
156  //formula_debugger fdb;
157  const variant v = f.evaluate(callable,nullptr);
158 
159  if (ai_ptr_) {
160  variant var = variant(this->fake_ptr()).execute_variant(v);
161 
162  if ( !var.is_empty() ) {
163  return "Made move: " + var.to_debug_string();
164  }
165  }
166 
167  return v.to_debug_string();
168  }
169  catch(formula_error& e) {
170  e.line = 0;
172  throw;
173  }
174 }
175 
177 {
178  if (!formula_) {
179  throw formula_error("null formula passed to make_action","","formula",0);
180  }
181  LOG_AI << "do move...";
182  const variant var = formula_->evaluate(variables);
183  variant res;
184 
185  if (ai_ptr_) {
186  res = variant(this->fake_ptr()).execute_variant(var);
187  } else {
188  ERR_AI << "skipped execution of action because ai context is not set correctly";
189  }
190 
191  return res;
192 }
193 
195  const map_location &dst, unit_map::iterator &unit_it,
196  pathfind::teleport_map& allowed_teleports) const
197 {
198  map_location destination = dst;
199 
200  unit_map &units_ = resources::gameboard->units();
202 
203  unit_map::const_iterator dst_un = units_.find(destination);
204 
205  map_location res;
206 
207  if( dst_un != units_.end() ) {
208  //there is unit standing at dst, let's try to find free hex to move to
209  const map_location::direction preferred = destination.get_relative_dir(src);
210 
211  int best_rating = 100;//smaller is better
212  const auto adj = get_adjacent_tiles(destination);
213 
214  for(std::size_t n = 0; n < adj.size(); ++n) {
215  if(resources::gameboard->map().on_board(adj[n]) == false) {
216  continue;
217  }
218 
219  if(units_.find(adj[n]) != units_.end()) {
220  continue;
221  }
222 
223  static constexpr std::size_t ndirections = static_cast<int>(map_location::direction::indeterminate);
224  unsigned int difference = std::abs(static_cast<int>(static_cast<int>(preferred) - n));
225  if(difference > ndirections/2) {
226  difference = ndirections - difference;
227  }
228 
229  const int rating = difference * 2;
230  if(rating < best_rating || res.valid() == false) {
231  best_rating = rating;
232  res = adj[n];
233  }
234  }
235  }
236 
237  if( res != map_location() ) {
238  destination = res;
239  }
240 
242  1000.0, calc, resources::gameboard->map().w(),
243  resources::gameboard->map().h(), &allowed_teleports);
244 
245  return route;
246 }
247 
249 {
250  return pathfind::get_teleport_locations(*unit_it, current_team(), true);
251 }
252 
253 void formula_ai::add_formula_function(const std::string& name, const_formula_ptr formula, const_formula_ptr precondition, const std::vector<std::string>& args)
254 {
255  function_table_.add_function(name, std::make_shared<user_formula_function>(name, formula, precondition, args));
256 }
257 
258 namespace
259 {
260 template<typename Container>
261 variant villages_from_set(const Container& villages, const std::set<map_location>* exclude = nullptr)
262 {
263  std::vector<variant> vars;
264  for(const map_location& loc : villages) {
265  if(exclude && exclude->count(loc)) {
266  continue;
267  }
268  vars.emplace_back(std::make_shared<location_callable>(loc));
269  }
270 
271  return variant(vars);
272 }
273 
274 // TODO: I have no damn idea what to name this function
275 variant visit_helper(const utils::variant<bool, std::vector<std::string>>& input)
276 {
277  return utils::visit(
278  [](const auto& v) {
279  if constexpr(utils::decayed_is_same<bool, decltype(v)>) {
280  return variant(v);
281  } else {
282  const std::vector<variant> vars(v.begin(), v.end());
283  return variant(vars);
284  }
285  },
286  input);
287 }
288 } // namespace
289 
290 variant formula_ai::get_value(const std::string& key) const
291 {
292  const unit_map& units = resources::gameboard->units();
293 
294  if(key == "aggression")
295  {
296  return variant(get_aggression()*1000,variant::DECIMAL_VARIANT);
297 
298  } else if(key == "allow_ally_villages")
299  {
300  return visit_helper(get_allow_ally_villages());
301 
302  } else if(key == "avoid")
303  {
304  std::set<map_location> av_locs;
305  get_avoid().get_locations(av_locs);
306  return villages_from_set(av_locs);
307 
308  } else if(key == "caution")
309  {
310  return variant(get_caution()*1000,variant::DECIMAL_VARIANT);
311 
312  } else if(key == "grouping")
313  {
314  return variant(get_grouping());
315 
316  } else if(key == "leader_aggression")
317  {
318  return variant(get_leader_aggression()*1000,variant::DECIMAL_VARIANT);
319 
320  } else if(key == "leader_ignores_keep")
321  {
322  return visit_helper(get_leader_ignores_keep());
323 
324  } else if(key == "leader_value")
325  {
326  return variant(get_leader_value()*1000,variant::DECIMAL_VARIANT);
327 
328  } else if(key == "passive_leader")
329  {
330  return visit_helper(get_passive_leader());
331 
332  } else if(key == "passive_leader_shares_keep")
333  {
334  return visit_helper(get_passive_leader_shares_keep());
335 
336  } else if(key == "recruitment_pattern")
337  {
338  const std::vector<std::string> &rp = get_recruitment_pattern();
339  std::vector<variant> vars;
340  for(const std::string &i : rp) {
341  vars.emplace_back(i);
342  }
343  return variant(vars);
344 
345  } else if(key == "retreat_enemy_weight")
346  {
347  return variant(get_retreat_enemy_weight()*1000,variant::DECIMAL_VARIANT);
348 
349  } else if(key == "retreat_factor")
350  {
351  return variant(get_retreat_factor()*1000,variant::DECIMAL_VARIANT);
352 
353  } else if(key == "scout_village_targeting")
354  {
355  return variant(get_scout_village_targeting()*1000,variant::DECIMAL_VARIANT);
356 
357  } else if(key == "support_villages")
358  {
359  return variant(get_support_villages());
360 
361  } else if(key == "village_value")
362  {
363  return variant(get_village_value()*1000,variant::DECIMAL_VARIANT);
364 
365  } else if(key == "villages_per_scout")
366  {
368 
369  } else if(key == "attacks")
370  {
371  return get_attacks_as_variant();
372 
373  } else if(key == "turn")
374  {
375  return variant(resources::tod_manager->turn());
376 
377  } else if(key == "time_of_day")
378  {
379  return variant(resources::tod_manager->get_time_of_day().id);
380 
381  } else if(key == "my_side")
382  {
383  return variant(std::make_shared<team_callable>(resources::gameboard->get_team(get_side())));
384 
385  } else if(key == "my_side_number")
386  {
387  return variant(get_side()-1);
388 
389  } else if(key == "teams")
390  {
391  std::vector<variant> vars;
392  for(const team& t : resources::gameboard->teams()) {
393  vars.emplace_back(std::make_shared<team_callable>(t));
394  }
395  return variant(vars);
396 
397  } else if(key == "allies")
398  {
399  std::vector<variant> vars;
400  for( std::size_t i = 0; i < resources::gameboard->teams().size(); ++i) {
401  if ( !current_team().is_enemy( i+1 ) )
402  vars.emplace_back(i);
403  }
404  return variant(vars);
405 
406  } else if(key == "enemies")
407  {
408  std::vector<variant> vars;
409  for( std::size_t i = 0; i < resources::gameboard->teams().size(); ++i) {
410  if ( current_team().is_enemy( i+1 ) )
411  vars.emplace_back(i);
412  }
413  return variant(vars);
414 
415  } else if(key == "my_recruits")
416  {
417  std::vector<variant> vars;
418 
420 
421  for(const std::string& recruit : current_team().recruits()) {
422  if(const unit_type* ut = unit_types.find(recruit)) {
423  vars.emplace_back(std::make_shared<unit_type_callable>(*ut));
424  }
425  }
426  return variant(vars);
427 
428  } else if(key == "recruits_of_side")
429  {
430  std::vector<variant> vars;
431  std::vector<std::vector<variant>> tmp(resources::gameboard->teams().size());
432 
434 
435  for(std::size_t i = 0; i < tmp.size(); ++i) {
436  for(const std::string& recruit : resources::gameboard->teams()[i].recruits()) {
437  if(const unit_type* ut = unit_types.find(recruit)) {
438  tmp[i].emplace_back(std::make_shared<unit_type_callable>(*ut));
439  }
440  }
441  }
442 
443  for( std::size_t i = 0; i<tmp.size(); ++i)
444  vars.emplace_back(tmp[i]);
445  return variant(vars);
446 
447  } else if(key == "units")
448  {
449  std::vector<variant> vars;
450  for(const unit& u : units) {
451  vars.emplace_back(std::make_shared<unit_callable>(u));
452  }
453  return variant(vars);
454 
455  } else if(key == "units_of_side")
456  {
457  std::vector<variant> vars;
458  std::vector<std::vector<variant>> tmp(resources::gameboard->teams().size());
459  for(const unit &u : units) {
460  tmp[u.side() - 1].emplace_back(std::make_shared<unit_callable>(u));
461  }
462  for( std::size_t i = 0; i<tmp.size(); ++i)
463  vars.emplace_back(tmp[i]);
464  return variant(vars);
465 
466  } else if(key == "my_units")
467  {
468  std::vector<variant> vars;
469  for(const unit& u : units) {
470  if(u.side() == get_side()) {
471  vars.emplace_back(std::make_shared<unit_callable>(u));
472  }
473  }
474  return variant(vars);
475 
476  } else if(key == "enemy_units")
477  {
478  std::vector<variant> vars;
479  for(const unit& u : units) {
480  if(current_team().is_enemy(u.side()) && !u.incapacitated()) {
481  vars.emplace_back(std::make_shared<unit_callable>(u));
482  }
483  }
484  return variant(vars);
485 
486  } else if(key == "my_moves")
487  {
488  return variant(std::make_shared<move_map_callable>(get_srcdst(), get_dstsrc(), units));
489 
490  } else if(key == "my_attacks")
491  {
493  } else if(key == "enemy_moves")
494  {
495  return variant(std::make_shared<move_map_callable>(get_enemy_srcdst(), get_enemy_dstsrc(), units));
496 
497  } else if(key == "my_leader")
498  {
500  if(i == units.end()) {
501  return variant();
502  }
503  return variant(std::make_shared<unit_callable>(*i));
504 
505  } else if(key == "recall_list")
506  {
507  std::vector<variant> tmp;
508  for(const unit_ptr& ptr : current_team().recall_list()) {
509  tmp.emplace_back(std::make_shared<unit_callable>(*ptr));
510  }
511 
512  return variant(tmp);
513 
514  } else if(key == "vars")
515  {
516  return variant(vars_.fake_ptr());
517  } else if(key == "keeps")
518  {
519  return get_keeps();
520  } else if(key == "map")
521  {
522  return variant(std::make_shared<gamemap_callable>(*resources::gameboard));
523  } else if(key == "villages")
524  {
525  return villages_from_set(resources::gameboard->map().villages());
526  } else if(key == "villages_of_side")
527  {
528  std::vector<variant> vars;
529  for(const team& t : resources::gameboard->teams()) {
530  vars.push_back(villages_from_set(t.villages()));
531  }
532  return variant(vars);
533 
534  } else if(key == "my_villages")
535  {
536  return villages_from_set(current_team().villages());
537 
538  } else if(key == "enemy_and_unowned_villages")
539  {
540  return villages_from_set(resources::gameboard->map().villages(), &current_team().villages());
541  }
542  else if(key == "world") {
543  return variant(std::make_shared<gamestate_callable>());
544  }
545 
546  return variant();
547 }
548 
550 {
551  add_input(inputs, "aggression");
552  add_input(inputs, "leader_aggression");
553  add_input(inputs, "caution");
554  add_input(inputs, "attacks");
555  add_input(inputs, "my_side");
556  add_input(inputs, "teams");
557  add_input(inputs, "turn");
558  add_input(inputs, "time_of_day");
559  add_input(inputs, "keeps");
560  add_input(inputs, "vars");
561  add_input(inputs, "allies");
562  add_input(inputs, "enemies");
563  add_input(inputs, "map");
564  add_input(inputs, "my_attacks");
565  add_input(inputs, "enemy_moves");
566  add_input(inputs, "my_leader");
567  add_input(inputs, "my_recruits");
568  //add_input(inputs, "recall_list");
569  add_input(inputs, "recruits_of_side");
570  add_input(inputs, "units");
571  add_input(inputs, "units_of_side");
572  add_input(inputs, "my_units");
573  add_input(inputs, "enemy_units");
574  add_input(inputs, "villages");
575  add_input(inputs, "my_villages");
576  add_input(inputs, "villages_of_side");
577  add_input(inputs, "enemy_and_unowned_villages");
578  add_input(inputs, "world");
579 }
580 
581 void formula_ai::set_value(const std::string& key, const variant& value) {
582  vars_.mutate_value(key, value);
583 }
584 
586 {
587  if(keeps_cache_.is_null()) {
588  std::vector<variant> vars;
589  for(std::size_t x = 0; x != std::size_t(resources::gameboard->map().w()); ++x) {
590  for(std::size_t y = 0; y != std::size_t(resources::gameboard->map().h()); ++y) {
591  const map_location loc(x,y);
592  if(resources::gameboard->map().is_keep(loc)) {
593  for(const map_location& adj : get_adjacent_tiles(loc)) {
594  if(resources::gameboard->map().is_castle(adj)) {
595  vars.emplace_back(std::make_shared<location_callable>(loc));
596  break;
597  }
598  }
599  }
600  }
601  }
602  keeps_cache_ = variant(vars);
603  }
604 
605  return keeps_cache_;
606 }
607 
609  if (tiles_adjacent(unit_A,unit_B)) {
610  return true;
611  }
612  move_map::const_iterator i;
613  std::pair<move_map::const_iterator,
614  move_map::const_iterator> unit_moves;
615 
616  unit_moves = get_srcdst().equal_range(unit_A);
617  for(i = unit_moves.first; i != unit_moves.second; ++i) {
618  if (tiles_adjacent((*i).second,unit_B)) {
619  return true;
620  }
621  }
622  return false;
623 }
624 
626  //make sure we don't run out of refcount
627 
628  for(const config &func : cfg_.child_range("function"))
629  {
630  const std::string name = func["name"];
631  const std::string inputs = func["inputs"];
632  const std::string formula_str = func["formula"];
633 
634  std::vector<std::string> args = utils::split(inputs);
635  try {
637  create_optional_formula(formula_str),
638  create_optional_formula(func["precondition"]),
639  args);
640  }
641  catch(const formula_error& e) {
642  handle_exception(e, "Error while registering function '" + name + "'");
643  }
644  }
645 
647  if (const auto ai_vars = cfg_.optional_child("vars"))
648  {
649  variant var;
650  for(const auto& [key, value] : ai_vars->attribute_range()) {
651  var.serialize_from_string(value);
652  vars_.add(key, var);
653  }
654  }
655 
656 }
657 
659 {
660  fai_ca->evaluate(this,resources::gameboard->units());
661 
662 }
663 
665 {
666  map_formula_callable callable(fake_ptr());
667  fai_ca->update_callable_map( callable );
668  const_formula_ptr move_formula(fai_ca->get_action());
669  return !make_action(move_formula, callable).is_empty();
670 }
671 
672 #if 0
673 formula_ai::gamestate_change_observer::gamestate_change_observer() :
674  set_var_counter_(), set_unit_var_counter_(), continue_counter_()
675 {
677 }
678 
679 formula_ai::gamestate_change_observer::~gamestate_change_observer() {
681 }
682 
683 void formula_ai::gamestate_change_observer::handle_generic_event(const std::string& /*event_name*/) {
684  set_var_counter_ = 0;
685  set_unit_var_counter_ = 0;
686  continue_counter_ = 0;
687 }
688 
689 //return false if number of calls exceeded MAX_CALLS
690 bool formula_ai::gamestate_change_observer::set_var_check() {
691  if(set_var_counter_ >= MAX_CALLS)
692  return false;
693 
694  set_var_counter_++;
695  return true;
696 }
697 
698 bool formula_ai::gamestate_change_observer::set_unit_var_check() {
699  if(set_unit_var_counter_ >= MAX_CALLS)
700  return false;
701 
702  set_unit_var_counter_++;
703  return true;
704 }
705 
706 bool formula_ai::gamestate_change_observer::continue_check() {
707  if(continue_counter_ >= MAX_CALLS)
708  return false;
709 
710  continue_counter_++;
711  return true;
712 }
713 #endif
714 
716 {
717  DBG_AI << "formula_ai::to_config(): "<< cfg_;
718  config cfg = cfg_;
719 
720  //formula AI variables
721  cfg.clear_children("vars");
722  if (vars_.empty() == false) {
723  config &ai_vars = cfg.add_child("vars");
724 
725  std::string str;
727  {
728  try {
729  str = i->second.serialize_to_string();
730  } catch(const type_error&) {
731  WRN_AI << "variable ["<< i->first <<"] is not serializable - it will not be persisted across savegames";
732  continue;
733  }
734  if (!str.empty())
735  {
736  ai_vars[i->first] = str;
737  str.clear();
738  }
739  }
740  }
741 
742  return cfg;
743 }
744 
745 } // end of namespace ai
double t
Definition: astarsearch.cpp:63
Defines formula ai candidate actions - headers.
virtual void add_formula_function(const std::string &name, wfl::const_formula_ptr formula, wfl::const_formula_ptr precondition, const std::vector< std::string > &args)
Definition: ai.cpp:253
wfl::variant make_action(wfl::const_formula_ptr formula_, const wfl::formula_callable &variables)
Definition: ai.cpp:176
bool can_reach_unit(map_location unit_A, map_location unit_B) const
Definition: ai.cpp:608
recursion_counter recursion_counter_
Definition: ai.hpp:152
ai_context * ai_ptr_
Definition: ai.hpp:150
pathfind::teleport_map get_allowed_teleports(unit_map::iterator &unit_it) const
Definition: ai.cpp:248
void handle_exception(const wfl::formula_error &e) const
Definition: ai.cpp:107
wfl::ai_function_symbol_table function_table_
Definition: ai.hpp:165
void evaluate_candidate_action(wfl::candidate_action_ptr fai_ca)
Evaluate the fai candidate action.
Definition: ai.cpp:658
wfl::formula_ptr create_optional_formula(const std::string &formula_string) const
Create a new formula from the string, using the symbol table which is stored in the AI.
Definition: ai.cpp:133
formula_ai(const formula_ai &)=delete
void set_value(const std::string &key, const wfl::variant &value) override
Definition: ai.cpp:581
wfl::candidate_action_ptr load_candidate_action_from_config(const config &cfg)
Definition: ai.cpp:66
wfl::variant get_keeps() const
Definition: ai.cpp:585
pathfind::plain_route shortest_path_calculator(const map_location &src, const map_location &dst, unit_map::iterator &unit_it, pathfind::teleport_map &allowed_teleports) const
Definition: ai.cpp:194
std::string evaluate(const std::string &formula_str)
Definition: ai.cpp:148
void set_ai_context(ai_context *context)
Definition: ai.cpp:143
wfl::attack_map_callable attacks_callable
Definition: ai.hpp:159
void display_message(const std::string &msg) const
Definition: ai.cpp:126
virtual void get_inputs(wfl::formula_input_vector &inputs) const override
Definition: ai.cpp:549
virtual config to_config() const
Definition: ai.cpp:715
int get_recursion_count() const override
Get the value of the recursion counter.
Definition: ai.cpp:86
wfl::map_formula_callable vars_
Definition: ai.hpp:162
bool execute_candidate_action(wfl::candidate_action_ptr fai_ca)
Execute the fai candidate action.
Definition: ai.cpp:664
void on_create()
Definition: ai.cpp:625
const config cfg_
Definition: ai.hpp:151
wfl::variant keeps_cache_
Definition: ai.hpp:158
virtual wfl::variant get_value(const std::string &key) const override
Definition: ai.cpp:290
void remove_gamestate_observer(events::observer *event_observer)
Removes an observer of game events except ai_user_interact event and ai_sync_network event.
Definition: manager.cpp:373
void add_gamestate_observer(events::observer *event_observer)
Adds observer of game events except ai_user_interact event and ai_sync_network event.
Definition: manager.cpp:367
static manager & get_singleton()
Definition: manager.hpp:142
virtual double get_caution() const override
Definition: contexts.hpp:591
virtual utils::variant< bool, std::vector< std::string > > get_passive_leader() const override
Definition: contexts.hpp:666
virtual const team & current_team() const override
Definition: contexts.hpp:450
virtual const move_map & get_enemy_srcdst() const override
Definition: contexts.hpp:611
virtual const wfl::variant & get_attacks_as_variant() const override
Definition: contexts.hpp:581
virtual const move_map & get_dstsrc() const override
Definition: contexts.hpp:596
virtual const terrain_filter & get_avoid() const override
Definition: contexts.hpp:586
virtual double get_retreat_enemy_weight() const override
Definition: contexts.hpp:721
virtual std::string get_grouping() const override
Definition: contexts.hpp:631
virtual double get_retreat_factor() const override
Definition: contexts.hpp:726
virtual const move_map & get_srcdst() const override
Definition: contexts.hpp:716
virtual utils::variant< bool, std::vector< std::string > > get_leader_ignores_keep() const override
Definition: contexts.hpp:656
virtual double get_scout_village_targeting() const override
Definition: contexts.hpp:731
virtual const std::vector< std::string > get_recruitment_pattern() const override
Definition: contexts.hpp:701
virtual double get_village_value() const override
Definition: contexts.hpp:746
virtual double get_leader_value() const override
Definition: contexts.hpp:661
virtual utils::variant< bool, std::vector< std::string > > get_passive_leader_shares_keep() const override
Definition: contexts.hpp:671
virtual double get_aggression() const override
Definition: contexts.hpp:546
virtual int get_villages_per_scout() const override
Definition: contexts.hpp:751
virtual double get_leader_aggression() const override
Definition: contexts.hpp:646
void init_readonly_context_proxy(readonly_context &target)
Definition: contexts.hpp:434
virtual bool get_support_villages() const override
Definition: contexts.hpp:741
virtual bool get_allow_ally_villages() const override
Definition: contexts.hpp:551
virtual const move_map & get_enemy_dstsrc() const override
Definition: contexts.hpp:601
int get_count() const
Get the current value of the recursion counter.
Definition: contexts.hpp:66
virtual side_number get_side() const override
Get the side number.
Definition: contexts.hpp:396
A config object defines a single node in a WML file, with access to child nodes.
Definition: config.hpp:172
void clear_children(T... keys)
Definition: config.hpp:616
child_itors child_range(config_key_type key)
Definition: config.cpp:272
void clear()
Definition: config.cpp:828
optional_config_impl< config > optional_child(config_key_type key, int n=0)
Equivalent to mandatory_child, but returns an empty optional if the nth child was not found.
Definition: config.cpp:384
config & add_child(config_key_type key)
Definition: config.cpp:440
void add_chat_message(const std::time_t &time, const std::string &speaker, int side, const std::string &msg, events::chat_handler::MESSAGE_TYPE type, bool bell)
virtual const std::vector< team > & teams() const override
Definition: game_board.hpp:80
virtual const unit_map & units() const override
Definition: game_board.hpp:107
static game_display * get_singleton()
display_chat_manager & get_chat_manager()
This class stores all the data for a single 'side' (in game nomenclature).
Definition: team.hpp:75
void get_locations(std::set< map_location > &locs, bool with_border=false) const
gets all locations on the map that match this filter
Definition: filter.hpp:63
Container associating units to locations.
Definition: map.hpp:98
unit_iterator end()
Definition: map.hpp:428
unit_iterator find(std::size_t id)
Definition: map.cpp:302
unit_iterator find_leader(int side)
Definition: map.cpp:320
const unit_type * find(const std::string &key, unit_type::BUILD_STATUS status=unit_type::FULL) const
Finds a unit_type by its id() and makes sure it is built to the specified level.
Definition: types.cpp:1265
void build_all(unit_type::BUILD_STATUS status)
Makes sure the all unit_types are built to the specified level.
Definition: types.cpp:1307
A single unit type that the player may recruit.
Definition: types.hpp:43
@ FULL
Definition: types.hpp:74
This class represents a single unit of a specific type.
Definition: unit.hpp:133
formula_callable_ptr fake_ptr()
Definition: callable.hpp:42
void mutate_value(const std::string &key, const variant &value)
Definition: callable.hpp:58
formula_input_vector inputs() const
Definition: callable.hpp:63
static void add_input(formula_input_vector &inputs, const std::string &key, formula_access access_type=formula_access::read_only)
Definition: callable.hpp:136
void add_function(const std::string &name, formula_function_ptr &&fcn)
Definition: function.cpp:1550
map_formula_callable & add(const std::string &key, const variant &value)
Definition: callable.hpp:253
const_iterator end() const
Definition: callable.hpp:277
std::map< std::string, variant >::const_iterator const_iterator
Definition: callable.hpp:274
const_iterator begin() const
Definition: callable.hpp:276
variant execute_variant(const variant &to_exec)
Definition: variant.cpp:653
void serialize_from_string(const std::string &str)
Definition: variant.cpp:628
bool is_empty() const
Definition: variant.cpp:262
std::string to_debug_string(bool verbose=false, formula_seen_stack *seen=nullptr) const
Definition: variant.cpp:643
bool is_null() const
Functions to test the type of the internal value.
Definition: variant.hpp:62
#define ERR_AI
Definition: ai.cpp:58
static lg::log_domain log_formula_ai("ai/engine/fai")
#define LOG_AI
Definition: ai.cpp:56
#define DBG_AI
Definition: ai.cpp:55
#define WRN_AI
Definition: ai.cpp:57
Defines formula ai.
std::size_t i
Definition: function.cpp:1028
int w
Game information for the AI.
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:479
bool tiles_adjacent(const map_location &a, const map_location &b)
Function which tells if two locations are adjacent.
Definition: location.cpp:507
Standard logging facilities (interface).
A small explanation about what's going on here: Each action has access to two game_info objects First...
Definition: actions.cpp:59
wfl::candidate_action_ptr ca_ptr
Definition: ai.cpp:64
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)
const teleport_map get_teleport_locations(const unit &u, const team &viewing_team, bool see_all, bool ignore_units, bool check_vision)
Definition: teleport.cpp:251
::tod_manager * tod_manager
Definition: resources.cpp:29
game_board * gameboard
Definition: resources.cpp:20
std::size_t size(const std::string &str)
Length in characters of a UTF-8 string.
Definition: unicode.cpp:85
constexpr bool decayed_is_same
Equivalent to as std::is_same_v except both types are passed through std::decay first.
Definition: general.hpp:30
std::vector< std::string > split(const config_attribute_value &val)
Definition: contexts.hpp:43
std::vector< formula_input > formula_input_vector
std::shared_ptr< const formula > const_formula_ptr
Definition: formula_fwd.hpp:24
static void msg(const char *act, debug_info &i, const char *to="", const char *result="")
Definition: debugger.cpp:109
std::shared_ptr< formula > formula_ptr
Definition: formula_fwd.hpp:22
std::shared_ptr< base_candidate_action > candidate_action_ptr
Definition: candidates.hpp:36
This module contains various pathfinding functions and utilities.
std::shared_ptr< unit > unit_ptr
Definition: ptr.hpp:26
static config unit_moves(const reports::context &rc, const unit *u, bool is_visible_unit)
Definition: reports.cpp:663
rect dst
Location on the final composed sheet.
rect src
Non-transparent portion of the surface to compose.
Encapsulates the map of the game.
Definition: location.hpp:45
bool valid() const
Definition: location.hpp:110
direction
Valid directions which can be moved in our hexagonal world.
Definition: location.hpp:47
direction get_relative_dir(const map_location &loc, map_location::RELATIVE_DIR_MODE mode) const
Definition: location.cpp:240
Structure which holds a single route between one location and another.
Definition: pathfind.hpp:133
static map_location::direction n
unit_type_data unit_types
Definition: types.cpp:1500
MacOS doesn't support std::visit when targing MacOS < 10.14 (currently we target 10....
#define e
#define h
#define f